claudemesh-cli 1.27.3 → 1.29.0

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.
@@ -103,7 +103,7 @@ __export(exports_urls, {
103
103
  VERSION: () => VERSION,
104
104
  URLS: () => URLS
105
105
  });
106
- var URLS, VERSION = "1.27.3", env;
106
+ var URLS, VERSION = "1.29.0", env;
107
107
  var init_urls = __esm(() => {
108
108
  URLS = {
109
109
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -150,6 +150,32 @@ function normaliseInviteUrl(input, host = "claudemesh.com") {
150
150
  return trimmed;
151
151
  }
152
152
 
153
+ // src/services/daemon/policy.ts
154
+ function readEnvDefault() {
155
+ if (process.env.CLAUDEMESH_NO_DAEMON === "1")
156
+ return { mode: "no-daemon" };
157
+ if (process.env.CLAUDEMESH_STRICT_DAEMON === "1")
158
+ return { mode: "strict" };
159
+ return { mode: "auto" };
160
+ }
161
+ function setDaemonPolicy(mode) {
162
+ policy = { mode };
163
+ }
164
+ function getDaemonPolicy() {
165
+ return policy;
166
+ }
167
+ function policyFromFlags(flags) {
168
+ if (flags["no-daemon"])
169
+ return "no-daemon";
170
+ if (flags.strict)
171
+ return "strict";
172
+ return readEnvDefault().mode;
173
+ }
174
+ var policy;
175
+ var init_policy = __esm(() => {
176
+ policy = readEnvDefault();
177
+ });
178
+
153
179
  // src/constants/paths.ts
154
180
  import { homedir as homedir2 } from "node:os";
155
181
  import { join as join2 } from "node:path";
@@ -3642,7 +3668,50 @@ var init_local_token = __esm(() => {
3642
3668
  init_paths2();
3643
3669
  });
3644
3670
 
3671
+ // src/services/session/token.ts
3672
+ var exports_token = {};
3673
+ __export(exports_token, {
3674
+ readSessionTokenFromEnv: () => readSessionTokenFromEnv,
3675
+ mintSessionToken: () => mintSessionToken,
3676
+ TOKEN_FILE_ENV: () => TOKEN_FILE_ENV
3677
+ });
3678
+ import { randomBytes as randomBytes5 } from "node:crypto";
3679
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "node:fs";
3680
+ function mintSessionToken(dir, fileName = "session-token") {
3681
+ const token = randomBytes5(32).toString("hex");
3682
+ const filePath = `${dir}/${fileName}`;
3683
+ writeFileSync5(filePath, token, { mode: 384 });
3684
+ return { token, filePath };
3685
+ }
3686
+ function readSessionTokenFromEnv(env2 = process.env) {
3687
+ const direct = env2.CLAUDEMESH_IPC_TOKEN;
3688
+ if (direct && /^[0-9a-f]{64}$/i.test(direct))
3689
+ return direct.toLowerCase();
3690
+ const path = env2[ENV_TOKEN_FILE];
3691
+ if (!path)
3692
+ return null;
3693
+ try {
3694
+ if (!existsSync5(path))
3695
+ return null;
3696
+ const raw = readFileSync5(path, "utf8").trim();
3697
+ if (/^[0-9a-f]{64}$/i.test(raw))
3698
+ return raw.toLowerCase();
3699
+ return null;
3700
+ } catch {
3701
+ return null;
3702
+ }
3703
+ }
3704
+ var ENV_TOKEN_FILE = "CLAUDEMESH_IPC_TOKEN_FILE", TOKEN_FILE_ENV;
3705
+ var init_token = __esm(() => {
3706
+ TOKEN_FILE_ENV = ENV_TOKEN_FILE;
3707
+ });
3708
+
3645
3709
  // src/daemon/ipc/client.ts
3710
+ var exports_client = {};
3711
+ __export(exports_client, {
3712
+ ipc: () => ipc,
3713
+ IpcError: () => IpcError
3714
+ });
3646
3715
  import { request as httpRequest } from "node:http";
3647
3716
  async function ipc(opts) {
3648
3717
  const useTcp = !!opts.preferTcp;
@@ -3662,6 +3731,11 @@ async function ipc(opts) {
3662
3731
  throw new IpcError(0, null, "daemon local token not found; is the daemon running?");
3663
3732
  headers.authorization = `Bearer ${tok}`;
3664
3733
  }
3734
+ if (!useTcp) {
3735
+ const sessionTok = readSessionTokenFromEnv();
3736
+ if (sessionTok)
3737
+ headers.authorization = `ClaudeMesh-Session ${sessionTok}`;
3738
+ }
3665
3739
  return new Promise((resolve, reject) => {
3666
3740
  const req = httpRequest(useTcp ? { host: DAEMON_TCP_HOST, port: DAEMON_TCP_DEFAULT_PORT, path: opts.path, method: opts.method ?? "GET", headers } : { socketPath: DAEMON_PATHS.SOCK_FILE, path: opts.path, method: opts.method ?? "GET", headers }, (res) => {
3667
3741
  const chunks = [];
@@ -3686,6 +3760,7 @@ var IpcError;
3686
3760
  var init_client3 = __esm(() => {
3687
3761
  init_paths2();
3688
3762
  init_local_token();
3763
+ init_token();
3689
3764
  IpcError = class IpcError extends Error {
3690
3765
  status;
3691
3766
  payload;
@@ -3703,7 +3778,7 @@ __export(exports_lifecycle, {
3703
3778
  ensureDaemonReady: () => ensureDaemonReady,
3704
3779
  _resetDaemonReadyCache: () => _resetDaemonReadyCache
3705
3780
  });
3706
- import { existsSync as existsSync5, readFileSync as readFileSync5, statSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "node:fs";
3781
+ import { existsSync as existsSync6, readFileSync as readFileSync6, statSync, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "node:fs";
3707
3782
  import { join as join4 } from "node:path";
3708
3783
  async function ensureDaemonReady(opts = {}) {
3709
3784
  if (lastResultThisProcess && (lastResultThisProcess.state === "up" || lastResultThisProcess.state === "started")) {
@@ -3744,7 +3819,7 @@ async function runEnsureDaemon(opts) {
3744
3819
  return { state: "spawn-failed", durationMs: Date.now() - t0, reason: spawnRes.reason };
3745
3820
  }
3746
3821
  async function probeDaemon() {
3747
- if (!existsSync5(DAEMON_PATHS.SOCK_FILE))
3822
+ if (!existsSync6(DAEMON_PATHS.SOCK_FILE))
3748
3823
  return "absent";
3749
3824
  try {
3750
3825
  const res = await ipc({ path: "/v1/version", timeoutMs: PROBE_TIMEOUT_MS });
@@ -3777,7 +3852,7 @@ function recentSpawnFailureFresh() {
3777
3852
  }
3778
3853
  function markSpawnFailure() {
3779
3854
  try {
3780
- writeFileSync5(SPAWN_FAIL_FILE(), String(Date.now()), { mode: 384 });
3855
+ writeFileSync6(SPAWN_FAIL_FILE(), String(Date.now()), { mode: 384 });
3781
3856
  } catch {}
3782
3857
  }
3783
3858
  function clearSpawnFailure() {
@@ -3814,9 +3889,9 @@ async function spawnDaemon(opts) {
3814
3889
  }
3815
3890
  async function acquireOrShareLock(_opts) {
3816
3891
  const lockPath = SPAWN_LOCK_FILE();
3817
- if (existsSync5(lockPath)) {
3892
+ if (existsSync6(lockPath)) {
3818
3893
  try {
3819
- const pidStr = readFileSync5(lockPath, "utf8").trim();
3894
+ const pidStr = readFileSync6(lockPath, "utf8").trim();
3820
3895
  const pid = Number.parseInt(pidStr, 10);
3821
3896
  if (Number.isFinite(pid) && pid > 0) {
3822
3897
  try {
@@ -3827,7 +3902,7 @@ async function acquireOrShareLock(_opts) {
3827
3902
  } catch {}
3828
3903
  }
3829
3904
  try {
3830
- writeFileSync5(lockPath, String(process.pid), { mode: 384 });
3905
+ writeFileSync6(lockPath, String(process.pid), { mode: 384 });
3831
3906
  } catch {}
3832
3907
  return "acquired";
3833
3908
  }
@@ -3839,7 +3914,7 @@ function releaseLock() {
3839
3914
  async function pollForSocket(budgetMs) {
3840
3915
  const start = Date.now();
3841
3916
  while (Date.now() - start < budgetMs) {
3842
- if (existsSync5(DAEMON_PATHS.SOCK_FILE)) {
3917
+ if (existsSync6(DAEMON_PATHS.SOCK_FILE)) {
3843
3918
  const probe = await probeDaemon();
3844
3919
  if (probe === "up")
3845
3920
  return { ok: true };
@@ -3873,7 +3948,7 @@ __export(exports_launch, {
3873
3948
  });
3874
3949
  import { spawnSync as spawnSync2 } from "node:child_process";
3875
3950
  import { randomUUID } from "node:crypto";
3876
- import { mkdtempSync, writeFileSync as writeFileSync6, rmSync, readdirSync, statSync as statSync2, existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
3951
+ import { mkdtempSync, writeFileSync as writeFileSync7, rmSync, readdirSync, statSync as statSync2, existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
3877
3952
  import { tmpdir, hostname as hostname2, homedir as homedir3 } from "node:os";
3878
3953
  import { join as join5 } from "node:path";
3879
3954
  import { createInterface as createInterface4 } from "node:readline";
@@ -4222,8 +4297,8 @@ async function runLaunch(flags, rawArgs) {
4222
4297
  await ensureDaemonRunning(mesh.slug, args.quiet);
4223
4298
  try {
4224
4299
  const claudeConfigPath = join5(homedir3(), ".claude.json");
4225
- if (existsSync6(claudeConfigPath)) {
4226
- const claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
4300
+ if (existsSync7(claudeConfigPath)) {
4301
+ const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
4227
4302
  const mcpServers = claudeConfig.mcpServers ?? {};
4228
4303
  let cleaned = 0;
4229
4304
  for (const key of Object.keys(mcpServers)) {
@@ -4241,7 +4316,7 @@ async function runLaunch(flags, rawArgs) {
4241
4316
  }
4242
4317
  if (cleaned > 0) {
4243
4318
  claudeConfig.mcpServers = mcpServers;
4244
- writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4319
+ writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4245
4320
  `, "utf-8");
4246
4321
  }
4247
4322
  }
@@ -4267,8 +4342,37 @@ async function runLaunch(flags, rawArgs) {
4267
4342
  ...parsedGroups.length > 0 ? { groups: parsedGroups } : {},
4268
4343
  messageMode
4269
4344
  };
4270
- writeFileSync6(join5(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
4345
+ writeFileSync7(join5(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
4271
4346
  `, "utf-8");
4347
+ let sessionTokenFilePath = null;
4348
+ let sessionTokenForCleanup = null;
4349
+ try {
4350
+ const { mintSessionToken: mintSessionToken2, TOKEN_FILE_ENV: TOKEN_FILE_ENV2 } = await Promise.resolve().then(() => (init_token(), exports_token));
4351
+ const minted = mintSessionToken2(tmpDir);
4352
+ sessionTokenFilePath = minted.filePath;
4353
+ sessionTokenForCleanup = minted.token;
4354
+ const { ipc: ipc2 } = await Promise.resolve().then(() => (init_client3(), exports_client));
4355
+ const sessionIdForRegister = claudeSessionId ?? randomUUID();
4356
+ await ipc2({
4357
+ method: "POST",
4358
+ path: "/v1/sessions/register",
4359
+ timeoutMs: 3000,
4360
+ body: {
4361
+ token: minted.token,
4362
+ session_id: sessionIdForRegister,
4363
+ mesh: mesh.slug,
4364
+ display_name: displayName,
4365
+ pid: process.pid,
4366
+ cwd: process.cwd(),
4367
+ ...role ? { role } : {},
4368
+ ...parsedGroups.length > 0 ? { groups: parsedGroups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`) } : {}
4369
+ }
4370
+ }).catch(() => null);
4371
+ process._claudemeshTokenEnv = {
4372
+ name: TOKEN_FILE_ENV2,
4373
+ value: minted.filePath
4374
+ };
4375
+ } catch {}
4272
4376
  if (!args.quiet) {
4273
4377
  printBanner(displayName, mesh.slug, role, parsedGroups, messageMode);
4274
4378
  }
@@ -4277,7 +4381,7 @@ async function runLaunch(flags, rawArgs) {
4277
4381
  const claudeConfigPath = join5(homedir3(), ".claude.json");
4278
4382
  let claudeConfig = {};
4279
4383
  try {
4280
- claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
4384
+ claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
4281
4385
  } catch {
4282
4386
  claudeConfig = {};
4283
4387
  }
@@ -4304,7 +4408,7 @@ async function runLaunch(flags, rawArgs) {
4304
4408
  meshMcpEntries.push({ key: entryKey, entry });
4305
4409
  }
4306
4410
  claudeConfig.mcpServers = mcpServers;
4307
- writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4411
+ writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4308
4412
  `, "utf-8");
4309
4413
  if (!args.quiet && meshMcpEntries.length > 0) {
4310
4414
  console.log(` ${meshMcpEntries.length} mesh service(s) registered as native MCPs:`);
@@ -4346,7 +4450,7 @@ async function runLaunch(flags, rawArgs) {
4346
4450
  join5(homedir3(), ".claude", "bin", "claude")
4347
4451
  ];
4348
4452
  for (const c of candidates) {
4349
- if (existsSync6(c)) {
4453
+ if (existsSync7(c)) {
4350
4454
  claudeBin = c;
4351
4455
  break;
4352
4456
  }
@@ -4356,13 +4460,13 @@ async function runLaunch(flags, rawArgs) {
4356
4460
  if (meshMcpEntries.length > 0) {
4357
4461
  try {
4358
4462
  const claudeConfigPath = join5(homedir3(), ".claude.json");
4359
- const claudeConfig = JSON.parse(readFileSync6(claudeConfigPath, "utf-8"));
4463
+ const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
4360
4464
  const mcpServers = claudeConfig.mcpServers ?? {};
4361
4465
  for (const { key } of meshMcpEntries) {
4362
4466
  delete mcpServers[key];
4363
4467
  }
4364
4468
  claudeConfig.mcpServers = mcpServers;
4365
- writeFileSync6(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4469
+ writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4366
4470
  `, "utf-8");
4367
4471
  } catch {}
4368
4472
  }
@@ -4392,6 +4496,7 @@ async function runLaunch(flags, rawArgs) {
4392
4496
  CLAUDEMESH_CONFIG_DIR: tmpDir,
4393
4497
  CLAUDEMESH_DISPLAY_NAME: displayName,
4394
4498
  ...claudeSessionId ? { CLAUDEMESH_SESSION_ID: claudeSessionId } : {},
4499
+ ...sessionTokenFilePath ? { CLAUDEMESH_IPC_TOKEN_FILE: sessionTokenFilePath } : {},
4395
4500
  MCP_TIMEOUT: process.env.MCP_TIMEOUT ?? "30000",
4396
4501
  MAX_MCP_OUTPUT_TOKENS: process.env.MAX_MCP_OUTPUT_TOKENS ?? "50000",
4397
4502
  ...role ? { CLAUDEMESH_ROLE: role } : {}
@@ -5059,7 +5164,7 @@ __export(exports_join, {
5059
5164
  runJoin: () => runJoin
5060
5165
  });
5061
5166
  import sodium3 from "libsodium-wrappers";
5062
- import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync4 } from "node:fs";
5167
+ import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync4 } from "node:fs";
5063
5168
  import { join as join6, dirname as dirname3 } from "node:path";
5064
5169
  import { homedir as homedir4, hostname as hostname3 } from "node:os";
5065
5170
  function deriveAppBaseUrl() {
@@ -5184,7 +5289,7 @@ async function runJoin(args) {
5184
5289
  const inviteFile = join6(configDir, `invite-${payload.mesh_slug}.txt`);
5185
5290
  try {
5186
5291
  mkdirSync4(dirname3(inviteFile), { recursive: true });
5187
- writeFileSync7(inviteFile, link, "utf-8");
5292
+ writeFileSync8(inviteFile, link, "utf-8");
5188
5293
  } catch {}
5189
5294
  console.log("");
5190
5295
  console.log(`✓ Joined "${payload.mesh_slug}" as ${displayName}${enroll.alreadyMember ? " (already a member — re-enrolled with same pubkey)" : ""}`);
@@ -6699,6 +6804,12 @@ async function pickMesh(meshes) {
6699
6804
  });
6700
6805
  }
6701
6806
  async function withMesh(opts, fn) {
6807
+ if (getDaemonPolicy().mode === "strict") {
6808
+ console.error(`
6809
+ ✘ daemon not reachable — --strict refuses cold-path fallback.
6810
+ ` + " run `claudemesh daemon up` (or `claudemesh doctor`) and retry.\n");
6811
+ process.exit(1);
6812
+ }
6702
6813
  const config = readConfig();
6703
6814
  if (config.meshes.length === 0) {
6704
6815
  console.error("No meshes joined. Run `claudemesh join <url>` first.");
@@ -6749,6 +6860,7 @@ async function withMesh(opts, fn) {
6749
6860
  var init_connect = __esm(() => {
6750
6861
  init_facade8();
6751
6862
  init_facade();
6863
+ init_policy();
6752
6864
  });
6753
6865
 
6754
6866
  // src/commands/info.ts
@@ -7385,107 +7497,6 @@ var init_ban = __esm(() => {
7385
7497
  init_exit_codes();
7386
7498
  });
7387
7499
 
7388
- // src/services/bridge/protocol.ts
7389
- import { homedir as homedir5 } from "node:os";
7390
- import { join as join7 } from "node:path";
7391
- function socketPath(meshSlug) {
7392
- return join7(homedir5(), ".claudemesh", "sockets", `${meshSlug}.sock`);
7393
- }
7394
- function frame(obj) {
7395
- return JSON.stringify(obj) + `
7396
- `;
7397
- }
7398
-
7399
- class LineParser {
7400
- buf = "";
7401
- feed(chunk) {
7402
- this.buf += typeof chunk === "string" ? chunk : chunk.toString("utf-8");
7403
- const lines = [];
7404
- let nl = this.buf.indexOf(`
7405
- `);
7406
- while (nl !== -1) {
7407
- lines.push(this.buf.slice(0, nl));
7408
- this.buf = this.buf.slice(nl + 1);
7409
- nl = this.buf.indexOf(`
7410
- `);
7411
- }
7412
- return lines;
7413
- }
7414
- }
7415
- var init_protocol = () => {};
7416
-
7417
- // src/services/bridge/client.ts
7418
- import { createConnection } from "node:net";
7419
- import { existsSync as existsSync7 } from "node:fs";
7420
- import { randomUUID as randomUUID2 } from "node:crypto";
7421
- async function tryBridge(meshSlug, verb, args = {}, timeoutMs = DEFAULT_TIMEOUT_MS) {
7422
- const path = socketPath(meshSlug);
7423
- if (!existsSync7(path))
7424
- return null;
7425
- return new Promise((resolve) => {
7426
- const id = randomUUID2();
7427
- const req = { id, verb, args };
7428
- const parser = new LineParser;
7429
- let settled = false;
7430
- const finish = (value) => {
7431
- if (settled)
7432
- return;
7433
- settled = true;
7434
- try {
7435
- socket.destroy();
7436
- } catch {}
7437
- clearTimeout(timer);
7438
- resolve(value);
7439
- };
7440
- const socket = createConnection({ path });
7441
- const timer = setTimeout(() => {
7442
- finish(null);
7443
- }, timeoutMs);
7444
- socket.on("connect", () => {
7445
- try {
7446
- socket.write(frame(req));
7447
- } catch {
7448
- finish(null);
7449
- }
7450
- });
7451
- socket.on("data", (chunk) => {
7452
- const lines = parser.feed(chunk);
7453
- for (const line of lines) {
7454
- if (!line.trim())
7455
- continue;
7456
- let res;
7457
- try {
7458
- res = JSON.parse(line);
7459
- } catch {
7460
- continue;
7461
- }
7462
- if (res.id !== id)
7463
- continue;
7464
- if (res.ok)
7465
- finish({ ok: true, result: res.result });
7466
- else
7467
- finish({ ok: false, error: res.error });
7468
- return;
7469
- }
7470
- });
7471
- socket.on("error", (err) => {
7472
- const code = err.code;
7473
- if (code === "ECONNREFUSED" || code === "ENOENT" || code === "EPERM") {
7474
- finish(null);
7475
- } else {
7476
- finish(null);
7477
- }
7478
- });
7479
- socket.on("close", () => {
7480
- finish(null);
7481
- });
7482
- });
7483
- }
7484
- var DEFAULT_TIMEOUT_MS = 5000;
7485
- var init_client4 = __esm(() => {
7486
- init_protocol();
7487
- });
7488
-
7489
7500
  // src/ui/warnings.ts
7490
7501
  function warnDaemonState(res, opts = {}) {
7491
7502
  if (alreadyWarned)
@@ -7494,6 +7505,8 @@ function warnDaemonState(res, opts = {}) {
7494
7505
  return false;
7495
7506
  if (res.state === "up")
7496
7507
  return false;
7508
+ if (getDaemonPolicy().mode === "strict" && res.state !== "started")
7509
+ return false;
7497
7510
  alreadyWarned = true;
7498
7511
  const tag = (label) => `[claudemesh] ${label}`;
7499
7512
  const hint = (s) => dim(s);
@@ -7519,6 +7532,7 @@ function warnDaemonState(res, opts = {}) {
7519
7532
  }
7520
7533
  var alreadyWarned = false;
7521
7534
  var init_warnings = __esm(() => {
7535
+ init_policy();
7522
7536
  init_styles();
7523
7537
  });
7524
7538
 
@@ -7540,7 +7554,10 @@ function meshQuery(mesh) {
7540
7554
  return mesh ? `?mesh=${encodeURIComponent(mesh)}` : "";
7541
7555
  }
7542
7556
  async function daemonReachable() {
7543
- const res = await ensureDaemonReady();
7557
+ const policy2 = getDaemonPolicy();
7558
+ if (policy2.mode === "no-daemon")
7559
+ return false;
7560
+ const res = await ensureDaemonReady({ noAutoSpawn: false });
7544
7561
  warnDaemonState(res, {});
7545
7562
  return res.state === "up" || res.state === "started";
7546
7563
  }
@@ -7718,9 +7735,49 @@ async function trySendViaDaemon(args) {
7718
7735
  var init_daemon_route = __esm(() => {
7719
7736
  init_client3();
7720
7737
  init_lifecycle();
7738
+ init_policy();
7721
7739
  init_warnings();
7722
7740
  });
7723
7741
 
7742
+ // src/services/session/resolve.ts
7743
+ var exports_resolve = {};
7744
+ __export(exports_resolve, {
7745
+ getSessionInfo: () => getSessionInfo,
7746
+ _resetSessionCache: () => _resetSessionCache
7747
+ });
7748
+ async function getSessionInfo() {
7749
+ if (cached !== undefined)
7750
+ return cached;
7751
+ const tok = readSessionTokenFromEnv();
7752
+ if (!tok) {
7753
+ cached = null;
7754
+ return null;
7755
+ }
7756
+ try {
7757
+ const res = await ipc({
7758
+ path: "/v1/sessions/me",
7759
+ timeoutMs: 1500
7760
+ });
7761
+ if (res.status !== 200 || !res.body.session) {
7762
+ cached = null;
7763
+ return null;
7764
+ }
7765
+ cached = res.body.session;
7766
+ return cached;
7767
+ } catch {
7768
+ cached = null;
7769
+ return null;
7770
+ }
7771
+ }
7772
+ function _resetSessionCache() {
7773
+ cached = undefined;
7774
+ }
7775
+ var cached = undefined;
7776
+ var init_resolve = __esm(() => {
7777
+ init_client3();
7778
+ init_token();
7779
+ });
7780
+
7724
7781
  // src/commands/peers.ts
7725
7782
  var exports_peers = {};
7726
7783
  __export(exports_peers, {
@@ -7745,11 +7802,6 @@ async function listPeersForMesh(slug) {
7745
7802
  return dr.map((p) => annotateSelf(p, selfMemberPubkey, null));
7746
7803
  }
7747
7804
  } catch {}
7748
- const bridged = await tryBridge(slug, "peers");
7749
- if (bridged && bridged.ok) {
7750
- const peers = bridged.result;
7751
- return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
7752
- }
7753
7805
  let result = [];
7754
7806
  await withMesh({ meshSlug: slug }, async (client) => {
7755
7807
  const all = await client.listPeers();
@@ -7765,7 +7817,14 @@ function annotateSelf(peer, selfMemberPubkey, selfSessionPubkey) {
7765
7817
  }
7766
7818
  async function runPeers(flags) {
7767
7819
  const config = readConfig();
7768
- const slugs = flags.mesh ? [flags.mesh] : config.meshes.map((m) => m.slug);
7820
+ let slugs;
7821
+ if (flags.mesh) {
7822
+ slugs = [flags.mesh];
7823
+ } else {
7824
+ const { getSessionInfo: getSessionInfo2 } = await Promise.resolve().then(() => (init_resolve(), exports_resolve));
7825
+ const sess = await getSessionInfo2();
7826
+ slugs = sess ? [sess.mesh] : config.meshes.map((m) => m.slug);
7827
+ }
7769
7828
  if (slugs.length === 0) {
7770
7829
  render.err("No meshes joined.");
7771
7830
  render.hint("claudemesh <invite-url> # join + launch");
@@ -7819,7 +7878,6 @@ var FIELD_ALIAS;
7819
7878
  var init_peers = __esm(() => {
7820
7879
  init_connect();
7821
7880
  init_facade();
7822
- init_client4();
7823
7881
  init_render();
7824
7882
  init_styles();
7825
7883
  FIELD_ALIAS = {
@@ -7865,26 +7923,6 @@ async function runSend(flags, to, message) {
7865
7923
  process.exit(1);
7866
7924
  }
7867
7925
  }
7868
- if (meshSlug) {
7869
- const bridged = await tryBridge(meshSlug, "send", { to, message, priority });
7870
- if (bridged !== null) {
7871
- if (bridged.ok) {
7872
- const r = bridged.result;
7873
- if (flags.json) {
7874
- console.log(JSON.stringify({ ok: true, messageId: r.messageId, target: to }));
7875
- } else {
7876
- render.ok(`sent to ${to}`, r.messageId ? dim(r.messageId.slice(0, 8)) : undefined);
7877
- }
7878
- return;
7879
- }
7880
- if (flags.json) {
7881
- console.log(JSON.stringify({ ok: false, error: bridged.error }));
7882
- } else {
7883
- render.err(`send failed: ${bridged.error}`);
7884
- }
7885
- process.exit(1);
7886
- }
7887
- }
7888
7926
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
7889
7927
  let targetSpec = to;
7890
7928
  if (to.startsWith("#") && !/^#[0-9a-z_-]{20,}$/i.test(to)) {
@@ -7927,7 +7965,6 @@ async function runSend(flags, to, message) {
7927
7965
  var init_send = __esm(() => {
7928
7966
  init_connect();
7929
7967
  init_facade();
7930
- init_client4();
7931
7968
  init_daemon_route();
7932
7969
  init_render();
7933
7970
  init_styles();
@@ -8255,33 +8292,12 @@ __export(exports_broker_actions, {
8255
8292
  runForget: () => runForget,
8256
8293
  runClock: () => runClock
8257
8294
  });
8258
- function unambiguousMesh(opts) {
8259
- if (opts.mesh)
8260
- return opts.mesh;
8261
- const config = readConfig();
8262
- return config.meshes.length === 1 ? config.meshes[0].slug : null;
8263
- }
8264
8295
  async function runStatusSet(state, opts) {
8265
8296
  const valid = ["idle", "working", "dnd"];
8266
8297
  if (!valid.includes(state)) {
8267
8298
  render.err(`Invalid status: ${state}`, `must be one of: ${valid.join(", ")}`);
8268
8299
  return EXIT.INVALID_ARGS;
8269
8300
  }
8270
- const meshSlug = unambiguousMesh(opts);
8271
- if (meshSlug) {
8272
- const bridged = await tryBridge(meshSlug, "status_set", { status: state });
8273
- if (bridged !== null) {
8274
- if (bridged.ok) {
8275
- if (opts.json)
8276
- console.log(JSON.stringify({ status: state }));
8277
- else
8278
- render.ok(`status set to ${bold(state)}`);
8279
- return EXIT.SUCCESS;
8280
- }
8281
- render.err(bridged.error);
8282
- return EXIT.INTERNAL_ERROR;
8283
- }
8284
- }
8285
8301
  await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
8286
8302
  await client.setStatus(state);
8287
8303
  });
@@ -8296,21 +8312,6 @@ async function runSummary(text, opts) {
8296
8312
  render.err("Usage: claudemesh summary <text>");
8297
8313
  return EXIT.INVALID_ARGS;
8298
8314
  }
8299
- const meshSlug = unambiguousMesh(opts);
8300
- if (meshSlug) {
8301
- const bridged = await tryBridge(meshSlug, "summary", { summary: text });
8302
- if (bridged !== null) {
8303
- if (bridged.ok) {
8304
- if (opts.json)
8305
- console.log(JSON.stringify({ summary: text }));
8306
- else
8307
- render.ok("summary set", dim(text));
8308
- return EXIT.SUCCESS;
8309
- }
8310
- render.err(bridged.error);
8311
- return EXIT.INTERNAL_ERROR;
8312
- }
8313
- }
8314
8315
  await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
8315
8316
  await client.setSummary(text);
8316
8317
  });
@@ -8330,21 +8331,6 @@ async function runVisible(value, opts) {
8330
8331
  render.err("Usage: claudemesh visible <true|false>");
8331
8332
  return EXIT.INVALID_ARGS;
8332
8333
  }
8333
- const meshSlug = unambiguousMesh(opts);
8334
- if (meshSlug) {
8335
- const bridged = await tryBridge(meshSlug, "visible", { visible });
8336
- if (bridged !== null) {
8337
- if (bridged.ok) {
8338
- if (opts.json)
8339
- console.log(JSON.stringify({ visible }));
8340
- else
8341
- render.ok(visible ? "you are now visible to peers" : "you are now hidden", visible ? undefined : "direct messages still reach you");
8342
- return EXIT.SUCCESS;
8343
- }
8344
- render.err(bridged.error);
8345
- return EXIT.INTERNAL_ERROR;
8346
- }
8347
- }
8348
8334
  await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
8349
8335
  await client.setVisible(visible);
8350
8336
  });
@@ -8574,8 +8560,6 @@ async function runTaskComplete(id, result, opts) {
8574
8560
  }
8575
8561
  var init_broker_actions = __esm(() => {
8576
8562
  init_connect();
8577
- init_facade();
8578
- init_client4();
8579
8563
  init_daemon_route();
8580
8564
  init_render();
8581
8565
  init_styles();
@@ -8810,12 +8794,12 @@ var init_whoami = __esm(() => {
8810
8794
  });
8811
8795
 
8812
8796
  // src/daemon/lock.ts
8813
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeFileSync as writeFileSync8 } from "node:fs";
8797
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync8, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "node:fs";
8814
8798
  import { dirname as dirname4 } from "node:path";
8815
8799
  function acquireSingletonLock() {
8816
8800
  mkdirSync5(dirname4(DAEMON_PATHS.PID_FILE), { recursive: true, mode: 448 });
8817
8801
  if (existsSync8(DAEMON_PATHS.PID_FILE)) {
8818
- const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
8802
+ const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
8819
8803
  const oldPid = Number.parseInt(raw, 10);
8820
8804
  if (Number.isFinite(oldPid) && oldPid > 0 && isProcessAlive(oldPid)) {
8821
8805
  return { result: "already-running", pid: oldPid };
@@ -8823,22 +8807,22 @@ function acquireSingletonLock() {
8823
8807
  try {
8824
8808
  unlinkSync3(DAEMON_PATHS.PID_FILE);
8825
8809
  } catch {}
8826
- writeFileSync8(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8810
+ writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8827
8811
  return { result: "stale", pid: process.pid };
8828
8812
  }
8829
- writeFileSync8(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8813
+ writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
8830
8814
  return { result: "acquired", pid: process.pid };
8831
8815
  }
8832
8816
  function releaseSingletonLock() {
8833
8817
  try {
8834
- const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
8818
+ const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
8835
8819
  if (Number.parseInt(raw, 10) === process.pid)
8836
8820
  unlinkSync3(DAEMON_PATHS.PID_FILE);
8837
8821
  } catch {}
8838
8822
  }
8839
8823
  function readRunningPid() {
8840
8824
  try {
8841
- const raw = readFileSync7(DAEMON_PATHS.PID_FILE, "utf8").trim();
8825
+ const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
8842
8826
  const pid = Number.parseInt(raw, 10);
8843
8827
  if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid))
8844
8828
  return pid;
@@ -8984,17 +8968,17 @@ function requeueDeadOrPending(db, args) {
8984
8968
 
8985
8969
  // src/daemon/db/sqlite.ts
8986
8970
  async function loadSqlite() {
8987
- if (cached)
8988
- return cached;
8971
+ if (cached2)
8972
+ return cached2;
8989
8973
  try {
8990
8974
  const mod = await import("node:sqlite");
8991
- cached = mod.DatabaseSync;
8992
- return cached;
8975
+ cached2 = mod.DatabaseSync;
8976
+ return cached2;
8993
8977
  } catch (nodeErr) {
8994
8978
  try {
8995
8979
  const bunMod = await import("bun:sqlite");
8996
- cached = bunMod.Database;
8997
- return cached;
8980
+ cached2 = bunMod.Database;
8981
+ return cached2;
8998
8982
  } catch {
8999
8983
  const msg = `claudemesh daemon requires Node.js 22.5+ for the embedded SQLite store (node:sqlite), or Bun (bun:sqlite) for dev. Current: ${process.version}. Original error: ${String(nodeErr)}`;
9000
8984
  throw new Error(msg);
@@ -9025,7 +9009,7 @@ function inImmediateTx(db, fn) {
9025
9009
  throw err;
9026
9010
  }
9027
9011
  }
9028
- var cached = null;
9012
+ var cached2 = null;
9029
9013
 
9030
9014
  // src/daemon/fingerprint.ts
9031
9015
  import { createHash } from "node:crypto";
@@ -9074,10 +9058,10 @@ var init_fingerprint = __esm(() => {
9074
9058
  });
9075
9059
 
9076
9060
  // src/daemon/ipc/handlers/send.ts
9077
- import { randomUUID as randomUUID3 } from "node:crypto";
9061
+ import { randomUUID as randomUUID2 } from "node:crypto";
9078
9062
  function acceptSend(req, deps) {
9079
9063
  const now = (deps.now ?? Date.now)();
9080
- const newId = deps.newId ?? randomUUID3;
9064
+ const newId = deps.newId ?? randomUUID2;
9081
9065
  const clientId = req.client_message_id?.trim() || ulidLike(newId);
9082
9066
  const body = Buffer.from(req.message, "utf8");
9083
9067
  const fingerprint = computeRequestFingerprint({
@@ -9268,11 +9252,72 @@ function bindSseStream(res, bus) {
9268
9252
  return cleanup;
9269
9253
  }
9270
9254
 
9255
+ // src/daemon/session-registry.ts
9256
+ function startReaper() {
9257
+ if (reaperHandle)
9258
+ return;
9259
+ reaperHandle = setInterval(reapDead, REAPER_INTERVAL_MS).unref?.() ?? reaperHandle;
9260
+ }
9261
+ function registerSession(info) {
9262
+ const priorToken = bySessionId.get(info.sessionId);
9263
+ if (priorToken && priorToken !== info.token)
9264
+ byToken.delete(priorToken);
9265
+ const stored = { ...info, registeredAt: Date.now() };
9266
+ byToken.set(info.token, stored);
9267
+ bySessionId.set(info.sessionId, info.token);
9268
+ return stored;
9269
+ }
9270
+ function deregisterByToken(token) {
9271
+ const entry = byToken.get(token);
9272
+ if (!entry)
9273
+ return false;
9274
+ byToken.delete(token);
9275
+ if (bySessionId.get(entry.sessionId) === token)
9276
+ bySessionId.delete(entry.sessionId);
9277
+ return true;
9278
+ }
9279
+ function resolveToken(token) {
9280
+ const entry = byToken.get(token);
9281
+ if (!entry)
9282
+ return null;
9283
+ if (Date.now() - entry.registeredAt > TTL_MS) {
9284
+ deregisterByToken(token);
9285
+ return null;
9286
+ }
9287
+ return entry;
9288
+ }
9289
+ function listSessions() {
9290
+ return [...byToken.values()];
9291
+ }
9292
+ function reapDead() {
9293
+ const dead = [];
9294
+ for (const [token, info] of byToken.entries()) {
9295
+ if (Date.now() - info.registeredAt > TTL_MS) {
9296
+ dead.push(token);
9297
+ continue;
9298
+ }
9299
+ try {
9300
+ process.kill(info.pid, 0);
9301
+ } catch {
9302
+ dead.push(token);
9303
+ }
9304
+ }
9305
+ for (const t of dead)
9306
+ deregisterByToken(t);
9307
+ }
9308
+ var TTL_MS, REAPER_INTERVAL_MS, byToken, bySessionId, reaperHandle = null;
9309
+ var init_session_registry = __esm(() => {
9310
+ TTL_MS = 24 * 60 * 60 * 1000;
9311
+ REAPER_INTERVAL_MS = 30 * 1000;
9312
+ byToken = new Map;
9313
+ bySessionId = new Map;
9314
+ });
9315
+
9271
9316
  // src/daemon/ipc/server.ts
9272
9317
  import { createServer as createServer2 } from "node:http";
9273
9318
  import { chmodSync as chmodSync3, existsSync as existsSync9, unlinkSync as unlinkSync4 } from "node:fs";
9274
9319
  import { timingSafeEqual } from "node:crypto";
9275
- import { randomUUID as randomUUID4 } from "node:crypto";
9320
+ import { randomUUID as randomUUID3 } from "node:crypto";
9276
9321
  function startIpcServer(opts) {
9277
9322
  const log2 = opts.log ?? defaultLogger;
9278
9323
  const handler = makeHandler({
@@ -9372,11 +9417,19 @@ function makeHandler(opts) {
9372
9417
  return;
9373
9418
  }
9374
9419
  }
9420
+ let session = null;
9421
+ {
9422
+ const authz = req.headers.authorization ?? "";
9423
+ const sm = /^ClaudeMesh-Session\s+([0-9a-f]{64})$/i.exec(authz.trim());
9424
+ if (sm && sm[1])
9425
+ session = resolveToken(sm[1].toLowerCase());
9426
+ }
9427
+ const meshFromCtx = (explicit) => explicit && explicit.trim() ? explicit : session?.mesh ?? null;
9375
9428
  if (req.method === "GET" && url.pathname === "/v1/version") {
9376
9429
  respond(res, 200, {
9377
9430
  daemon_version: VERSION,
9378
9431
  ipc_api: "v1",
9379
- ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills", "state", "memory"],
9432
+ ipc_features: ["version", "health", "send", "inbox", "events", "peers", "profile", "skills", "state", "memory", "sessions"],
9380
9433
  schema_version: 1
9381
9434
  });
9382
9435
  return;
@@ -9385,6 +9438,70 @@ function makeHandler(opts) {
9385
9438
  respond(res, 200, { ok: true, pid: process.pid });
9386
9439
  return;
9387
9440
  }
9441
+ if (req.method === "POST" && url.pathname === "/v1/sessions/register") {
9442
+ try {
9443
+ const body = await readJsonBody(req, 64 * 1024);
9444
+ if (!body) {
9445
+ respond(res, 400, { error: "missing body" });
9446
+ return;
9447
+ }
9448
+ const token = typeof body.token === "string" ? body.token : "";
9449
+ if (!/^[0-9a-f]{64}$/i.test(token)) {
9450
+ respond(res, 400, { error: "token must be 64 hex chars" });
9451
+ return;
9452
+ }
9453
+ const sessionId = typeof body.session_id === "string" ? body.session_id : "";
9454
+ const mesh = typeof body.mesh === "string" ? body.mesh : "";
9455
+ const displayName = typeof body.display_name === "string" ? body.display_name : "";
9456
+ const pid = typeof body.pid === "number" ? body.pid : 0;
9457
+ if (!sessionId || !mesh || !displayName || !pid) {
9458
+ respond(res, 400, { error: "session_id, mesh, display_name, pid all required" });
9459
+ return;
9460
+ }
9461
+ const cwd = typeof body.cwd === "string" ? body.cwd : undefined;
9462
+ const role = typeof body.role === "string" ? body.role : undefined;
9463
+ const groups = Array.isArray(body.groups) ? body.groups.filter((g) => typeof g === "string") : undefined;
9464
+ const stored = registerSession({
9465
+ token: token.toLowerCase(),
9466
+ sessionId,
9467
+ mesh,
9468
+ displayName,
9469
+ pid,
9470
+ cwd,
9471
+ role,
9472
+ groups
9473
+ });
9474
+ opts.log("info", "session_registered", { sessionId, mesh, pid });
9475
+ respond(res, 200, { ok: true, registered_at: stored.registeredAt });
9476
+ } catch (e) {
9477
+ respond(res, 400, { error: String(e) });
9478
+ }
9479
+ return;
9480
+ }
9481
+ if (req.method === "DELETE" && url.pathname.startsWith("/v1/sessions/")) {
9482
+ const tail = url.pathname.slice("/v1/sessions/".length);
9483
+ if (!/^[0-9a-f]{64}$/i.test(tail)) {
9484
+ respond(res, 400, { error: "invalid token" });
9485
+ return;
9486
+ }
9487
+ const ok = deregisterByToken(tail.toLowerCase());
9488
+ respond(res, ok ? 200 : 404, { ok, token_prefix: tail.slice(0, 8) });
9489
+ return;
9490
+ }
9491
+ if (req.method === "GET" && url.pathname === "/v1/sessions/me") {
9492
+ if (!session) {
9493
+ respond(res, 401, { error: "no session token" });
9494
+ return;
9495
+ }
9496
+ const { token, ...redacted } = session;
9497
+ respond(res, 200, { session: { ...redacted, token_prefix: token.slice(0, 8) } });
9498
+ return;
9499
+ }
9500
+ if (req.method === "GET" && url.pathname === "/v1/sessions") {
9501
+ const all = listSessions().map(({ token, ...rest }) => ({ ...rest, token_prefix: token.slice(0, 8) }));
9502
+ respond(res, 200, { sessions: all });
9503
+ return;
9504
+ }
9388
9505
  if (req.method === "GET" && url.pathname === "/v1/events") {
9389
9506
  if (!opts.bus) {
9390
9507
  respond(res, 503, { error: "event bus not initialised" });
@@ -9398,7 +9515,7 @@ function makeHandler(opts) {
9398
9515
  respond(res, 503, { error: "broker not initialised" });
9399
9516
  return;
9400
9517
  }
9401
- const filterMesh = url.searchParams.get("mesh") ?? undefined;
9518
+ const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
9402
9519
  try {
9403
9520
  const all = [];
9404
9521
  for (const [slug, b] of opts.brokers.entries()) {
@@ -9423,7 +9540,7 @@ function makeHandler(opts) {
9423
9540
  respond(res, 503, { error: "broker not initialised" });
9424
9541
  return;
9425
9542
  }
9426
- const filterMesh = url.searchParams.get("mesh") ?? undefined;
9543
+ const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
9427
9544
  const key = url.searchParams.get("key");
9428
9545
  try {
9429
9546
  if (key) {
@@ -9464,7 +9581,7 @@ function makeHandler(opts) {
9464
9581
  respond(res, 400, { error: "missing 'key' (string)" });
9465
9582
  return;
9466
9583
  }
9467
- const requested = (typeof body.mesh === "string" ? body.mesh : null) || null;
9584
+ const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : null);
9468
9585
  let chosen = requested;
9469
9586
  if (!chosen && opts.brokers.size === 1)
9470
9587
  chosen = opts.brokers.keys().next().value;
@@ -9490,7 +9607,7 @@ function makeHandler(opts) {
9490
9607
  return;
9491
9608
  }
9492
9609
  const query = url.searchParams.get("q") ?? "";
9493
- const filterMesh = url.searchParams.get("mesh") ?? undefined;
9610
+ const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
9494
9611
  try {
9495
9612
  const all = [];
9496
9613
  for (const [slug, b] of opts.brokers.entries()) {
@@ -9517,7 +9634,7 @@ function makeHandler(opts) {
9517
9634
  respond(res, 400, { error: "missing 'content' (string)" });
9518
9635
  return;
9519
9636
  }
9520
- const requested = (typeof body.mesh === "string" ? body.mesh : null) || null;
9637
+ const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : null);
9521
9638
  let chosen = requested;
9522
9639
  if (!chosen && opts.brokers.size === 1)
9523
9640
  chosen = opts.brokers.keys().next().value;
@@ -9575,7 +9692,7 @@ function makeHandler(opts) {
9575
9692
  return;
9576
9693
  }
9577
9694
  const query = url.searchParams.get("query") ?? undefined;
9578
- const filterMesh = url.searchParams.get("mesh") ?? undefined;
9695
+ const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
9579
9696
  try {
9580
9697
  const all = [];
9581
9698
  for (const [slug, b] of opts.brokers.entries()) {
@@ -9605,7 +9722,7 @@ function makeHandler(opts) {
9605
9722
  respond(res, 400, { error: "missing skill name" });
9606
9723
  return;
9607
9724
  }
9608
- const filterMesh = url.searchParams.get("mesh") ?? undefined;
9725
+ const filterMesh = meshFromCtx(url.searchParams.get("mesh")) ?? undefined;
9609
9726
  try {
9610
9727
  for (const [slug, b] of opts.brokers.entries()) {
9611
9728
  if (filterMesh && filterMesh !== slug)
@@ -9633,7 +9750,7 @@ function makeHandler(opts) {
9633
9750
  respond(res, 400, { error: "expected JSON object" });
9634
9751
  return;
9635
9752
  }
9636
- const requested = (typeof body.mesh === "string" ? body.mesh : url.searchParams.get("mesh")) || null;
9753
+ const requested = meshFromCtx(typeof body.mesh === "string" ? body.mesh : url.searchParams.get("mesh"));
9637
9754
  const targets = requested ? [opts.brokers.get(requested)].filter(Boolean) : [...opts.brokers.values()];
9638
9755
  if (targets.length === 0) {
9639
9756
  respond(res, 404, { error: "mesh_not_attached", mesh: requested });
@@ -9743,11 +9860,11 @@ function makeHandler(opts) {
9743
9860
  respond(res, 400, { error: "missing 'id'" });
9744
9861
  return;
9745
9862
  }
9746
- const newId = typeof body.new_client_message_id === "string" && body.new_client_message_id.trim() ? body.new_client_message_id.trim() : randomUUID4();
9863
+ const newId = typeof body.new_client_message_id === "string" && body.new_client_message_id.trim() ? body.new_client_message_id.trim() : randomUUID3();
9747
9864
  const result = requeueDeadOrPending(opts.outboxDb, {
9748
9865
  id: body.id,
9749
9866
  newClientMessageId: newId,
9750
- newRowId: randomUUID4(),
9867
+ newRowId: randomUUID3(),
9751
9868
  now: Date.now(),
9752
9869
  abortedBy: typeof body.aborted_by === "string" ? body.aborted_by : "operator"
9753
9870
  });
@@ -9917,16 +10034,16 @@ function parseSendRequest(body, idempotencyHeader) {
9917
10034
  }
9918
10035
  async function resolveAndEncrypt(req, broker, meshSecretKey, meshSlug) {
9919
10036
  const { encryptDirect: encryptDirect2 } = await Promise.resolve().then(() => (init_box(), exports_box));
9920
- const { randomBytes: randomBytes5 } = await import("node:crypto");
10037
+ const { randomBytes: randomBytes6 } = await import("node:crypto");
9921
10038
  const to = req.to.trim();
9922
10039
  if (to.startsWith("#") && /^#[0-9a-z_-]{20,}$/i.test(to)) {
9923
10040
  const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
9924
- const nonce = randomBytes5(24).toString("base64");
10041
+ const nonce = randomBytes6(24).toString("base64");
9925
10042
  return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
9926
10043
  }
9927
10044
  if (to.startsWith("@") || to === "*") {
9928
10045
  const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
9929
- const nonce = randomBytes5(24).toString("base64");
10046
+ const nonce = randomBytes6(24).toString("base64");
9930
10047
  return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
9931
10048
  }
9932
10049
  if (/^[0-9a-f]{64}$/i.test(to)) {
@@ -9967,6 +10084,7 @@ function respond(res, status, body) {
9967
10084
  var init_server = __esm(() => {
9968
10085
  init_paths2();
9969
10086
  init_send2();
10087
+ init_session_registry();
9970
10088
  init_urls();
9971
10089
  });
9972
10090
 
@@ -10598,8 +10716,8 @@ function bufferToHex(b) {
10598
10716
  return s;
10599
10717
  }
10600
10718
  async function randomNonce2() {
10601
- const { randomBytes: randomBytes5 } = await import("node:crypto");
10602
- return randomBytes5(24).toString("base64");
10719
+ const { randomBytes: randomBytes6 } = await import("node:crypto");
10720
+ return randomBytes6(24).toString("base64");
10603
10721
  }
10604
10722
  function defaultLog2(level, msg, meta) {
10605
10723
  const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
@@ -10614,7 +10732,7 @@ var POLL_INTERVAL_MS = 500, MAX_ATTEMPTS_PER_ROW = 25, BACKOFF_BASE_MS = 500, BA
10614
10732
  var init_drain = () => {};
10615
10733
 
10616
10734
  // src/daemon/inbound.ts
10617
- import { randomUUID as randomUUID5 } from "node:crypto";
10735
+ import { randomUUID as randomUUID4 } from "node:crypto";
10618
10736
  async function handleBrokerPush(msg, ctx) {
10619
10737
  if (msg.subtype === "system" && typeof msg.event === "string") {
10620
10738
  ctx.bus.publish(mapSystemEventKind(msg.event), {
@@ -10637,14 +10755,14 @@ async function handleBrokerPush(msg, ctx) {
10637
10755
  const createdAt = stringOrNull(msg.createdAt);
10638
10756
  const priority = stringOrNull(msg.priority) ?? "next";
10639
10757
  const subtype = stringOrNull(msg.subtype);
10640
- const clientMessageId = stringOrNull(msg.client_message_id) ?? brokerMessageId ?? randomUUID5();
10758
+ const clientMessageId = stringOrNull(msg.client_message_id) ?? brokerMessageId ?? randomUUID4();
10641
10759
  const body = await decryptOrFallback({
10642
10760
  ciphertext,
10643
10761
  nonce,
10644
10762
  senderPubkey,
10645
10763
  ctx
10646
10764
  });
10647
- const id = randomUUID5();
10765
+ const id = randomUUID4();
10648
10766
  const inserted = insertIfNew(ctx.db, {
10649
10767
  id,
10650
10768
  client_message_id: clientMessageId,
@@ -10721,12 +10839,12 @@ __export(exports_identity, {
10721
10839
  checkFingerprint: () => checkFingerprint,
10722
10840
  acceptCurrentHost: () => acceptCurrentHost
10723
10841
  });
10724
- import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync9 } from "node:fs";
10725
- import { join as join8 } from "node:path";
10842
+ import { existsSync as existsSync10, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "node:fs";
10843
+ import { join as join7 } from "node:path";
10726
10844
  import { createHash as createHash2 } from "node:crypto";
10727
10845
  import { networkInterfaces } from "node:os";
10728
10846
  function path() {
10729
- return join8(DAEMON_PATHS.DAEMON_DIR, FILE_NAME);
10847
+ return join7(DAEMON_PATHS.DAEMON_DIR, FILE_NAME);
10730
10848
  }
10731
10849
  function computeCurrentFingerprint() {
10732
10850
  const host_id = readHostId() ?? "";
@@ -10743,12 +10861,12 @@ function computeCurrentFingerprint() {
10743
10861
  function checkFingerprint() {
10744
10862
  const current = computeCurrentFingerprint();
10745
10863
  if (!existsSync10(path())) {
10746
- writeFileSync9(path(), JSON.stringify(current, null, 2), { mode: 384 });
10864
+ writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
10747
10865
  return { result: "first_run", current };
10748
10866
  }
10749
10867
  let stored;
10750
10868
  try {
10751
- stored = JSON.parse(readFileSync8(path(), "utf8"));
10869
+ stored = JSON.parse(readFileSync9(path(), "utf8"));
10752
10870
  } catch {
10753
10871
  return { result: "unavailable", current };
10754
10872
  }
@@ -10758,14 +10876,14 @@ function checkFingerprint() {
10758
10876
  }
10759
10877
  function acceptCurrentHost() {
10760
10878
  const current = computeCurrentFingerprint();
10761
- writeFileSync9(path(), JSON.stringify(current, null, 2), { mode: 384 });
10879
+ writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
10762
10880
  return current;
10763
10881
  }
10764
10882
  function readHostId() {
10765
10883
  if (process.platform === "linux") {
10766
10884
  for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
10767
10885
  try {
10768
- const raw = readFileSync8(p, "utf8").trim();
10886
+ const raw = readFileSync9(p, "utf8").trim();
10769
10887
  if (raw)
10770
10888
  return `linux:${raw}`;
10771
10889
  } catch {}
@@ -10810,7 +10928,7 @@ var init_identity = __esm(() => {
10810
10928
  });
10811
10929
 
10812
10930
  // src/daemon/run.ts
10813
- import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9 } from "node:fs";
10931
+ import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync10 } from "node:fs";
10814
10932
  function detectContainer() {
10815
10933
  if (process.env.KUBERNETES_SERVICE_HOST)
10816
10934
  return true;
@@ -10819,7 +10937,7 @@ function detectContainer() {
10819
10937
  try {
10820
10938
  if (existsSync11("/.dockerenv"))
10821
10939
  return true;
10822
- const cg = readFileSync9("/proc/1/cgroup", "utf8");
10940
+ const cg = readFileSync10("/proc/1/cgroup", "utf8");
10823
10941
  if (/(docker|kubepods|containerd)/.test(cg))
10824
10942
  return true;
10825
10943
  } catch {}
@@ -10838,10 +10956,10 @@ async function runDaemon(opts = {}) {
10838
10956
  `);
10839
10957
  }
10840
10958
  const fpCheck = checkFingerprint();
10841
- const policy = opts.clonePolicy ?? "refuse";
10959
+ const policy2 = opts.clonePolicy ?? "refuse";
10842
10960
  if (fpCheck.result === "mismatch") {
10843
10961
  const msg = `host_fingerprint mismatch: this daemon dir was started on a different host.`;
10844
- if (policy === "refuse") {
10962
+ if (policy2 === "refuse") {
10845
10963
  process.stderr.write(`${msg}
10846
10964
  `);
10847
10965
  process.stderr.write(` stored host_id: ${fpCheck.stored?.host_id}
@@ -10855,7 +10973,7 @@ async function runDaemon(opts = {}) {
10855
10973
  releaseSingletonLock();
10856
10974
  return 4;
10857
10975
  }
10858
- if (policy === "warn") {
10976
+ if (policy2 === "warn") {
10859
10977
  process.stderr.write(`WARN: ${msg} (continuing per [clone] policy=warn)
10860
10978
  `);
10861
10979
  }
@@ -10944,6 +11062,7 @@ async function runDaemon(opts = {}) {
10944
11062
  }
10945
11063
  let drain = null;
10946
11064
  drain = startDrainWorker({ db: outboxDb, brokers });
11065
+ startReaper();
10947
11066
  const ipc2 = startIpcServer({
10948
11067
  localToken,
10949
11068
  tcpEnabled,
@@ -11005,6 +11124,7 @@ var init_run = __esm(() => {
11005
11124
  init_lock();
11006
11125
  init_local_token();
11007
11126
  init_server();
11127
+ init_session_registry();
11008
11128
  init_broker();
11009
11129
  init_drain();
11010
11130
  init_inbound();
@@ -11020,10 +11140,10 @@ __export(exports_service_install, {
11020
11140
  installService: () => installService,
11021
11141
  detectPlatform: () => detectPlatform
11022
11142
  });
11023
- import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync10, unlinkSync as unlinkSync5, readFileSync as readFileSync10 } from "node:fs";
11143
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, writeFileSync as writeFileSync11, unlinkSync as unlinkSync5, readFileSync as readFileSync11 } from "node:fs";
11024
11144
  import { execSync as execSync2 } from "node:child_process";
11025
- import { homedir as homedir6 } from "node:os";
11026
- import { join as join9, dirname as dirname5 } from "node:path";
11145
+ import { homedir as homedir5 } from "node:os";
11146
+ import { join as join8, dirname as dirname5 } from "node:path";
11027
11147
  function detectPlatform() {
11028
11148
  if (process.platform === "darwin")
11029
11149
  return "darwin";
@@ -11074,7 +11194,7 @@ function uninstallService() {
11074
11194
  return { platform: platform5, removed };
11075
11195
  }
11076
11196
  function darwinPlistPath() {
11077
- return join9(homedir6(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
11197
+ return join8(homedir5(), "Library", "LaunchAgents", `${SERVICE_LABEL}.plist`);
11078
11198
  }
11079
11199
  function installDarwin(args) {
11080
11200
  const plist = darwinPlistPath();
@@ -11108,18 +11228,18 @@ function installDarwin(args) {
11108
11228
  <key>StandardErrorPath</key>
11109
11229
  <string>${escapeXml(log2)}</string>
11110
11230
  <key>WorkingDirectory</key>
11111
- <string>${escapeXml(homedir6())}</string>
11231
+ <string>${escapeXml(homedir5())}</string>
11112
11232
  <key>EnvironmentVariables</key>
11113
11233
  <dict>
11114
11234
  <key>HOME</key>
11115
- <string>${escapeXml(homedir6())}</string>
11235
+ <string>${escapeXml(homedir5())}</string>
11116
11236
  <key>PATH</key>
11117
11237
  <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
11118
11238
  </dict>
11119
11239
  </dict>
11120
11240
  </plist>
11121
11241
  `;
11122
- writeFileSync10(plist, xml, { mode: 420 });
11242
+ writeFileSync11(plist, xml, { mode: 420 });
11123
11243
  return {
11124
11244
  platform: "darwin",
11125
11245
  unitPath: plist,
@@ -11127,7 +11247,7 @@ function installDarwin(args) {
11127
11247
  };
11128
11248
  }
11129
11249
  function linuxUnitPath() {
11130
- return join9(homedir6(), ".config", "systemd", "user", SYSTEMD_UNIT);
11250
+ return join8(homedir5(), ".config", "systemd", "user", SYSTEMD_UNIT);
11131
11251
  }
11132
11252
  function installLinux(args) {
11133
11253
  const unit = linuxUnitPath();
@@ -11156,7 +11276,7 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin
11156
11276
  [Install]
11157
11277
  WantedBy=default.target
11158
11278
  `;
11159
- writeFileSync10(unit, content, { mode: 420 });
11279
+ writeFileSync11(unit, content, { mode: 420 });
11160
11280
  return {
11161
11281
  platform: "linux",
11162
11282
  unitPath: unit,
@@ -11179,7 +11299,7 @@ function readInstalledUnit() {
11179
11299
  if (!existsSync12(path2))
11180
11300
  return { platform: platform5, path: null, content: null };
11181
11301
  try {
11182
- return { platform: platform5, path: path2, content: readFileSync10(path2, "utf8") };
11302
+ return { platform: platform5, path: path2, content: readFileSync11(path2, "utf8") };
11183
11303
  } catch {
11184
11304
  return { platform: platform5, path: path2, content: null };
11185
11305
  }
@@ -11523,17 +11643,17 @@ import {
11523
11643
  copyFileSync,
11524
11644
  existsSync as existsSync13,
11525
11645
  mkdirSync as mkdirSync8,
11526
- readFileSync as readFileSync11,
11527
- writeFileSync as writeFileSync11
11646
+ readFileSync as readFileSync12,
11647
+ writeFileSync as writeFileSync12
11528
11648
  } from "node:fs";
11529
- import { homedir as homedir7, platform as platform5 } from "node:os";
11530
- import { dirname as dirname6, join as join10, resolve } from "node:path";
11649
+ import { homedir as homedir6, platform as platform5 } from "node:os";
11650
+ import { dirname as dirname6, join as join9, resolve } from "node:path";
11531
11651
  import { fileURLToPath } from "node:url";
11532
11652
  import { spawnSync as spawnSync3 } from "node:child_process";
11533
11653
  function readClaudeConfig() {
11534
11654
  if (!existsSync13(CLAUDE_CONFIG))
11535
11655
  return {};
11536
- const text = readFileSync11(CLAUDE_CONFIG, "utf-8").trim();
11656
+ const text = readFileSync12(CLAUDE_CONFIG, "utf-8").trim();
11537
11657
  if (!text)
11538
11658
  return {};
11539
11659
  try {
@@ -11545,10 +11665,10 @@ function readClaudeConfig() {
11545
11665
  function backupClaudeConfig() {
11546
11666
  if (!existsSync13(CLAUDE_CONFIG))
11547
11667
  return;
11548
- const backupDir = join10(dirname6(CLAUDE_CONFIG), ".claude", "backups");
11668
+ const backupDir = join9(dirname6(CLAUDE_CONFIG), ".claude", "backups");
11549
11669
  mkdirSync8(backupDir, { recursive: true });
11550
11670
  const ts = Date.now();
11551
- const dest = join10(backupDir, `.claude.json.pre-claudemesh.${ts}`);
11671
+ const dest = join9(backupDir, `.claude.json.pre-claudemesh.${ts}`);
11552
11672
  copyFileSync(CLAUDE_CONFIG, dest);
11553
11673
  }
11554
11674
  function patchMcpServer(entry) {
@@ -11586,7 +11706,7 @@ function removeMcpServer() {
11586
11706
  }
11587
11707
  function flushClaudeConfig(obj) {
11588
11708
  mkdirSync8(dirname6(CLAUDE_CONFIG), { recursive: true });
11589
- writeFileSync11(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
11709
+ writeFileSync12(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
11590
11710
  `, "utf-8");
11591
11711
  try {
11592
11712
  chmodSync4(CLAUDE_CONFIG, 384);
@@ -11608,7 +11728,7 @@ function resolveEntry() {
11608
11728
  function resolveBundledSkillsDir() {
11609
11729
  const here = fileURLToPath(import.meta.url);
11610
11730
  const pkgRoot = resolve(dirname6(here), "..", "..");
11611
- const skillsDir = join10(pkgRoot, "skills");
11731
+ const skillsDir = join9(pkgRoot, "skills");
11612
11732
  if (existsSync13(skillsDir))
11613
11733
  return skillsDir;
11614
11734
  return null;
@@ -11622,13 +11742,13 @@ function installSkills() {
11622
11742
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
11623
11743
  if (!entry.isDirectory())
11624
11744
  continue;
11625
- const srcDir = join10(src, entry.name);
11626
- const dstDir = join10(CLAUDE_SKILLS_ROOT, entry.name);
11745
+ const srcDir = join9(src, entry.name);
11746
+ const dstDir = join9(CLAUDE_SKILLS_ROOT, entry.name);
11627
11747
  mkdirSync8(dstDir, { recursive: true });
11628
11748
  for (const file of fs.readdirSync(srcDir, { withFileTypes: true })) {
11629
11749
  if (!file.isFile())
11630
11750
  continue;
11631
- copyFileSync(join10(srcDir, file.name), join10(dstDir, file.name));
11751
+ copyFileSync(join9(srcDir, file.name), join9(dstDir, file.name));
11632
11752
  }
11633
11753
  installed.push(entry.name);
11634
11754
  }
@@ -11643,7 +11763,7 @@ function uninstallSkills() {
11643
11763
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
11644
11764
  if (!entry.isDirectory())
11645
11765
  continue;
11646
- const dstDir = join10(CLAUDE_SKILLS_ROOT, entry.name);
11766
+ const dstDir = join9(CLAUDE_SKILLS_ROOT, entry.name);
11647
11767
  if (existsSync13(dstDir)) {
11648
11768
  try {
11649
11769
  fs.rmSync(dstDir, { recursive: true, force: true });
@@ -11671,7 +11791,7 @@ function entriesEqual(a, b) {
11671
11791
  function readClaudeSettings() {
11672
11792
  if (!existsSync13(CLAUDE_SETTINGS))
11673
11793
  return {};
11674
- const text = readFileSync11(CLAUDE_SETTINGS, "utf-8").trim();
11794
+ const text = readFileSync12(CLAUDE_SETTINGS, "utf-8").trim();
11675
11795
  if (!text)
11676
11796
  return {};
11677
11797
  try {
@@ -11682,7 +11802,7 @@ function readClaudeSettings() {
11682
11802
  }
11683
11803
  function writeClaudeSettings(obj) {
11684
11804
  mkdirSync8(dirname6(CLAUDE_SETTINGS), { recursive: true });
11685
- writeFileSync11(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
11805
+ writeFileSync12(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
11686
11806
  `, "utf-8");
11687
11807
  }
11688
11808
  function installAllowedTools() {
@@ -11832,7 +11952,7 @@ function runInstall(args = []) {
11832
11952
  const installed = installSkills();
11833
11953
  if (installed.length > 0) {
11834
11954
  render.ok(`Claude skill${installed.length === 1 ? "" : "s"} installed`, installed.join(", "));
11835
- render.info(dim(` ${join10(CLAUDE_SKILLS_ROOT, installed[0])}/SKILL.md`));
11955
+ render.info(dim(` ${join9(CLAUDE_SKILLS_ROOT, installed[0])}/SKILL.md`));
11836
11956
  }
11837
11957
  } catch (e) {
11838
11958
  render.warn(`skill install failed: ${e instanceof Error ? e.message : String(e)}`);
@@ -11969,9 +12089,9 @@ var init_install = __esm(() => {
11969
12089
  init_facade();
11970
12090
  init_render();
11971
12091
  init_styles();
11972
- CLAUDE_CONFIG = join10(homedir7(), ".claude.json");
11973
- CLAUDE_SETTINGS = join10(homedir7(), ".claude", "settings.json");
11974
- CLAUDE_SKILLS_ROOT = join10(homedir7(), ".claude", "skills");
12092
+ CLAUDE_CONFIG = join9(homedir6(), ".claude.json");
12093
+ CLAUDE_SETTINGS = join9(homedir6(), ".claude", "settings.json");
12094
+ CLAUDE_SKILLS_ROOT = join9(homedir6(), ".claude", "skills");
11975
12095
  CLAUDEMESH_TOOLS = [
11976
12096
  "mcp__claudemesh__cancel_scheduled",
11977
12097
  "mcp__claudemesh__check_messages",
@@ -12026,26 +12146,26 @@ var exports_uninstall = {};
12026
12146
  __export(exports_uninstall, {
12027
12147
  uninstall: () => uninstall
12028
12148
  });
12029
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync12, existsSync as existsSync14, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
12030
- import { join as join11, dirname as dirname7 } from "node:path";
12031
- import { homedir as homedir8 } from "node:os";
12149
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync14, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
12150
+ import { join as join10, dirname as dirname7 } from "node:path";
12151
+ import { homedir as homedir7 } from "node:os";
12032
12152
  import { fileURLToPath as fileURLToPath2 } from "node:url";
12033
12153
  function bundledSkillsDir() {
12034
12154
  const here = fileURLToPath2(import.meta.url);
12035
- const pkgRoot = join11(dirname7(here), "..", "..");
12036
- const skillsDir = join11(pkgRoot, "skills");
12155
+ const pkgRoot = join10(dirname7(here), "..", "..");
12156
+ const skillsDir = join10(pkgRoot, "skills");
12037
12157
  return existsSync14(skillsDir) ? skillsDir : null;
12038
12158
  }
12039
12159
  async function uninstall() {
12040
12160
  let removed = 0;
12041
12161
  if (existsSync14(PATHS.CLAUDE_JSON)) {
12042
12162
  try {
12043
- const raw = readFileSync12(PATHS.CLAUDE_JSON, "utf-8");
12163
+ const raw = readFileSync13(PATHS.CLAUDE_JSON, "utf-8");
12044
12164
  const config = JSON.parse(raw);
12045
12165
  const servers = config.mcpServers;
12046
12166
  if (servers && "claudemesh" in servers) {
12047
12167
  delete servers.claudemesh;
12048
- writeFileSync12(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
12168
+ writeFileSync13(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
12049
12169
  `, "utf-8");
12050
12170
  render.ok("removed MCP server", dim("~/.claude.json"));
12051
12171
  removed++;
@@ -12054,7 +12174,7 @@ async function uninstall() {
12054
12174
  }
12055
12175
  if (existsSync14(PATHS.CLAUDE_SETTINGS)) {
12056
12176
  try {
12057
- const raw = readFileSync12(PATHS.CLAUDE_SETTINGS, "utf-8");
12177
+ const raw = readFileSync13(PATHS.CLAUDE_SETTINGS, "utf-8");
12058
12178
  const config = JSON.parse(raw);
12059
12179
  const hooks = config.hooks;
12060
12180
  if (hooks) {
@@ -12075,7 +12195,7 @@ async function uninstall() {
12075
12195
  }
12076
12196
  }
12077
12197
  if (removedHooks > 0) {
12078
- writeFileSync12(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
12198
+ writeFileSync13(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
12079
12199
  `, "utf-8");
12080
12200
  render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
12081
12201
  removed++;
@@ -12090,7 +12210,7 @@ async function uninstall() {
12090
12210
  for (const entry of readdirSync2(src, { withFileTypes: true })) {
12091
12211
  if (!entry.isDirectory())
12092
12212
  continue;
12093
- const dst = join11(CLAUDE_SKILLS_ROOT2, entry.name);
12213
+ const dst = join10(CLAUDE_SKILLS_ROOT2, entry.name);
12094
12214
  if (existsSync14(dst)) {
12095
12215
  try {
12096
12216
  rmSync2(dst, { recursive: true, force: true });
@@ -12115,7 +12235,7 @@ var init_uninstall = __esm(() => {
12115
12235
  init_render();
12116
12236
  init_styles();
12117
12237
  init_exit_codes();
12118
- CLAUDE_SKILLS_ROOT2 = join11(homedir8(), ".claude", "skills");
12238
+ CLAUDE_SKILLS_ROOT2 = join10(homedir7(), ".claude", "skills");
12119
12239
  });
12120
12240
 
12121
12241
  // src/commands/doctor.ts
@@ -12123,9 +12243,9 @@ var exports_doctor = {};
12123
12243
  __export(exports_doctor, {
12124
12244
  runDoctor: () => runDoctor
12125
12245
  });
12126
- import { existsSync as existsSync15, readFileSync as readFileSync13, statSync as statSync3 } from "node:fs";
12127
- import { homedir as homedir9, platform as platform6 } from "node:os";
12128
- import { join as join12 } from "node:path";
12246
+ import { existsSync as existsSync15, readFileSync as readFileSync14, statSync as statSync3 } from "node:fs";
12247
+ import { homedir as homedir8, platform as platform6 } from "node:os";
12248
+ import { join as join11 } from "node:path";
12129
12249
  import { spawnSync as spawnSync4 } from "node:child_process";
12130
12250
  function checkNode() {
12131
12251
  const major = Number(process.versions.node.split(".")[0]);
@@ -12149,7 +12269,7 @@ function checkClaudeOnPath() {
12149
12269
  };
12150
12270
  }
12151
12271
  function checkMcpRegistered() {
12152
- const claudeConfig = join12(homedir9(), ".claude.json");
12272
+ const claudeConfig = join11(homedir8(), ".claude.json");
12153
12273
  if (!existsSync15(claudeConfig)) {
12154
12274
  return {
12155
12275
  name: "claudemesh MCP registered in ~/.claude.json",
@@ -12158,7 +12278,7 @@ function checkMcpRegistered() {
12158
12278
  };
12159
12279
  }
12160
12280
  try {
12161
- const cfg = JSON.parse(readFileSync13(claudeConfig, "utf-8"));
12281
+ const cfg = JSON.parse(readFileSync14(claudeConfig, "utf-8"));
12162
12282
  const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
12163
12283
  return {
12164
12284
  name: "claudemesh MCP registered in ~/.claude.json",
@@ -12175,7 +12295,7 @@ function checkMcpRegistered() {
12175
12295
  }
12176
12296
  }
12177
12297
  function checkHooksRegistered() {
12178
- const settings = join12(homedir9(), ".claude", "settings.json");
12298
+ const settings = join11(homedir8(), ".claude", "settings.json");
12179
12299
  if (!existsSync15(settings)) {
12180
12300
  return {
12181
12301
  name: "Status hooks registered in ~/.claude/settings.json",
@@ -12184,7 +12304,7 @@ function checkHooksRegistered() {
12184
12304
  };
12185
12305
  }
12186
12306
  try {
12187
- const raw = readFileSync13(settings, "utf-8");
12307
+ const raw = readFileSync14(settings, "utf-8");
12188
12308
  const has = raw.includes("claudemesh hook ");
12189
12309
  return {
12190
12310
  name: "Status hooks registered in ~/.claude/settings.json",
@@ -12560,13 +12680,13 @@ var init_check_claude_binary = __esm(() => {
12560
12680
  });
12561
12681
 
12562
12682
  // src/services/health/check-mcp-registered.ts
12563
- import { existsSync as existsSync17, readFileSync as readFileSync14 } from "node:fs";
12683
+ import { existsSync as existsSync17, readFileSync as readFileSync15 } from "node:fs";
12564
12684
  function checkMcpRegistered2() {
12565
12685
  try {
12566
12686
  if (!existsSync17(PATHS.CLAUDE_JSON)) {
12567
12687
  return { name: "mcp-registered", ok: false, message: "~/.claude.json not found" };
12568
12688
  }
12569
- const raw = readFileSync14(PATHS.CLAUDE_JSON, "utf-8");
12689
+ const raw = readFileSync15(PATHS.CLAUDE_JSON, "utf-8");
12570
12690
  const config = JSON.parse(raw);
12571
12691
  if (config.mcpServers && "claudemesh" in config.mcpServers) {
12572
12692
  return { name: "mcp-registered", ok: true, message: "MCP server registered" };
@@ -12581,13 +12701,13 @@ var init_check_mcp_registered = __esm(() => {
12581
12701
  });
12582
12702
 
12583
12703
  // src/services/health/check-hooks-registered.ts
12584
- import { existsSync as existsSync18, readFileSync as readFileSync15 } from "node:fs";
12704
+ import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
12585
12705
  function checkHooksRegistered2() {
12586
12706
  try {
12587
12707
  if (!existsSync18(PATHS.CLAUDE_SETTINGS)) {
12588
12708
  return { name: "hooks-registered", ok: false, message: "~/.claude/settings.json not found" };
12589
12709
  }
12590
- const raw = readFileSync15(PATHS.CLAUDE_SETTINGS, "utf-8");
12710
+ const raw = readFileSync16(PATHS.CLAUDE_SETTINGS, "utf-8");
12591
12711
  const config = JSON.parse(raw);
12592
12712
  if (config.hooks) {
12593
12713
  return { name: "hooks-registered", ok: true, message: "Hooks configured" };
@@ -12623,13 +12743,13 @@ var init_check_config_perms = __esm(() => {
12623
12743
  });
12624
12744
 
12625
12745
  // src/services/health/check-keypairs-valid.ts
12626
- import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
12746
+ import { existsSync as existsSync20, readFileSync as readFileSync17 } from "node:fs";
12627
12747
  function checkKeypairsValid() {
12628
12748
  if (!existsSync20(PATHS.CONFIG_FILE)) {
12629
12749
  return { name: "keypairs-valid", ok: true, message: "No config (first run)" };
12630
12750
  }
12631
12751
  try {
12632
- const raw = readFileSync16(PATHS.CONFIG_FILE, "utf-8");
12752
+ const raw = readFileSync17(PATHS.CONFIG_FILE, "utf-8");
12633
12753
  const config = JSON.parse(raw);
12634
12754
  const meshes = config.meshes ?? [];
12635
12755
  if (meshes.length === 0) {
@@ -13109,18 +13229,18 @@ var exports_url_handler = {};
13109
13229
  __export(exports_url_handler, {
13110
13230
  runUrlHandler: () => runUrlHandler
13111
13231
  });
13112
- import { platform as platform7, homedir as homedir10 } from "node:os";
13113
- import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync13, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
13114
- import { join as join13 } from "node:path";
13232
+ import { platform as platform7, homedir as homedir9 } from "node:os";
13233
+ import { existsSync as existsSync21, mkdirSync as mkdirSync9, writeFileSync as writeFileSync14, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
13234
+ import { join as join12 } from "node:path";
13115
13235
  import { spawnSync as spawnSync5 } from "node:child_process";
13116
13236
  function resolveClaudemeshBin() {
13117
13237
  return process.argv[1] ?? "claudemesh";
13118
13238
  }
13119
13239
  function installDarwin2() {
13120
13240
  const binPath = resolveClaudemeshBin();
13121
- const appDir = join13(homedir10(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
13122
- const contents = join13(appDir, "Contents");
13123
- const macOS = join13(contents, "MacOS");
13241
+ const appDir = join12(homedir9(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
13242
+ const contents = join12(appDir, "Contents");
13243
+ const macOS = join12(contents, "MacOS");
13124
13244
  mkdirSync9(macOS, { recursive: true });
13125
13245
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
13126
13246
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -13144,7 +13264,7 @@ function installDarwin2() {
13144
13264
  </array>
13145
13265
  </dict>
13146
13266
  </plist>`;
13147
- writeFileSync13(join13(contents, "Info.plist"), plist);
13267
+ writeFileSync14(join12(contents, "Info.plist"), plist);
13148
13268
  const shim = `#!/bin/sh
13149
13269
  URL="$1"
13150
13270
  CODE=\${URL#claudemesh://}
@@ -13158,8 +13278,8 @@ tell application "Terminal"
13158
13278
  end tell
13159
13279
  EOF
13160
13280
  `;
13161
- const shimPath = join13(macOS, "open-url");
13162
- writeFileSync13(shimPath, shim);
13281
+ const shimPath = join12(macOS, "open-url");
13282
+ writeFileSync14(shimPath, shim);
13163
13283
  chmodSync5(shimPath, 493);
13164
13284
  const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
13165
13285
  if (lsreg.status !== 0) {
@@ -13170,7 +13290,7 @@ EOF
13170
13290
  }
13171
13291
  function installLinux2() {
13172
13292
  const binPath = resolveClaudemeshBin();
13173
- const appsDir = join13(homedir10(), ".local", "share", "applications");
13293
+ const appsDir = join12(homedir9(), ".local", "share", "applications");
13174
13294
  mkdirSync9(appsDir, { recursive: true });
13175
13295
  const desktop = `[Desktop Entry]
13176
13296
  Type=Application
@@ -13182,8 +13302,8 @@ Terminal=true
13182
13302
  MimeType=x-scheme-handler/claudemesh;
13183
13303
  NoDisplay=true
13184
13304
  `;
13185
- const desktopPath = join13(appsDir, "claudemesh.desktop");
13186
- writeFileSync13(desktopPath, desktop);
13305
+ const desktopPath = join12(appsDir, "claudemesh.desktop");
13306
+ writeFileSync14(desktopPath, desktop);
13187
13307
  const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
13188
13308
  if (xdg1.status !== 0) {
13189
13309
  render.warn("xdg-mime not available — skipped mime default registration");
@@ -13205,8 +13325,8 @@ function installWindows() {
13205
13325
  `[HKEY_CURRENT_USER\\Software\\Classes\\claudemesh\\shell\\open\\command]`,
13206
13326
  `@="\\"${binPath.replace(/\\/g, "\\\\")}\\" \\"%1\\""`
13207
13327
  ];
13208
- const regPath = join13(homedir10(), "claudemesh-handler.reg");
13209
- writeFileSync13(regPath, lines.join(`\r
13328
+ const regPath = join12(homedir9(), "claudemesh-handler.reg");
13329
+ writeFileSync14(regPath, lines.join(`\r
13210
13330
  `));
13211
13331
  const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
13212
13332
  if (res.status !== 0) {
@@ -13217,14 +13337,14 @@ function installWindows() {
13217
13337
  return EXIT.SUCCESS;
13218
13338
  }
13219
13339
  function uninstallDarwin() {
13220
- const appDir = join13(homedir10(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
13340
+ const appDir = join12(homedir9(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
13221
13341
  if (existsSync21(appDir))
13222
13342
  rmSync3(appDir, { recursive: true, force: true });
13223
13343
  render.ok("removed claudemesh:// handler on macOS");
13224
13344
  return EXIT.SUCCESS;
13225
13345
  }
13226
13346
  function uninstallLinux() {
13227
- const desktopPath = join13(homedir10(), ".local", "share", "applications", "claudemesh.desktop");
13347
+ const desktopPath = join12(homedir9(), ".local", "share", "applications", "claudemesh.desktop");
13228
13348
  if (existsSync21(desktopPath))
13229
13349
  rmSync3(desktopPath, { force: true });
13230
13350
  render.ok("removed claudemesh:// handler on Linux");
@@ -13270,9 +13390,9 @@ var exports_status_line = {};
13270
13390
  __export(exports_status_line, {
13271
13391
  runStatusLine: () => runStatusLine
13272
13392
  });
13273
- import { existsSync as existsSync22, readFileSync as readFileSync17 } from "node:fs";
13274
- import { join as join14 } from "node:path";
13275
- import { homedir as homedir11 } from "node:os";
13393
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
13394
+ import { join as join13 } from "node:path";
13395
+ import { homedir as homedir10 } from "node:os";
13276
13396
  async function runStatusLine() {
13277
13397
  try {
13278
13398
  const config = readConfig();
@@ -13280,11 +13400,11 @@ async function runStatusLine() {
13280
13400
  process.stdout.write("◇ claudemesh (not joined)");
13281
13401
  return EXIT.SUCCESS;
13282
13402
  }
13283
- const cachePath = join14(homedir11(), ".claudemesh", "peer-cache.json");
13403
+ const cachePath = join13(homedir10(), ".claudemesh", "peer-cache.json");
13284
13404
  let cache = {};
13285
13405
  if (existsSync22(cachePath)) {
13286
13406
  try {
13287
- cache = JSON.parse(readFileSync17(cachePath, "utf-8"));
13407
+ cache = JSON.parse(readFileSync18(cachePath, "utf-8"));
13288
13408
  } catch {}
13289
13409
  }
13290
13410
  const pick = config.meshes[0];
@@ -13315,7 +13435,7 @@ __export(exports_backup, {
13315
13435
  runRestore: () => runRestore,
13316
13436
  runBackup: () => runBackup
13317
13437
  });
13318
- import { readFileSync as readFileSync18, writeFileSync as writeFileSync14, existsSync as existsSync23 } from "node:fs";
13438
+ import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, existsSync as existsSync23 } from "node:fs";
13319
13439
  import { createInterface as createInterface11 } from "node:readline";
13320
13440
  function readHidden(prompt5) {
13321
13441
  return new Promise((resolve2) => {
@@ -13361,7 +13481,7 @@ async function runBackup(outPath) {
13361
13481
  console.error(" No config found — nothing to back up. Join a mesh first.");
13362
13482
  return EXIT.NOT_FOUND;
13363
13483
  }
13364
- const plaintext = readFileSync18(configPath);
13484
+ const plaintext = readFileSync19(configPath);
13365
13485
  const pass = await readHidden(" Passphrase (min 12 chars): ");
13366
13486
  if (pass.length < 12) {
13367
13487
  console.error(" ✗ Passphrase too short.");
@@ -13379,7 +13499,7 @@ async function runBackup(outPath) {
13379
13499
  const ciphertext = Buffer.from(s.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, null, null, nonce, key));
13380
13500
  const blob = Buffer.concat([MAGIC, salt, nonce, ciphertext]);
13381
13501
  const file = outPath ?? `claudemesh-backup-${new Date().toISOString().replace(/[:.]/g, "-")}.cmb`;
13382
- writeFileSync14(file, blob, { mode: 384 });
13502
+ writeFileSync15(file, blob, { mode: 384 });
13383
13503
  console.log(`
13384
13504
  ✓ Backup saved: ${file}`);
13385
13505
  console.log(` Size: ${blob.length} bytes. Guard the passphrase — there is no recovery.
@@ -13395,7 +13515,7 @@ async function runRestore(inPath) {
13395
13515
  console.error(` ✗ File not found: ${inPath}`);
13396
13516
  return EXIT.NOT_FOUND;
13397
13517
  }
13398
- const blob = readFileSync18(inPath);
13518
+ const blob = readFileSync19(inPath);
13399
13519
  if (blob.length < 4 + 16 + 24 + 17 || !blob.subarray(0, 4).equals(MAGIC)) {
13400
13520
  console.error(" ✗ Not a claudemesh backup file (bad magic).");
13401
13521
  return EXIT.INVALID_ARGS;
@@ -13416,10 +13536,10 @@ async function runRestore(inPath) {
13416
13536
  const configPath = getConfigPath();
13417
13537
  if (existsSync23(configPath)) {
13418
13538
  const backupOld = `${configPath}.before-restore.${Date.now()}`;
13419
- writeFileSync14(backupOld, readFileSync18(configPath), { mode: 384 });
13539
+ writeFileSync15(backupOld, readFileSync19(configPath), { mode: 384 });
13420
13540
  console.log(` ↻ Existing config saved to ${backupOld}`);
13421
13541
  }
13422
- writeFileSync14(configPath, Buffer.from(plaintext), { mode: 384 });
13542
+ writeFileSync15(configPath, Buffer.from(plaintext), { mode: 384 });
13423
13543
  console.log(`
13424
13544
  ✓ Config restored to ${configPath}`);
13425
13545
  console.log(" Run `claudemesh list` to verify your meshes.\n");
@@ -13440,7 +13560,7 @@ __export(exports_upgrade, {
13440
13560
  });
13441
13561
  import { spawnSync as spawnSync6 } from "node:child_process";
13442
13562
  import { existsSync as existsSync24 } from "node:fs";
13443
- import { dirname as dirname8, join as join15, resolve as resolve2 } from "node:path";
13563
+ import { dirname as dirname8, join as join14, resolve as resolve2 } from "node:path";
13444
13564
  async function latestVersion() {
13445
13565
  try {
13446
13566
  const res = await fetch(URLS.NPM_REGISTRY, { signal: AbortSignal.timeout(8000) });
@@ -13453,14 +13573,14 @@ async function latestVersion() {
13453
13573
  }
13454
13574
  }
13455
13575
  function findNpm() {
13456
- const portable = join15(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
13576
+ const portable = join14(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
13457
13577
  if (existsSync24(portable)) {
13458
- return { npm: portable, prefix: join15(process.env.HOME ?? "", ".claudemesh") };
13578
+ return { npm: portable, prefix: join14(process.env.HOME ?? "", ".claudemesh") };
13459
13579
  }
13460
13580
  let cur = resolve2(process.argv[1] ?? ".");
13461
13581
  for (let i = 0;i < 6; i++) {
13462
13582
  cur = dirname8(cur);
13463
- const candidate = join15(cur, "bin", "npm");
13583
+ const candidate = join14(cur, "bin", "npm");
13464
13584
  if (existsSync24(candidate))
13465
13585
  return { npm: candidate };
13466
13586
  }
@@ -13523,9 +13643,9 @@ __export(exports_grants, {
13523
13643
  runBlock: () => runBlock,
13524
13644
  isAllowed: () => isAllowed
13525
13645
  });
13526
- import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync19, writeFileSync as writeFileSync15 } from "node:fs";
13527
- import { homedir as homedir12 } from "node:os";
13528
- import { join as join16 } from "node:path";
13646
+ import { existsSync as existsSync25, mkdirSync as mkdirSync10, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "node:fs";
13647
+ import { homedir as homedir11 } from "node:os";
13648
+ import { join as join15 } from "node:path";
13529
13649
  async function syncToBroker(meshSlug, grants) {
13530
13650
  const auth = getStoredToken();
13531
13651
  if (!auth)
@@ -13546,16 +13666,16 @@ function readGrants() {
13546
13666
  if (!existsSync25(GRANT_FILE))
13547
13667
  return {};
13548
13668
  try {
13549
- return JSON.parse(readFileSync19(GRANT_FILE, "utf-8"));
13669
+ return JSON.parse(readFileSync20(GRANT_FILE, "utf-8"));
13550
13670
  } catch {
13551
13671
  return {};
13552
13672
  }
13553
13673
  }
13554
13674
  function writeGrants(g) {
13555
- const dir = join16(homedir12(), ".claudemesh");
13675
+ const dir = join15(homedir11(), ".claudemesh");
13556
13676
  if (!existsSync25(dir))
13557
13677
  mkdirSync10(dir, { recursive: true });
13558
- writeFileSync15(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
13678
+ writeFileSync16(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
13559
13679
  }
13560
13680
  function resolveCaps(input) {
13561
13681
  if (input.includes("all"))
@@ -13711,7 +13831,7 @@ var init_grants = __esm(() => {
13711
13831
  BROKER_HTTP7 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
13712
13832
  ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
13713
13833
  DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
13714
- GRANT_FILE = join16(homedir12(), ".claudemesh", "grants.json");
13834
+ GRANT_FILE = join15(homedir11(), ".claudemesh", "grants.json");
13715
13835
  });
13716
13836
 
13717
13837
  // src/commands/profile.ts
@@ -15393,7 +15513,7 @@ __export(exports_file, {
15393
15513
  });
15394
15514
  import { hostname as osHostname } from "node:os";
15395
15515
  import { resolve as resolvePath, basename, dirname as dirname9 } from "node:path";
15396
- import { statSync as statSync7, existsSync as existsSync26, writeFileSync as writeFileSync16, mkdirSync as mkdirSync11 } from "node:fs";
15516
+ import { statSync as statSync7, existsSync as existsSync26, writeFileSync as writeFileSync17, mkdirSync as mkdirSync11 } from "node:fs";
15397
15517
  function emitJson2(data) {
15398
15518
  console.log(JSON.stringify(data, null, 2));
15399
15519
  }
@@ -15490,7 +15610,7 @@ async function runFileGet(fileId, opts) {
15490
15610
  const buf = Buffer.from(await res.arrayBuffer());
15491
15611
  const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
15492
15612
  mkdirSync11(dirname9(outPath), { recursive: true });
15493
- writeFileSync16(outPath, buf);
15613
+ writeFileSync17(outPath, buf);
15494
15614
  if (opts.json) {
15495
15615
  emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
15496
15616
  } else {
@@ -16100,7 +16220,7 @@ __export(exports_bridge, {
16100
16220
  runBridge: () => runBridge,
16101
16221
  bridgeConfigTemplate: () => bridgeConfigTemplate
16102
16222
  });
16103
- import { readFileSync as readFileSync20, existsSync as existsSync27 } from "node:fs";
16223
+ import { readFileSync as readFileSync21, existsSync as existsSync27 } from "node:fs";
16104
16224
  function parseConfig(text) {
16105
16225
  const trimmed = text.trim();
16106
16226
  if (trimmed.startsWith("{"))
@@ -16150,7 +16270,7 @@ async function runBridge(configPath) {
16150
16270
  }
16151
16271
  let cfg;
16152
16272
  try {
16153
- cfg = parseConfig(readFileSync20(configPath, "utf-8"));
16273
+ cfg = parseConfig(readFileSync21(configPath, "utf-8"));
16154
16274
  } catch (e) {
16155
16275
  render.err(`failed to parse ${configPath}: ${e instanceof Error ? e.message : String(e)}`);
16156
16276
  return EXIT.INVALID_ARGS;
@@ -16554,9 +16674,9 @@ function cacheKey(apiKeySecret, topicName) {
16554
16674
  async function getTopicKey(args) {
16555
16675
  const cacheId = cacheKey(args.apiKeySecret, args.topicName);
16556
16676
  if (!args.fresh) {
16557
- const cached2 = cache.get(cacheId);
16558
- if (cached2)
16559
- return { ok: true, topicKey: cached2.topicKey };
16677
+ const cached3 = cache.get(cacheId);
16678
+ if (cached3)
16679
+ return { ok: true, topicKey: cached3.topicKey };
16560
16680
  }
16561
16681
  let sealed;
16562
16682
  try {
@@ -17458,9 +17578,9 @@ async function startServiceProxy(serviceName) {
17458
17578
  const fetched = await client.getServiceTools(serviceName);
17459
17579
  tools = fetched;
17460
17580
  } catch {
17461
- const cached2 = client.serviceCatalog.find((s) => s.name === serviceName);
17462
- if (cached2)
17463
- tools = cached2.tools;
17581
+ const cached3 = client.serviceCatalog.find((s) => s.name === serviceName);
17582
+ if (cached3)
17583
+ tools = cached3.tools;
17464
17584
  }
17465
17585
  if (tools.length === 0) {
17466
17586
  process.stderr.write(`[mesh:${serviceName}] no tools found — service may not be running
@@ -18205,10 +18325,12 @@ async function gate(ctx, opts) {
18205
18325
  }
18206
18326
 
18207
18327
  // src/entrypoints/cli.ts
18328
+ init_policy();
18208
18329
  init_styles();
18209
18330
  installSignalHandlers();
18210
18331
  installErrorHandlers();
18211
18332
  var { command, positionals, flags } = parseArgv(process.argv);
18333
+ setDaemonPolicy(policyFromFlags(flags));
18212
18334
  function resolveApprovalMode() {
18213
18335
  const raw = flags["approval-mode"] ?? process.env.CLAUDEMESH_APPROVAL_MODE ?? null;
18214
18336
  if (raw === "plan" || raw === "read-only" || raw === "write" || raw === "yolo")
@@ -18385,6 +18507,8 @@ Flags
18385
18507
  --policy <path> override policy file
18386
18508
  -y, --yes skip confirmations (= --approval-mode yolo)
18387
18509
  -q, --quiet suppress non-essential output
18510
+ --strict require daemon for broker-touching verbs (no cold-path fallback)
18511
+ --no-daemon skip daemon entirely; open broker WS directly (CI / sandboxed scripts)
18388
18512
  `;
18389
18513
  function colorizeHelp(raw) {
18390
18514
  const lines = raw.split(`
@@ -19426,4 +19550,4 @@ main().catch((err) => {
19426
19550
  process.exit(EXIT.INTERNAL_ERROR);
19427
19551
  });
19428
19552
 
19429
- //# debugId=1F2A51E3A3AE432A64756E2164756E21
19553
+ //# debugId=FBD494B01BF81C7164756E2164756E21