claudemesh-cli 1.35.0 → 1.36.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.
@@ -104,7 +104,7 @@ __export(exports_urls, {
104
104
  VERSION: () => VERSION,
105
105
  URLS: () => URLS
106
106
  });
107
- var URLS, VERSION = "1.35.0", env;
107
+ var URLS, VERSION = "1.36.0", env;
108
108
  var init_urls = __esm(() => {
109
109
  URLS = {
110
110
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -3668,6 +3668,9 @@ var init_paths2 = __esm(() => {
3668
3668
  },
3669
3669
  get LOG_FILE() {
3670
3670
  return join3(this.DAEMON_DIR, "daemon.log");
3671
+ },
3672
+ get SESSIONS_FILE() {
3673
+ return join3(this.DAEMON_DIR, "sessions.json");
3671
3674
  }
3672
3675
  };
3673
3676
  });
@@ -4891,7 +4894,7 @@ async function runLaunch(flags, rawArgs) {
4891
4894
  messageMode
4892
4895
  };
4893
4896
  writeFileSync8(join6(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
4894
- `, "utf-8");
4897
+ `, { encoding: "utf-8", mode: 384 });
4895
4898
  const isResume = args.resume !== null || args.continueSession;
4896
4899
  let claudeSessionId;
4897
4900
  if (args.resume) {
@@ -8274,37 +8277,62 @@ async function runSend(flags, to, message) {
8274
8277
  }
8275
8278
  const priority = flags.priority === "now" ? "now" : flags.priority === "low" ? "low" : "next";
8276
8279
  const config = readConfig();
8277
- const meshSlug = flags.mesh ?? (config.meshes.length === 1 ? config.meshes[0].slug : null);
8278
- if (!to.startsWith("@") && !to.startsWith("#") && to !== "*" && /^[0-9a-f]{4,63}$/i.test(to)) {
8279
- try {
8280
- const { tryListPeersViaDaemon: tryListPeersViaDaemon2 } = await Promise.resolve().then(() => (init_daemon_route(), exports_daemon_route));
8281
- const peers = await tryListPeersViaDaemon2() ?? [];
8282
- const lower = to.toLowerCase();
8283
- const matches2 = peers.filter((p) => {
8284
- const pk = p.pubkey ?? "";
8285
- const mpk = p.memberPubkey ?? "";
8286
- return pk.toLowerCase().startsWith(lower) || mpk.toLowerCase().startsWith(lower);
8287
- });
8288
- if (matches2.length === 0) {
8289
- render.err(`No peer matches hex prefix "${to}".`);
8290
- const names = peers.map((p) => p.displayName).filter(Boolean).join(", ");
8291
- if (names)
8292
- render.hint(`online: ${names}`);
8293
- process.exit(1);
8294
- }
8295
- if (matches2.length > 1) {
8296
- const candidates = matches2.map((p) => {
8297
- const pk = p.pubkey ?? "";
8298
- const dn = p.displayName ?? "?";
8299
- return `${dn} ${pk.slice(0, 16)}…`;
8300
- }).join(", ");
8301
- render.err(`Ambiguous hex prefix "${to}" — matches ${matches2.length} peers.`);
8280
+ let meshSlug = flags.mesh ?? (config.meshes.length === 1 ? config.meshes[0].slug : null);
8281
+ const isDirect = !to.startsWith("@") && !to.startsWith("#") && to !== "*";
8282
+ const isFullPubkey = /^[0-9a-f]{64}$/i.test(to);
8283
+ const isPrefix = /^[0-9a-f]{4,63}$/i.test(to);
8284
+ const isName = isDirect && !isFullPubkey && !isPrefix;
8285
+ if (isDirect && (isPrefix || isName || isFullPubkey && !meshSlug)) {
8286
+ const { tryListPeersViaDaemon: tryListPeersViaDaemon2 } = await Promise.resolve().then(() => (init_daemon_route(), exports_daemon_route));
8287
+ const searchSlugs = meshSlug ? [meshSlug] : config.meshes.map((m) => m.slug);
8288
+ const lower = to.toLowerCase();
8289
+ let daemonReachable2 = false;
8290
+ const matches2 = [];
8291
+ for (const slug of searchSlugs) {
8292
+ const peers = await tryListPeersViaDaemon2(slug);
8293
+ if (peers === null)
8294
+ continue;
8295
+ daemonReachable2 = true;
8296
+ for (const p of peers) {
8297
+ const pk = (p.pubkey ?? "").toLowerCase();
8298
+ const mpk = (p.memberPubkey ?? "").toLowerCase();
8299
+ const dn = p.displayName ?? "?";
8300
+ const hit = isName ? dn.toLowerCase() === lower : pk.startsWith(lower) || mpk.startsWith(lower);
8301
+ if (hit)
8302
+ matches2.push({ slug, pubkey: p.pubkey ?? "", displayName: dn });
8303
+ }
8304
+ }
8305
+ if (daemonReachable2) {
8306
+ const byPubkey = new Map;
8307
+ for (const m of matches2)
8308
+ if (!byPubkey.has(m.pubkey))
8309
+ byPubkey.set(m.pubkey, m);
8310
+ const uniq = [...byPubkey.values()];
8311
+ const meshesHit = [...new Set(uniq.map((m) => m.slug))];
8312
+ if (uniq.length === 0) {
8313
+ if (!isFullPubkey) {
8314
+ render.err(`No peer matches "${to}"${flags.mesh ? ` on mesh "${flags.mesh}"` : " on any joined mesh"}.`);
8315
+ render.hint("Check `claudemesh peer list` (add --mesh <slug> to scope).");
8316
+ process.exit(1);
8317
+ }
8318
+ } else if (uniq.length > 1) {
8319
+ if (meshesHit.length > 1 && !meshSlug) {
8320
+ const where = uniq.map((m) => `${m.displayName} ${m.pubkey.slice(0, 12)}… @${m.slug}`).join(", ");
8321
+ render.err(`"${to}" matches peers on ${meshesHit.length} meshes — pick one with --mesh <slug>.`);
8322
+ render.hint(`candidates: ${where}`);
8323
+ process.exit(1);
8324
+ }
8325
+ const candidates = uniq.map((m) => `${m.displayName} ${m.pubkey.slice(0, 16)}…`).join(", ");
8326
+ render.err(`Ambiguous ${isName ? "name" : "prefix"} "${to}" — matches ${uniq.length} peers.`);
8302
8327
  render.hint(`candidates: ${candidates}`);
8303
8328
  render.hint("Use a longer prefix or paste the full 64-char pubkey.");
8304
8329
  process.exit(1);
8330
+ } else {
8331
+ meshSlug = uniq[0].slug;
8332
+ if (!isFullPubkey)
8333
+ to = uniq[0].pubkey;
8305
8334
  }
8306
- to = matches2[0].pubkey ?? to;
8307
- } catch {}
8335
+ }
8308
8336
  }
8309
8337
  if (meshSlug) {
8310
8338
  const joined = config.meshes.find((m) => m.slug === meshSlug);
@@ -8391,7 +8419,7 @@ async function runSend(flags, to, message) {
8391
8419
  process.exit(1);
8392
8420
  }
8393
8421
  }
8394
- await withMesh({ meshSlug: flags.mesh ?? null }, async (client) => {
8422
+ await withMesh({ meshSlug: meshSlug ?? flags.mesh ?? null }, async (client) => {
8395
8423
  let targetSpec = to;
8396
8424
  if (to.startsWith("#") && !/^#[0-9a-z_-]{20,}$/i.test(to)) {
8397
8425
  const name = to.slice(1);
@@ -9924,6 +9952,12 @@ function bindSseStream(res, bus, filter = {}) {
9924
9952
  }
9925
9953
 
9926
9954
  // src/daemon/process-info.ts
9955
+ var exports_process_info = {};
9956
+ __export(exports_process_info, {
9957
+ isPidAlive: () => isPidAlive,
9958
+ getProcessStartTimes: () => getProcessStartTimes,
9959
+ getProcessStartTime: () => getProcessStartTime
9960
+ });
9927
9961
  import { execFile as execFile2 } from "node:child_process";
9928
9962
  import { promisify } from "node:util";
9929
9963
  async function getProcessStartTime(pid) {
@@ -9979,6 +10013,37 @@ var init_process_info = __esm(() => {
9979
10013
  });
9980
10014
 
9981
10015
  // src/daemon/session-registry.ts
10016
+ import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync3, writeFileSync as writeFileSync11 } from "node:fs";
10017
+ import { dirname as dirname5 } from "node:path";
10018
+ import { randomBytes as randomBytes7 } from "node:crypto";
10019
+ function toPersisted(info) {
10020
+ const { presence: _presence, ...rest } = info;
10021
+ return rest;
10022
+ }
10023
+ function setRegistryPersistence(path) {
10024
+ persistPath = path;
10025
+ }
10026
+ function persist() {
10027
+ if (!persistPath)
10028
+ return;
10029
+ try {
10030
+ mkdirSync7(dirname5(persistPath), { recursive: true, mode: 448 });
10031
+ const rows = [...byToken.values()].map(toPersisted);
10032
+ const tmp = `${persistPath}.${randomBytes7(6).toString("hex")}.tmp`;
10033
+ writeFileSync11(tmp, JSON.stringify({ version: 1, sessions: rows }), { mode: 384 });
10034
+ renameSync3(tmp, persistPath);
10035
+ } catch {}
10036
+ }
10037
+ function readPersistedSessions(path) {
10038
+ try {
10039
+ if (!existsSync11(path))
10040
+ return [];
10041
+ const parsed = JSON.parse(readFileSync10(path, "utf8"));
10042
+ return Array.isArray(parsed.sessions) ? parsed.sessions : [];
10043
+ } catch {
10044
+ return [];
10045
+ }
10046
+ }
9982
10047
  function startReaper() {
9983
10048
  if (reaperHandle)
9984
10049
  return;
@@ -10004,6 +10069,7 @@ function registerSession(info) {
10004
10069
  const stored = { ...info, registeredAt: Date.now() };
10005
10070
  byToken.set(info.token, stored);
10006
10071
  bySessionId.set(info.sessionId, info.token);
10072
+ persist();
10007
10073
  try {
10008
10074
  hooks.onRegister?.(stored);
10009
10075
  } catch {}
@@ -10020,6 +10086,7 @@ async function captureStartTimeAsync(token, pid) {
10020
10086
  if (!entry || entry.pid !== pid)
10021
10087
  return;
10022
10088
  entry.startTime = lstart;
10089
+ persist();
10023
10090
  }
10024
10091
  function deregisterByToken(token) {
10025
10092
  const entry = byToken.get(token);
@@ -10028,6 +10095,7 @@ function deregisterByToken(token) {
10028
10095
  byToken.delete(token);
10029
10096
  if (bySessionId.get(entry.sessionId) === token)
10030
10097
  bySessionId.delete(entry.sessionId);
10098
+ persist();
10031
10099
  try {
10032
10100
  hooks.onDeregister?.(entry);
10033
10101
  } catch {}
@@ -10079,7 +10147,7 @@ async function reapDead() {
10079
10147
  for (const t of dead)
10080
10148
  deregisterByToken(t);
10081
10149
  }
10082
- var TTL_MS, REAPER_INTERVAL_MS, byToken, bySessionId, hooks, reaperHandle = null;
10150
+ var TTL_MS, REAPER_INTERVAL_MS, byToken, bySessionId, hooks, reaperHandle = null, persistPath = null;
10083
10151
  var init_session_registry = __esm(() => {
10084
10152
  init_process_info();
10085
10153
  TTL_MS = 24 * 60 * 60 * 1000;
@@ -10091,7 +10159,7 @@ var init_session_registry = __esm(() => {
10091
10159
 
10092
10160
  // src/daemon/ipc/server.ts
10093
10161
  import { createServer as createServer2 } from "node:http";
10094
- import { chmodSync as chmodSync3, existsSync as existsSync11, unlinkSync as unlinkSync4 } from "node:fs";
10162
+ import { chmodSync as chmodSync3, existsSync as existsSync12, unlinkSync as unlinkSync4 } from "node:fs";
10095
10163
  import { timingSafeEqual } from "node:crypto";
10096
10164
  import { randomUUID as randomUUID3 } from "node:crypto";
10097
10165
  function startIpcServer(opts) {
@@ -10107,7 +10175,7 @@ function startIpcServer(opts) {
10107
10175
  meshConfigs: opts.meshConfigs,
10108
10176
  onPendingInserted: opts.onPendingInserted
10109
10177
  });
10110
- if (existsSync11(DAEMON_PATHS.SOCK_FILE)) {
10178
+ if (existsSync12(DAEMON_PATHS.SOCK_FILE)) {
10111
10179
  try {
10112
10180
  unlinkSync4(DAEMON_PATHS.SOCK_FILE);
10113
10181
  } catch {}
@@ -10934,16 +11002,16 @@ function parseSendRequest(body, idempotencyHeader) {
10934
11002
  }
10935
11003
  async function resolveAndEncrypt(req, broker, meshSecretKey, meshSlug) {
10936
11004
  const { encryptDirect: encryptDirect2 } = await Promise.resolve().then(() => (init_box(), exports_box));
10937
- const { randomBytes: randomBytes7 } = await import("node:crypto");
11005
+ const { randomBytes: randomBytes8 } = await import("node:crypto");
10938
11006
  const to = req.to.trim();
10939
11007
  if (to.startsWith("#") && /^#[0-9a-z_-]{20,}$/i.test(to)) {
10940
11008
  const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
10941
- const nonce = randomBytes7(24).toString("base64");
11009
+ const nonce = randomBytes8(24).toString("base64");
10942
11010
  return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
10943
11011
  }
10944
11012
  if (to.startsWith("@") || to === "*") {
10945
11013
  const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
10946
- const nonce = randomBytes7(24).toString("base64");
11014
+ const nonce = randomBytes8(24).toString("base64");
10947
11015
  return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
10948
11016
  }
10949
11017
  if (/^[0-9a-f]{64}$/i.test(to)) {
@@ -11964,8 +12032,8 @@ function bufferToHex(b) {
11964
12032
  return s;
11965
12033
  }
11966
12034
  async function randomNonce2() {
11967
- const { randomBytes: randomBytes7 } = await import("node:crypto");
11968
- return randomBytes7(24).toString("base64");
12035
+ const { randomBytes: randomBytes8 } = await import("node:crypto");
12036
+ return randomBytes8(24).toString("base64");
11969
12037
  }
11970
12038
  function defaultLog4(level, msg, meta) {
11971
12039
  const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
@@ -12140,7 +12208,7 @@ __export(exports_identity, {
12140
12208
  __resetHostIdCacheForTests: () => __resetHostIdCacheForTests,
12141
12209
  __computeV1FingerprintForTests: () => __computeV1FingerprintForTests
12142
12210
  });
12143
- import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "node:fs";
12211
+ import { existsSync as existsSync13, readFileSync as readFileSync11, writeFileSync as writeFileSync12 } from "node:fs";
12144
12212
  import { join as join8 } from "node:path";
12145
12213
  import { createHash as createHash2 } from "node:crypto";
12146
12214
  import { execFileSync } from "node:child_process";
@@ -12161,13 +12229,13 @@ function computeCurrentFingerprint() {
12161
12229
  }
12162
12230
  function checkFingerprint() {
12163
12231
  const current = computeCurrentFingerprint();
12164
- if (!existsSync12(path())) {
12165
- writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12232
+ if (!existsSync13(path())) {
12233
+ writeFileSync12(path(), JSON.stringify(current, null, 2), { mode: 384 });
12166
12234
  return { result: "first_run", current };
12167
12235
  }
12168
12236
  let stored;
12169
12237
  try {
12170
- stored = JSON.parse(readFileSync10(path(), "utf8"));
12238
+ stored = JSON.parse(readFileSync11(path(), "utf8"));
12171
12239
  } catch {
12172
12240
  return { result: "unavailable", current };
12173
12241
  }
@@ -12175,7 +12243,7 @@ function checkFingerprint() {
12175
12243
  if (stored.fingerprint === current.fingerprint)
12176
12244
  return { result: "match", current, stored };
12177
12245
  if (stored.host_id && stored.host_id === current.host_id) {
12178
- writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12246
+ writeFileSync12(path(), JSON.stringify(current, null, 2), { mode: 384 });
12179
12247
  return { result: "match", current, stored };
12180
12248
  }
12181
12249
  return { result: "mismatch", current, stored };
@@ -12183,7 +12251,7 @@ function checkFingerprint() {
12183
12251
  if (stored.schema_version === 1) {
12184
12252
  const v1 = computeCurrentFingerprintV1();
12185
12253
  if (stored.fingerprint === v1.fingerprint) {
12186
- writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12254
+ writeFileSync12(path(), JSON.stringify(current, null, 2), { mode: 384 });
12187
12255
  return { result: "match", current, stored };
12188
12256
  }
12189
12257
  return { result: "mismatch", current, stored };
@@ -12192,7 +12260,7 @@ function checkFingerprint() {
12192
12260
  }
12193
12261
  function acceptCurrentHost() {
12194
12262
  const current = computeCurrentFingerprint();
12195
- writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12263
+ writeFileSync12(path(), JSON.stringify(current, null, 2), { mode: 384 });
12196
12264
  return current;
12197
12265
  }
12198
12266
  function fingerprintV2(host_id, stable_mac) {
@@ -12242,7 +12310,7 @@ function readHostIdV1() {
12242
12310
  if (process.platform === "linux") {
12243
12311
  for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
12244
12312
  try {
12245
- const raw = readFileSync10(p, "utf8").trim();
12313
+ const raw = readFileSync11(p, "utf8").trim();
12246
12314
  if (raw)
12247
12315
  return `linux:${raw}`;
12248
12316
  } catch {}
@@ -12288,7 +12356,7 @@ function readHostIdV2Uncached() {
12288
12356
  if (process.platform === "linux") {
12289
12357
  for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
12290
12358
  try {
12291
- const raw = readFileSync10(p, "utf8").trim();
12359
+ const raw = readFileSync11(p, "utf8").trim();
12292
12360
  if (raw)
12293
12361
  return `linux:${raw}`;
12294
12362
  } catch {}
@@ -12331,23 +12399,23 @@ var init_identity = __esm(() => {
12331
12399
  });
12332
12400
 
12333
12401
  // src/daemon/run.ts
12334
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync11 } from "node:fs";
12402
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, readFileSync as readFileSync12 } from "node:fs";
12335
12403
  function detectContainer() {
12336
12404
  if (process.env.KUBERNETES_SERVICE_HOST)
12337
12405
  return true;
12338
12406
  if (process.env.CONTAINER === "1")
12339
12407
  return true;
12340
12408
  try {
12341
- if (existsSync13("/.dockerenv"))
12409
+ if (existsSync14("/.dockerenv"))
12342
12410
  return true;
12343
- const cg = readFileSync11("/proc/1/cgroup", "utf8");
12411
+ const cg = readFileSync12("/proc/1/cgroup", "utf8");
12344
12412
  if (/(docker|kubepods|containerd)/.test(cg))
12345
12413
  return true;
12346
12414
  } catch {}
12347
12415
  return false;
12348
12416
  }
12349
12417
  async function runDaemon(opts = {}) {
12350
- mkdirSync7(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12418
+ mkdirSync8(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12351
12419
  const lock = acquireSingletonLock();
12352
12420
  if (lock.result === "already-running") {
12353
12421
  process.stderr.write(`daemon already running (pid ${lock.pid})
@@ -12549,6 +12617,85 @@ async function runDaemon(opts = {}) {
12549
12617
  }
12550
12618
  });
12551
12619
  startReaper();
12620
+ try {
12621
+ const persisted = readPersistedSessions(DAEMON_PATHS.SESSIONS_FILE);
12622
+ if (persisted.length > 0) {
12623
+ const { loadOrCreateSessionKeypair: loadOrCreateSessionKeypair2 } = await Promise.resolve().then(() => (init_keypair_store(), exports_keypair_store));
12624
+ const { signParentAttestation: signParentAttestation2 } = await Promise.resolve().then(() => (init_session_hello_sig(), exports_session_hello_sig));
12625
+ const { isPidAlive: isPidAlive2, getProcessStartTimes: getProcessStartTimes2 } = await Promise.resolve().then(() => (init_process_info(), exports_process_info));
12626
+ const liveStartTimes = await getProcessStartTimes2(persisted.map((p) => p.pid)).catch(() => new Map);
12627
+ let revived = 0;
12628
+ for (const s of persisted) {
12629
+ if (!isPidAlive2(s.pid))
12630
+ continue;
12631
+ if (s.startTime !== undefined) {
12632
+ const live = liveStartTimes.get(s.pid);
12633
+ if (live !== undefined && live !== s.startTime)
12634
+ continue;
12635
+ }
12636
+ const meshConfig = meshConfigs.get(s.mesh);
12637
+ if (!meshConfig)
12638
+ continue;
12639
+ try {
12640
+ const kp = await loadOrCreateSessionKeypair2(meshConfig.slug, s.sessionId);
12641
+ const att = await signParentAttestation2({
12642
+ parentMemberPubkey: meshConfig.pubkey,
12643
+ parentSecretKey: meshConfig.secretKey,
12644
+ sessionPubkey: kp.publicKey
12645
+ });
12646
+ registerSession({
12647
+ token: s.token,
12648
+ sessionId: s.sessionId,
12649
+ mesh: s.mesh,
12650
+ displayName: s.displayName,
12651
+ pid: s.pid,
12652
+ ...s.cwd ? { cwd: s.cwd } : {},
12653
+ ...s.role ? { role: s.role } : {},
12654
+ ...s.groups ? { groups: s.groups } : {},
12655
+ ...s.startTime ? { startTime: s.startTime } : {},
12656
+ presence: {
12657
+ sessionPubkey: kp.publicKey,
12658
+ sessionSecretKey: kp.secretKey,
12659
+ parentAttestation: {
12660
+ sessionPubkey: att.sessionPubkey,
12661
+ parentMemberPubkey: att.parentMemberPubkey,
12662
+ expiresAt: att.expiresAt,
12663
+ signature: att.signature
12664
+ }
12665
+ }
12666
+ });
12667
+ revived++;
12668
+ } catch (err) {
12669
+ process.stderr.write(JSON.stringify({
12670
+ level: "warn",
12671
+ msg: "session_rehydrate_failed",
12672
+ token: s.token.slice(0, 8),
12673
+ mesh: s.mesh,
12674
+ err: String(err),
12675
+ ts: new Date().toISOString()
12676
+ }) + `
12677
+ `);
12678
+ }
12679
+ }
12680
+ process.stderr.write(JSON.stringify({
12681
+ level: "info",
12682
+ msg: "sessions_rehydrated",
12683
+ revived,
12684
+ persisted: persisted.length,
12685
+ ts: new Date().toISOString()
12686
+ }) + `
12687
+ `);
12688
+ }
12689
+ } catch (err) {
12690
+ process.stderr.write(JSON.stringify({
12691
+ level: "warn",
12692
+ msg: "session_rehydrate_scan_failed",
12693
+ err: String(err),
12694
+ ts: new Date().toISOString()
12695
+ }) + `
12696
+ `);
12697
+ }
12698
+ setRegistryPersistence(DAEMON_PATHS.SESSIONS_FILE);
12552
12699
  const ipc2 = startIpcServer({
12553
12700
  localToken,
12554
12701
  tcpEnabled,
@@ -12637,10 +12784,10 @@ __export(exports_service_install, {
12637
12784
  installService: () => installService,
12638
12785
  detectPlatform: () => detectPlatform
12639
12786
  });
12640
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, writeFileSync as writeFileSync12, unlinkSync as unlinkSync5, readFileSync as readFileSync12 } from "node:fs";
12787
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, writeFileSync as writeFileSync13, unlinkSync as unlinkSync5, readFileSync as readFileSync13 } from "node:fs";
12641
12788
  import { execSync as execSync2 } from "node:child_process";
12642
12789
  import { homedir as homedir8 } from "node:os";
12643
- import { join as join9, dirname as dirname5 } from "node:path";
12790
+ import { join as join9, dirname as dirname6 } from "node:path";
12644
12791
  function detectPlatform() {
12645
12792
  if (process.platform === "darwin")
12646
12793
  return "darwin";
@@ -12658,10 +12805,10 @@ function installService(args) {
12658
12805
  if (isCi() && !args.allowCi) {
12659
12806
  throw new Error("Refusing to install persistent service in CI; pass --allow-ci-persistent to override.");
12660
12807
  }
12661
- if (!existsSync14(args.binaryPath)) {
12808
+ if (!existsSync15(args.binaryPath)) {
12662
12809
  throw new Error(`binary not found at ${args.binaryPath}`);
12663
12810
  }
12664
- mkdirSync8(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12811
+ mkdirSync9(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12665
12812
  if (platform5 === "darwin")
12666
12813
  return installDarwin(args);
12667
12814
  return installLinux(args);
@@ -12674,7 +12821,7 @@ function uninstallService() {
12674
12821
  try {
12675
12822
  execSync2(`launchctl bootout gui/$(id -u)/${SERVICE_LABEL2}`, { stdio: "ignore" });
12676
12823
  } catch {}
12677
- if (existsSync14(p)) {
12824
+ if (existsSync15(p)) {
12678
12825
  unlinkSync5(p);
12679
12826
  removed.push(p);
12680
12827
  }
@@ -12683,7 +12830,7 @@ function uninstallService() {
12683
12830
  try {
12684
12831
  execSync2(`systemctl --user disable --now ${SYSTEMD_UNIT2}`, { stdio: "ignore" });
12685
12832
  } catch {}
12686
- if (existsSync14(p)) {
12833
+ if (existsSync15(p)) {
12687
12834
  unlinkSync5(p);
12688
12835
  removed.push(p);
12689
12836
  }
@@ -12695,7 +12842,7 @@ function darwinPlistPath() {
12695
12842
  }
12696
12843
  function installDarwin(args) {
12697
12844
  const plist = darwinPlistPath();
12698
- mkdirSync8(dirname5(plist), { recursive: true });
12845
+ mkdirSync9(dirname6(plist), { recursive: true });
12699
12846
  const log2 = DAEMON_PATHS.LOG_FILE;
12700
12847
  const nodeBin = process.execPath;
12701
12848
  const meshArgs = [
@@ -12738,14 +12885,14 @@ function installDarwin(args) {
12738
12885
  </dict>
12739
12886
  </plist>
12740
12887
  `;
12741
- writeFileSync12(plist, xml, { mode: 420 });
12888
+ writeFileSync13(plist, xml, { mode: 420 });
12742
12889
  try {
12743
12890
  execSync2(`launchctl bootout gui/$(id -u)/${SERVICE_LABEL2}`, { stdio: "ignore" });
12744
12891
  } catch {}
12745
12892
  try {
12746
12893
  const pidPath = DAEMON_PATHS.PID_FILE;
12747
- if (existsSync14(pidPath)) {
12748
- const pid = parseInt(readFileSync12(pidPath, "utf8").trim(), 10);
12894
+ if (existsSync15(pidPath)) {
12895
+ const pid = parseInt(readFileSync13(pidPath, "utf8").trim(), 10);
12749
12896
  if (Number.isFinite(pid) && pid > 0) {
12750
12897
  try {
12751
12898
  process.kill(pid, "SIGTERM");
@@ -12764,7 +12911,7 @@ function linuxUnitPath() {
12764
12911
  }
12765
12912
  function installLinux(args) {
12766
12913
  const unit = linuxUnitPath();
12767
- mkdirSync8(dirname5(unit), { recursive: true });
12914
+ mkdirSync9(dirname6(unit), { recursive: true });
12768
12915
  const nodeBin = process.execPath;
12769
12916
  const execArgs = [
12770
12917
  "daemon",
@@ -12790,14 +12937,14 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin
12790
12937
  [Install]
12791
12938
  WantedBy=default.target
12792
12939
  `;
12793
- writeFileSync12(unit, content, { mode: 420 });
12940
+ writeFileSync13(unit, content, { mode: 420 });
12794
12941
  try {
12795
12942
  execSync2(`systemctl --user stop ${SYSTEMD_UNIT2}`, { stdio: "ignore" });
12796
12943
  } catch {}
12797
12944
  try {
12798
12945
  const pidPath = DAEMON_PATHS.PID_FILE;
12799
- if (existsSync14(pidPath)) {
12800
- const pid = parseInt(readFileSync12(pidPath, "utf8").trim(), 10);
12946
+ if (existsSync15(pidPath)) {
12947
+ const pid = parseInt(readFileSync13(pidPath, "utf8").trim(), 10);
12801
12948
  if (Number.isFinite(pid) && pid > 0) {
12802
12949
  try {
12803
12950
  process.kill(pid, "SIGTERM");
@@ -12824,10 +12971,10 @@ function readInstalledUnit() {
12824
12971
  if (!platform5)
12825
12972
  return { platform: null, path: null, content: null };
12826
12973
  const path2 = platform5 === "darwin" ? darwinPlistPath() : linuxUnitPath();
12827
- if (!existsSync14(path2))
12974
+ if (!existsSync15(path2))
12828
12975
  return { platform: platform5, path: null, content: null };
12829
12976
  try {
12830
- return { platform: platform5, path: path2, content: readFileSync12(path2, "utf8") };
12977
+ return { platform: platform5, path: path2, content: readFileSync13(path2, "utf8") };
12831
12978
  } catch {
12832
12979
  return { platform: platform5, path: path2, content: null };
12833
12980
  }
@@ -12843,7 +12990,7 @@ __export(exports_daemon, {
12843
12990
  runDaemonCommand: () => runDaemonCommand
12844
12991
  });
12845
12992
  import { spawn } from "node:child_process";
12846
- import { existsSync as existsSync15, openSync as openSync3, mkdirSync as mkdirSync9 } from "node:fs";
12993
+ import { existsSync as existsSync16, openSync as openSync3, mkdirSync as mkdirSync10 } from "node:fs";
12847
12994
  import { join as join10 } from "node:path";
12848
12995
  async function runDaemonCommand(sub, opts, rest = []) {
12849
12996
  switch (sub) {
@@ -13166,7 +13313,7 @@ async function runStop(opts) {
13166
13313
  return 1;
13167
13314
  }
13168
13315
  async function spawnDetachedDaemon(opts) {
13169
- mkdirSync9(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
13316
+ mkdirSync10(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
13170
13317
  const logPath = join10(DAEMON_PATHS.DAEMON_DIR, "daemon.log");
13171
13318
  const binary = process.argv[1] ?? "claudemesh";
13172
13319
  const args = ["daemon", "up", "--foreground"];
@@ -13185,7 +13332,7 @@ async function spawnDetachedDaemon(opts) {
13185
13332
  const sockPath = DAEMON_PATHS.SOCK_FILE;
13186
13333
  const startedAt = Date.now();
13187
13334
  while (Date.now() - startedAt < 3000) {
13188
- if (existsSync15(sockPath)) {
13335
+ if (existsSync16(sockPath)) {
13189
13336
  if (opts.json) {
13190
13337
  process.stdout.write(JSON.stringify({ ok: true, detached: true, pid: child.pid, log: logPath }) + `
13191
13338
  `);
@@ -13230,19 +13377,19 @@ __export(exports_install, {
13230
13377
  import {
13231
13378
  chmodSync as chmodSync4,
13232
13379
  copyFileSync,
13233
- existsSync as existsSync16,
13234
- mkdirSync as mkdirSync10,
13235
- readFileSync as readFileSync13,
13236
- writeFileSync as writeFileSync13
13380
+ existsSync as existsSync17,
13381
+ mkdirSync as mkdirSync11,
13382
+ readFileSync as readFileSync14,
13383
+ writeFileSync as writeFileSync14
13237
13384
  } from "node:fs";
13238
13385
  import { homedir as homedir9, platform as platform5 } from "node:os";
13239
- import { dirname as dirname6, join as join11, resolve } from "node:path";
13386
+ import { dirname as dirname7, join as join11, resolve } from "node:path";
13240
13387
  import { fileURLToPath } from "node:url";
13241
13388
  import { spawnSync as spawnSync3 } from "node:child_process";
13242
13389
  function readClaudeConfig() {
13243
- if (!existsSync16(CLAUDE_CONFIG))
13390
+ if (!existsSync17(CLAUDE_CONFIG))
13244
13391
  return {};
13245
- const text = readFileSync13(CLAUDE_CONFIG, "utf-8").trim();
13392
+ const text = readFileSync14(CLAUDE_CONFIG, "utf-8").trim();
13246
13393
  if (!text)
13247
13394
  return {};
13248
13395
  try {
@@ -13252,10 +13399,10 @@ function readClaudeConfig() {
13252
13399
  }
13253
13400
  }
13254
13401
  function backupClaudeConfig() {
13255
- if (!existsSync16(CLAUDE_CONFIG))
13402
+ if (!existsSync17(CLAUDE_CONFIG))
13256
13403
  return;
13257
- const backupDir = join11(dirname6(CLAUDE_CONFIG), ".claude", "backups");
13258
- mkdirSync10(backupDir, { recursive: true });
13404
+ const backupDir = join11(dirname7(CLAUDE_CONFIG), ".claude", "backups");
13405
+ mkdirSync11(backupDir, { recursive: true });
13259
13406
  const ts = Date.now();
13260
13407
  const dest = join11(backupDir, `.claude.json.pre-claudemesh.${ts}`);
13261
13408
  copyFileSync(CLAUDE_CONFIG, dest);
@@ -13281,7 +13428,7 @@ function patchMcpServer(entry) {
13281
13428
  return action;
13282
13429
  }
13283
13430
  function removeMcpServer() {
13284
- if (!existsSync16(CLAUDE_CONFIG))
13431
+ if (!existsSync17(CLAUDE_CONFIG))
13285
13432
  return false;
13286
13433
  backupClaudeConfig();
13287
13434
  const cfg = readClaudeConfig();
@@ -13294,8 +13441,8 @@ function removeMcpServer() {
13294
13441
  return true;
13295
13442
  }
13296
13443
  function flushClaudeConfig(obj) {
13297
- mkdirSync10(dirname6(CLAUDE_CONFIG), { recursive: true });
13298
- writeFileSync13(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
13444
+ mkdirSync11(dirname7(CLAUDE_CONFIG), { recursive: true });
13445
+ writeFileSync14(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
13299
13446
  `, "utf-8");
13300
13447
  try {
13301
13448
  chmodSync4(CLAUDE_CONFIG, 384);
@@ -13312,13 +13459,13 @@ function resolveEntry() {
13312
13459
  const here = fileURLToPath(import.meta.url);
13313
13460
  if (isBundledFile(here))
13314
13461
  return here;
13315
- return resolve(dirname6(here), "..", "index.ts");
13462
+ return resolve(dirname7(here), "..", "index.ts");
13316
13463
  }
13317
13464
  function resolveBundledSkillsDir() {
13318
13465
  const here = fileURLToPath(import.meta.url);
13319
- const pkgRoot = resolve(dirname6(here), "..", "..");
13466
+ const pkgRoot = resolve(dirname7(here), "..", "..");
13320
13467
  const skillsDir = join11(pkgRoot, "skills");
13321
- if (existsSync16(skillsDir))
13468
+ if (existsSync17(skillsDir))
13322
13469
  return skillsDir;
13323
13470
  return null;
13324
13471
  }
@@ -13333,7 +13480,7 @@ function installSkills() {
13333
13480
  continue;
13334
13481
  const srcDir = join11(src, entry.name);
13335
13482
  const dstDir = join11(CLAUDE_SKILLS_ROOT, entry.name);
13336
- mkdirSync10(dstDir, { recursive: true });
13483
+ mkdirSync11(dstDir, { recursive: true });
13337
13484
  for (const file of fs.readdirSync(srcDir, { withFileTypes: true })) {
13338
13485
  if (!file.isFile())
13339
13486
  continue;
@@ -13353,7 +13500,7 @@ function uninstallSkills() {
13353
13500
  if (!entry.isDirectory())
13354
13501
  continue;
13355
13502
  const dstDir = join11(CLAUDE_SKILLS_ROOT, entry.name);
13356
- if (existsSync16(dstDir)) {
13503
+ if (existsSync17(dstDir)) {
13357
13504
  try {
13358
13505
  fs.rmSync(dstDir, { recursive: true, force: true });
13359
13506
  removed.push(entry.name);
@@ -13378,9 +13525,9 @@ function entriesEqual(a, b) {
13378
13525
  return a.command === b.command && JSON.stringify(a.args ?? []) === JSON.stringify(b.args ?? []);
13379
13526
  }
13380
13527
  function readClaudeSettings() {
13381
- if (!existsSync16(CLAUDE_SETTINGS))
13528
+ if (!existsSync17(CLAUDE_SETTINGS))
13382
13529
  return {};
13383
- const text = readFileSync13(CLAUDE_SETTINGS, "utf-8").trim();
13530
+ const text = readFileSync14(CLAUDE_SETTINGS, "utf-8").trim();
13384
13531
  if (!text)
13385
13532
  return {};
13386
13533
  try {
@@ -13390,8 +13537,8 @@ function readClaudeSettings() {
13390
13537
  }
13391
13538
  }
13392
13539
  function writeClaudeSettings(obj) {
13393
- mkdirSync10(dirname6(CLAUDE_SETTINGS), { recursive: true });
13394
- writeFileSync13(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
13540
+ mkdirSync11(dirname7(CLAUDE_SETTINGS), { recursive: true });
13541
+ writeFileSync14(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
13395
13542
  `, "utf-8");
13396
13543
  }
13397
13544
  function installAllowedTools() {
@@ -13405,7 +13552,7 @@ function installAllowedTools() {
13405
13552
  return { added: toAdd, unchanged: CLAUDEMESH_TOOLS.length - toAdd.length };
13406
13553
  }
13407
13554
  function uninstallAllowedTools() {
13408
- if (!existsSync16(CLAUDE_SETTINGS))
13555
+ if (!existsSync17(CLAUDE_SETTINGS))
13409
13556
  return 0;
13410
13557
  const settings = readClaudeSettings();
13411
13558
  const existing = settings.allowedTools ?? [];
@@ -13440,7 +13587,7 @@ function installHooks() {
13440
13587
  return { added, unchanged };
13441
13588
  }
13442
13589
  function uninstallHooks() {
13443
- if (!existsSync16(CLAUDE_SETTINGS))
13590
+ if (!existsSync17(CLAUDE_SETTINGS))
13444
13591
  return 0;
13445
13592
  const settings = readClaudeSettings();
13446
13593
  const hooks2 = settings.hooks;
@@ -13490,7 +13637,7 @@ async function runInstall(args = []) {
13490
13637
  render.err("`bun` is not on PATH.", "Install Bun first: https://bun.com");
13491
13638
  process.exit(1);
13492
13639
  }
13493
- if (!existsSync16(entry)) {
13640
+ if (!existsSync17(entry)) {
13494
13641
  render.err(`MCP entry not found at ${entry}`);
13495
13642
  process.exit(1);
13496
13643
  }
@@ -13761,35 +13908,35 @@ var exports_uninstall = {};
13761
13908
  __export(exports_uninstall, {
13762
13909
  uninstall: () => uninstall
13763
13910
  });
13764
- import { readFileSync as readFileSync14, writeFileSync as writeFileSync14, existsSync as existsSync17, rmSync as rmSync3, readdirSync as readdirSync2 } from "node:fs";
13765
- import { join as join12, dirname as dirname7 } from "node:path";
13911
+ import { readFileSync as readFileSync15, writeFileSync as writeFileSync15, existsSync as existsSync18, rmSync as rmSync3, readdirSync as readdirSync2 } from "node:fs";
13912
+ import { join as join12, dirname as dirname8 } from "node:path";
13766
13913
  import { homedir as homedir10 } from "node:os";
13767
13914
  import { fileURLToPath as fileURLToPath2 } from "node:url";
13768
13915
  function bundledSkillsDir() {
13769
13916
  const here = fileURLToPath2(import.meta.url);
13770
- const pkgRoot = join12(dirname7(here), "..", "..");
13917
+ const pkgRoot = join12(dirname8(here), "..", "..");
13771
13918
  const skillsDir = join12(pkgRoot, "skills");
13772
- return existsSync17(skillsDir) ? skillsDir : null;
13919
+ return existsSync18(skillsDir) ? skillsDir : null;
13773
13920
  }
13774
13921
  async function uninstall() {
13775
13922
  let removed = 0;
13776
- if (existsSync17(PATHS.CLAUDE_JSON)) {
13923
+ if (existsSync18(PATHS.CLAUDE_JSON)) {
13777
13924
  try {
13778
- const raw = readFileSync14(PATHS.CLAUDE_JSON, "utf-8");
13925
+ const raw = readFileSync15(PATHS.CLAUDE_JSON, "utf-8");
13779
13926
  const config = JSON.parse(raw);
13780
13927
  const servers = config.mcpServers;
13781
13928
  if (servers && "claudemesh" in servers) {
13782
13929
  delete servers.claudemesh;
13783
- writeFileSync14(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
13930
+ writeFileSync15(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
13784
13931
  `, "utf-8");
13785
13932
  render.ok("removed MCP server", dim("~/.claude.json"));
13786
13933
  removed++;
13787
13934
  }
13788
13935
  } catch {}
13789
13936
  }
13790
- if (existsSync17(PATHS.CLAUDE_SETTINGS)) {
13937
+ if (existsSync18(PATHS.CLAUDE_SETTINGS)) {
13791
13938
  try {
13792
- const raw = readFileSync14(PATHS.CLAUDE_SETTINGS, "utf-8");
13939
+ const raw = readFileSync15(PATHS.CLAUDE_SETTINGS, "utf-8");
13793
13940
  const config = JSON.parse(raw);
13794
13941
  const hooks2 = config.hooks;
13795
13942
  if (hooks2) {
@@ -13810,7 +13957,7 @@ async function uninstall() {
13810
13957
  }
13811
13958
  }
13812
13959
  if (removedHooks > 0) {
13813
- writeFileSync14(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
13960
+ writeFileSync15(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
13814
13961
  `, "utf-8");
13815
13962
  render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
13816
13963
  removed++;
@@ -13826,7 +13973,7 @@ async function uninstall() {
13826
13973
  if (!entry.isDirectory())
13827
13974
  continue;
13828
13975
  const dst = join12(CLAUDE_SKILLS_ROOT2, entry.name);
13829
- if (existsSync17(dst)) {
13976
+ if (existsSync18(dst)) {
13830
13977
  try {
13831
13978
  rmSync3(dst, { recursive: true, force: true });
13832
13979
  removedSkills.push(entry.name);
@@ -13858,7 +14005,7 @@ var exports_doctor = {};
13858
14005
  __export(exports_doctor, {
13859
14006
  runDoctor: () => runDoctor
13860
14007
  });
13861
- import { existsSync as existsSync18, readFileSync as readFileSync15, statSync as statSync3 } from "node:fs";
14008
+ import { existsSync as existsSync19, readFileSync as readFileSync16, statSync as statSync3 } from "node:fs";
13862
14009
  import { homedir as homedir11, platform as platform6 } from "node:os";
13863
14010
  import { join as join13 } from "node:path";
13864
14011
  import { spawnSync as spawnSync4 } from "node:child_process";
@@ -13885,7 +14032,7 @@ function checkClaudeOnPath() {
13885
14032
  }
13886
14033
  function checkMcpRegistered() {
13887
14034
  const claudeConfig = join13(homedir11(), ".claude.json");
13888
- if (!existsSync18(claudeConfig)) {
14035
+ if (!existsSync19(claudeConfig)) {
13889
14036
  return {
13890
14037
  name: "claudemesh MCP registered in ~/.claude.json",
13891
14038
  pass: false,
@@ -13893,7 +14040,7 @@ function checkMcpRegistered() {
13893
14040
  };
13894
14041
  }
13895
14042
  try {
13896
- const cfg = JSON.parse(readFileSync15(claudeConfig, "utf-8"));
14043
+ const cfg = JSON.parse(readFileSync16(claudeConfig, "utf-8"));
13897
14044
  const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
13898
14045
  return {
13899
14046
  name: "claudemesh MCP registered in ~/.claude.json",
@@ -13911,7 +14058,7 @@ function checkMcpRegistered() {
13911
14058
  }
13912
14059
  function checkHooksRegistered() {
13913
14060
  const settings = join13(homedir11(), ".claude", "settings.json");
13914
- if (!existsSync18(settings)) {
14061
+ if (!existsSync19(settings)) {
13915
14062
  return {
13916
14063
  name: "Status hooks registered in ~/.claude/settings.json",
13917
14064
  pass: false,
@@ -13919,7 +14066,7 @@ function checkHooksRegistered() {
13919
14066
  };
13920
14067
  }
13921
14068
  try {
13922
- const raw = readFileSync15(settings, "utf-8");
14069
+ const raw = readFileSync16(settings, "utf-8");
13923
14070
  const has = raw.includes("claudemesh hook ");
13924
14071
  return {
13925
14072
  name: "Status hooks registered in ~/.claude/settings.json",
@@ -13936,7 +14083,7 @@ function checkHooksRegistered() {
13936
14083
  }
13937
14084
  function checkConfigFile() {
13938
14085
  const path2 = getConfigPath();
13939
- if (!existsSync18(path2)) {
14086
+ if (!existsSync19(path2)) {
13940
14087
  return {
13941
14088
  name: "~/.claudemesh/config.json exists and parses",
13942
14089
  pass: true,
@@ -14119,7 +14266,7 @@ var exports_status = {};
14119
14266
  __export(exports_status, {
14120
14267
  runStatus: () => runStatus2
14121
14268
  });
14122
- import { statSync as statSync4, existsSync as existsSync19 } from "node:fs";
14269
+ import { statSync as statSync4, existsSync as existsSync20 } from "node:fs";
14123
14270
  import WebSocket3 from "ws";
14124
14271
  async function probeBroker(url, timeoutMs = 4000) {
14125
14272
  return new Promise((resolve2) => {
@@ -14149,7 +14296,7 @@ async function runStatus2() {
14149
14296
  render.section(`status (v${VERSION})`);
14150
14297
  const configPath = getConfigPath();
14151
14298
  let configPermsNote = "missing";
14152
- if (existsSync19(configPath)) {
14299
+ if (existsSync20(configPath)) {
14153
14300
  const mode = (statSync4(configPath).mode & 511).toString(8).padStart(4, "0");
14154
14301
  configPermsNote = mode === "0600" ? `${mode}` : `${mode} — expected 0600`;
14155
14302
  }
@@ -14295,13 +14442,13 @@ var init_check_claude_binary = __esm(() => {
14295
14442
  });
14296
14443
 
14297
14444
  // src/services/health/check-mcp-registered.ts
14298
- import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
14445
+ import { existsSync as existsSync21, readFileSync as readFileSync17 } from "node:fs";
14299
14446
  function checkMcpRegistered2() {
14300
14447
  try {
14301
- if (!existsSync20(PATHS.CLAUDE_JSON)) {
14448
+ if (!existsSync21(PATHS.CLAUDE_JSON)) {
14302
14449
  return { name: "mcp-registered", ok: false, message: "~/.claude.json not found" };
14303
14450
  }
14304
- const raw = readFileSync16(PATHS.CLAUDE_JSON, "utf-8");
14451
+ const raw = readFileSync17(PATHS.CLAUDE_JSON, "utf-8");
14305
14452
  const config = JSON.parse(raw);
14306
14453
  if (config.mcpServers && "claudemesh" in config.mcpServers) {
14307
14454
  return { name: "mcp-registered", ok: true, message: "MCP server registered" };
@@ -14316,13 +14463,13 @@ var init_check_mcp_registered = __esm(() => {
14316
14463
  });
14317
14464
 
14318
14465
  // src/services/health/check-hooks-registered.ts
14319
- import { existsSync as existsSync21, readFileSync as readFileSync17 } from "node:fs";
14466
+ import { existsSync as existsSync22, readFileSync as readFileSync18 } from "node:fs";
14320
14467
  function checkHooksRegistered2() {
14321
14468
  try {
14322
- if (!existsSync21(PATHS.CLAUDE_SETTINGS)) {
14469
+ if (!existsSync22(PATHS.CLAUDE_SETTINGS)) {
14323
14470
  return { name: "hooks-registered", ok: false, message: "~/.claude/settings.json not found" };
14324
14471
  }
14325
- const raw = readFileSync17(PATHS.CLAUDE_SETTINGS, "utf-8");
14472
+ const raw = readFileSync18(PATHS.CLAUDE_SETTINGS, "utf-8");
14326
14473
  const config = JSON.parse(raw);
14327
14474
  if (config.hooks) {
14328
14475
  return { name: "hooks-registered", ok: true, message: "Hooks configured" };
@@ -14337,10 +14484,10 @@ var init_check_hooks_registered = __esm(() => {
14337
14484
  });
14338
14485
 
14339
14486
  // src/services/health/check-config-perms.ts
14340
- import { existsSync as existsSync22, statSync as statSync5 } from "node:fs";
14487
+ import { existsSync as existsSync23, statSync as statSync5 } from "node:fs";
14341
14488
  function checkConfigPerms() {
14342
14489
  const configFile = PATHS.CONFIG_FILE;
14343
- if (!existsSync22(configFile)) {
14490
+ if (!existsSync23(configFile)) {
14344
14491
  return { name: "config-perms", ok: true, message: "No config file yet (first run)" };
14345
14492
  }
14346
14493
  try {
@@ -14358,13 +14505,13 @@ var init_check_config_perms = __esm(() => {
14358
14505
  });
14359
14506
 
14360
14507
  // src/services/health/check-keypairs-valid.ts
14361
- import { existsSync as existsSync23, readFileSync as readFileSync18 } from "node:fs";
14508
+ import { existsSync as existsSync24, readFileSync as readFileSync19 } from "node:fs";
14362
14509
  function checkKeypairsValid() {
14363
- if (!existsSync23(PATHS.CONFIG_FILE)) {
14510
+ if (!existsSync24(PATHS.CONFIG_FILE)) {
14364
14511
  return { name: "keypairs-valid", ok: true, message: "No config (first run)" };
14365
14512
  }
14366
14513
  try {
14367
- const raw = readFileSync18(PATHS.CONFIG_FILE, "utf-8");
14514
+ const raw = readFileSync19(PATHS.CONFIG_FILE, "utf-8");
14368
14515
  const config = JSON.parse(raw);
14369
14516
  const meshes = config.meshes ?? [];
14370
14517
  if (meshes.length === 0) {
@@ -14845,7 +14992,7 @@ __export(exports_url_handler, {
14845
14992
  runUrlHandler: () => runUrlHandler
14846
14993
  });
14847
14994
  import { platform as platform7, homedir as homedir12 } from "node:os";
14848
- import { existsSync as existsSync24, mkdirSync as mkdirSync11, writeFileSync as writeFileSync15, rmSync as rmSync4, chmodSync as chmodSync5 } from "node:fs";
14995
+ import { existsSync as existsSync25, mkdirSync as mkdirSync12, writeFileSync as writeFileSync16, rmSync as rmSync4, chmodSync as chmodSync5 } from "node:fs";
14849
14996
  import { join as join14 } from "node:path";
14850
14997
  import { spawnSync as spawnSync5 } from "node:child_process";
14851
14998
  function resolveClaudemeshBin() {
@@ -14856,7 +15003,7 @@ function installDarwin2() {
14856
15003
  const appDir = join14(homedir12(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
14857
15004
  const contents = join14(appDir, "Contents");
14858
15005
  const macOS = join14(contents, "MacOS");
14859
- mkdirSync11(macOS, { recursive: true });
15006
+ mkdirSync12(macOS, { recursive: true });
14860
15007
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
14861
15008
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
14862
15009
  <plist version="1.0">
@@ -14879,7 +15026,7 @@ function installDarwin2() {
14879
15026
  </array>
14880
15027
  </dict>
14881
15028
  </plist>`;
14882
- writeFileSync15(join14(contents, "Info.plist"), plist);
15029
+ writeFileSync16(join14(contents, "Info.plist"), plist);
14883
15030
  const shim = `#!/bin/sh
14884
15031
  URL="$1"
14885
15032
  CODE=\${URL#claudemesh://}
@@ -14894,7 +15041,7 @@ end tell
14894
15041
  EOF
14895
15042
  `;
14896
15043
  const shimPath = join14(macOS, "open-url");
14897
- writeFileSync15(shimPath, shim);
15044
+ writeFileSync16(shimPath, shim);
14898
15045
  chmodSync5(shimPath, 493);
14899
15046
  const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
14900
15047
  if (lsreg.status !== 0) {
@@ -14906,7 +15053,7 @@ EOF
14906
15053
  function installLinux2() {
14907
15054
  const binPath = resolveClaudemeshBin();
14908
15055
  const appsDir = join14(homedir12(), ".local", "share", "applications");
14909
- mkdirSync11(appsDir, { recursive: true });
15056
+ mkdirSync12(appsDir, { recursive: true });
14910
15057
  const desktop = `[Desktop Entry]
14911
15058
  Type=Application
14912
15059
  Name=Claudemesh
@@ -14918,7 +15065,7 @@ MimeType=x-scheme-handler/claudemesh;
14918
15065
  NoDisplay=true
14919
15066
  `;
14920
15067
  const desktopPath = join14(appsDir, "claudemesh.desktop");
14921
- writeFileSync15(desktopPath, desktop);
15068
+ writeFileSync16(desktopPath, desktop);
14922
15069
  const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
14923
15070
  if (xdg1.status !== 0) {
14924
15071
  render.warn("xdg-mime not available — skipped mime default registration");
@@ -14941,7 +15088,7 @@ function installWindows() {
14941
15088
  `@="\\"${binPath.replace(/\\/g, "\\\\")}\\" \\"%1\\""`
14942
15089
  ];
14943
15090
  const regPath = join14(homedir12(), "claudemesh-handler.reg");
14944
- writeFileSync15(regPath, lines.join(`\r
15091
+ writeFileSync16(regPath, lines.join(`\r
14945
15092
  `));
14946
15093
  const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
14947
15094
  if (res.status !== 0) {
@@ -14953,14 +15100,14 @@ function installWindows() {
14953
15100
  }
14954
15101
  function uninstallDarwin() {
14955
15102
  const appDir = join14(homedir12(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
14956
- if (existsSync24(appDir))
15103
+ if (existsSync25(appDir))
14957
15104
  rmSync4(appDir, { recursive: true, force: true });
14958
15105
  render.ok("removed claudemesh:// handler on macOS");
14959
15106
  return EXIT.SUCCESS;
14960
15107
  }
14961
15108
  function uninstallLinux() {
14962
15109
  const desktopPath = join14(homedir12(), ".local", "share", "applications", "claudemesh.desktop");
14963
- if (existsSync24(desktopPath))
15110
+ if (existsSync25(desktopPath))
14964
15111
  rmSync4(desktopPath, { force: true });
14965
15112
  render.ok("removed claudemesh:// handler on Linux");
14966
15113
  return EXIT.SUCCESS;
@@ -15005,7 +15152,7 @@ var exports_status_line = {};
15005
15152
  __export(exports_status_line, {
15006
15153
  runStatusLine: () => runStatusLine
15007
15154
  });
15008
- import { existsSync as existsSync25, readFileSync as readFileSync19 } from "node:fs";
15155
+ import { existsSync as existsSync26, readFileSync as readFileSync20 } from "node:fs";
15009
15156
  import { join as join15 } from "node:path";
15010
15157
  import { homedir as homedir13 } from "node:os";
15011
15158
  async function runStatusLine() {
@@ -15017,9 +15164,9 @@ async function runStatusLine() {
15017
15164
  }
15018
15165
  const cachePath = join15(homedir13(), ".claudemesh", "peer-cache.json");
15019
15166
  let cache = {};
15020
- if (existsSync25(cachePath)) {
15167
+ if (existsSync26(cachePath)) {
15021
15168
  try {
15022
- cache = JSON.parse(readFileSync19(cachePath, "utf-8"));
15169
+ cache = JSON.parse(readFileSync20(cachePath, "utf-8"));
15023
15170
  } catch {}
15024
15171
  }
15025
15172
  const pick = config.meshes[0];
@@ -15050,7 +15197,7 @@ __export(exports_backup, {
15050
15197
  runRestore: () => runRestore,
15051
15198
  runBackup: () => runBackup
15052
15199
  });
15053
- import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, existsSync as existsSync26 } from "node:fs";
15200
+ import { readFileSync as readFileSync21, writeFileSync as writeFileSync17, existsSync as existsSync27 } from "node:fs";
15054
15201
  import { createInterface as createInterface11 } from "node:readline";
15055
15202
  function readHidden(prompt5) {
15056
15203
  return new Promise((resolve2) => {
@@ -15092,11 +15239,11 @@ async function deriveKey(pass, salt, s) {
15092
15239
  }
15093
15240
  async function runBackup(outPath) {
15094
15241
  const configPath = getConfigPath();
15095
- if (!existsSync26(configPath)) {
15242
+ if (!existsSync27(configPath)) {
15096
15243
  console.error(" No config found — nothing to back up. Join a mesh first.");
15097
15244
  return EXIT.NOT_FOUND;
15098
15245
  }
15099
- const plaintext = readFileSync20(configPath);
15246
+ const plaintext = readFileSync21(configPath);
15100
15247
  const pass = await readHidden(" Passphrase (min 12 chars): ");
15101
15248
  if (pass.length < 12) {
15102
15249
  console.error(" ✗ Passphrase too short.");
@@ -15114,7 +15261,7 @@ async function runBackup(outPath) {
15114
15261
  const ciphertext = Buffer.from(s.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, null, null, nonce, key));
15115
15262
  const blob = Buffer.concat([MAGIC, salt, nonce, ciphertext]);
15116
15263
  const file = outPath ?? `claudemesh-backup-${new Date().toISOString().replace(/[:.]/g, "-")}.cmb`;
15117
- writeFileSync16(file, blob, { mode: 384 });
15264
+ writeFileSync17(file, blob, { mode: 384 });
15118
15265
  console.log(`
15119
15266
  ✓ Backup saved: ${file}`);
15120
15267
  console.log(` Size: ${blob.length} bytes. Guard the passphrase — there is no recovery.
@@ -15126,11 +15273,11 @@ async function runRestore(inPath) {
15126
15273
  console.error(" Usage: claudemesh restore <backup-file>");
15127
15274
  return EXIT.INVALID_ARGS;
15128
15275
  }
15129
- if (!existsSync26(inPath)) {
15276
+ if (!existsSync27(inPath)) {
15130
15277
  console.error(` ✗ File not found: ${inPath}`);
15131
15278
  return EXIT.NOT_FOUND;
15132
15279
  }
15133
- const blob = readFileSync20(inPath);
15280
+ const blob = readFileSync21(inPath);
15134
15281
  if (blob.length < 4 + 16 + 24 + 17 || !blob.subarray(0, 4).equals(MAGIC)) {
15135
15282
  console.error(" ✗ Not a claudemesh backup file (bad magic).");
15136
15283
  return EXIT.INVALID_ARGS;
@@ -15149,12 +15296,12 @@ async function runRestore(inPath) {
15149
15296
  return EXIT.INTERNAL_ERROR;
15150
15297
  }
15151
15298
  const configPath = getConfigPath();
15152
- if (existsSync26(configPath)) {
15299
+ if (existsSync27(configPath)) {
15153
15300
  const backupOld = `${configPath}.before-restore.${Date.now()}`;
15154
- writeFileSync16(backupOld, readFileSync20(configPath), { mode: 384 });
15301
+ writeFileSync17(backupOld, readFileSync21(configPath), { mode: 384 });
15155
15302
  console.log(` ↻ Existing config saved to ${backupOld}`);
15156
15303
  }
15157
- writeFileSync16(configPath, Buffer.from(plaintext), { mode: 384 });
15304
+ writeFileSync17(configPath, Buffer.from(plaintext), { mode: 384 });
15158
15305
  console.log(`
15159
15306
  ✓ Config restored to ${configPath}`);
15160
15307
  console.log(" Run `claudemesh list` to verify your meshes.\n");
@@ -15174,8 +15321,8 @@ __export(exports_upgrade, {
15174
15321
  runUpgrade: () => runUpgrade
15175
15322
  });
15176
15323
  import { spawnSync as spawnSync6 } from "node:child_process";
15177
- import { existsSync as existsSync27 } from "node:fs";
15178
- import { dirname as dirname8, join as join16, resolve as resolve2 } from "node:path";
15324
+ import { existsSync as existsSync28 } from "node:fs";
15325
+ import { dirname as dirname9, join as join16, resolve as resolve2 } from "node:path";
15179
15326
  async function latestVersion() {
15180
15327
  try {
15181
15328
  const res = await fetch(URLS.NPM_REGISTRY, { signal: AbortSignal.timeout(8000) });
@@ -15189,14 +15336,14 @@ async function latestVersion() {
15189
15336
  }
15190
15337
  function findNpm() {
15191
15338
  const portable = join16(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
15192
- if (existsSync27(portable)) {
15339
+ if (existsSync28(portable)) {
15193
15340
  return { npm: portable, prefix: join16(process.env.HOME ?? "", ".claudemesh") };
15194
15341
  }
15195
15342
  let cur = resolve2(process.argv[1] ?? ".");
15196
15343
  for (let i = 0;i < 6; i++) {
15197
- cur = dirname8(cur);
15344
+ cur = dirname9(cur);
15198
15345
  const candidate = join16(cur, "bin", "npm");
15199
- if (existsSync27(candidate))
15346
+ if (existsSync28(candidate))
15200
15347
  return { npm: candidate };
15201
15348
  }
15202
15349
  return { npm: "npm" };
@@ -15258,7 +15405,7 @@ __export(exports_grants, {
15258
15405
  runBlock: () => runBlock,
15259
15406
  isAllowed: () => isAllowed
15260
15407
  });
15261
- import { existsSync as existsSync28, mkdirSync as mkdirSync12, readFileSync as readFileSync21, writeFileSync as writeFileSync17 } from "node:fs";
15408
+ import { existsSync as existsSync29, mkdirSync as mkdirSync13, readFileSync as readFileSync22, writeFileSync as writeFileSync18 } from "node:fs";
15262
15409
  import { homedir as homedir14 } from "node:os";
15263
15410
  import { join as join17 } from "node:path";
15264
15411
  async function syncToBroker(meshSlug, grants) {
@@ -15278,19 +15425,19 @@ async function syncToBroker(meshSlug, grants) {
15278
15425
  }
15279
15426
  }
15280
15427
  function readGrants() {
15281
- if (!existsSync28(GRANT_FILE))
15428
+ if (!existsSync29(GRANT_FILE))
15282
15429
  return {};
15283
15430
  try {
15284
- return JSON.parse(readFileSync21(GRANT_FILE, "utf-8"));
15431
+ return JSON.parse(readFileSync22(GRANT_FILE, "utf-8"));
15285
15432
  } catch {
15286
15433
  return {};
15287
15434
  }
15288
15435
  }
15289
15436
  function writeGrants(g) {
15290
15437
  const dir = join17(homedir14(), ".claudemesh");
15291
- if (!existsSync28(dir))
15292
- mkdirSync12(dir, { recursive: true });
15293
- writeFileSync17(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
15438
+ if (!existsSync29(dir))
15439
+ mkdirSync13(dir, { recursive: true });
15440
+ writeFileSync18(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
15294
15441
  }
15295
15442
  function resolveCaps(input) {
15296
15443
  if (input.includes("all"))
@@ -17166,8 +17313,8 @@ __export(exports_file, {
17166
17313
  runFileGet: () => runFileGet
17167
17314
  });
17168
17315
  import { hostname as osHostname2 } from "node:os";
17169
- import { resolve as resolvePath, basename, dirname as dirname9 } from "node:path";
17170
- import { statSync as statSync7, existsSync as existsSync29, writeFileSync as writeFileSync18, mkdirSync as mkdirSync13 } from "node:fs";
17316
+ import { resolve as resolvePath, basename, dirname as dirname10 } from "node:path";
17317
+ import { statSync as statSync7, existsSync as existsSync30, writeFileSync as writeFileSync19, mkdirSync as mkdirSync14 } from "node:fs";
17171
17318
  function emitJson2(data) {
17172
17319
  console.log(JSON.stringify(data, null, 2));
17173
17320
  }
@@ -17184,7 +17331,7 @@ async function runFileShare(filePath, opts) {
17184
17331
  return EXIT.INVALID_ARGS;
17185
17332
  }
17186
17333
  const absPath = resolvePath(filePath);
17187
- if (!existsSync29(absPath)) {
17334
+ if (!existsSync30(absPath)) {
17188
17335
  render.err(`File not found: ${absPath}`);
17189
17336
  return EXIT.INVALID_ARGS;
17190
17337
  }
@@ -17263,8 +17410,8 @@ async function runFileGet(fileId, opts) {
17263
17410
  }
17264
17411
  const buf = Buffer.from(await res.arrayBuffer());
17265
17412
  const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
17266
- mkdirSync13(dirname9(outPath), { recursive: true });
17267
- writeFileSync18(outPath, buf);
17413
+ mkdirSync14(dirname10(outPath), { recursive: true });
17414
+ writeFileSync19(outPath, buf);
17268
17415
  if (opts.json) {
17269
17416
  emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
17270
17417
  } else {
@@ -17874,7 +18021,7 @@ __export(exports_bridge, {
17874
18021
  runBridge: () => runBridge,
17875
18022
  bridgeConfigTemplate: () => bridgeConfigTemplate
17876
18023
  });
17877
- import { readFileSync as readFileSync22, existsSync as existsSync30 } from "node:fs";
18024
+ import { readFileSync as readFileSync23, existsSync as existsSync31 } from "node:fs";
17878
18025
  function parseConfig(text) {
17879
18026
  const trimmed = text.trim();
17880
18027
  if (trimmed.startsWith("{"))
@@ -17918,13 +18065,13 @@ async function runBridge(configPath) {
17918
18065
  render.err("Usage: claudemesh bridge run <config.yaml>");
17919
18066
  return EXIT.INVALID_ARGS;
17920
18067
  }
17921
- if (!existsSync30(configPath)) {
18068
+ if (!existsSync31(configPath)) {
17922
18069
  render.err(`config file not found: ${configPath}`);
17923
18070
  return EXIT.NOT_FOUND;
17924
18071
  }
17925
18072
  let cfg;
17926
18073
  try {
17927
- cfg = parseConfig(readFileSync22(configPath, "utf-8"));
18074
+ cfg = parseConfig(readFileSync23(configPath, "utf-8"));
17928
18075
  } catch (e) {
17929
18076
  render.err(`failed to parse ${configPath}: ${e instanceof Error ? e.message : String(e)}`);
17930
18077
  return EXIT.INVALID_ARGS;
@@ -18898,12 +19045,12 @@ import {
18898
19045
  ListResourcesRequestSchema,
18899
19046
  ReadResourceRequestSchema
18900
19047
  } from "@modelcontextprotocol/sdk/types.js";
18901
- import { existsSync as existsSync31, appendFileSync as appendFileSync2 } from "node:fs";
19048
+ import { existsSync as existsSync32, appendFileSync as appendFileSync2 } from "node:fs";
18902
19049
  import { request as httpRequest2 } from "node:http";
18903
19050
  import { join as join18 } from "node:path";
18904
19051
  async function daemonReady() {
18905
19052
  for (let i = 0;i < DAEMON_BOOT_RETRIES; i++) {
18906
- if (existsSync31(DAEMON_PATHS.SOCK_FILE))
19053
+ if (existsSync32(DAEMON_PATHS.SOCK_FILE))
18907
19054
  return true;
18908
19055
  await new Promise((r) => setTimeout(r, DAEMON_BOOT_RETRY_MS));
18909
19056
  }
@@ -21504,4 +21651,4 @@ main().catch((err) => {
21504
21651
  process.exit(EXIT.INTERNAL_ERROR);
21505
21652
  });
21506
21653
 
21507
- //# debugId=8E61E2D1C10135BF64756E2164756E21
21654
+ //# debugId=0CB1BFC94A895DDD64756E2164756E21