claudemesh-cli 1.34.16 → 1.35.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.34.16", env;
107
+ var URLS, VERSION = "1.35.0", env;
108
108
  var init_urls = __esm(() => {
109
109
  URLS = {
110
110
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -4337,6 +4337,76 @@ var init_session_hello_sig = __esm(() => {
4337
4337
  DEFAULT_ATTESTATION_TTL_MS = 12 * 60 * 60 * 1000;
4338
4338
  });
4339
4339
 
4340
+ // src/services/session/keypair-store.ts
4341
+ var exports_keypair_store = {};
4342
+ __export(exports_keypair_store, {
4343
+ sessionsDir: () => sessionsDir,
4344
+ loadOrCreateSessionKeypair: () => loadOrCreateSessionKeypair
4345
+ });
4346
+ import { randomBytes as randomBytes6 } from "node:crypto";
4347
+ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync7 } from "node:fs";
4348
+ import { homedir as homedir5 } from "node:os";
4349
+ import { join as join5 } from "node:path";
4350
+ function sessionsDir() {
4351
+ return process.env.CLAUDEMESH_SESSIONS_DIR || join5(homedir5(), ".claudemesh", "sessions");
4352
+ }
4353
+ function keyFilePath(meshSlug, sessionId) {
4354
+ return join5(sessionsDir(), meshSlug, `${sessionId}.json`);
4355
+ }
4356
+ function readValidKeypair(file) {
4357
+ try {
4358
+ if (!existsSync8(file))
4359
+ return null;
4360
+ const parsed = JSON.parse(readFileSync7(file, "utf8"));
4361
+ if (parsed && typeof parsed.publicKey === "string" && /^[0-9a-f]{64}$/.test(parsed.publicKey) && typeof parsed.secretKey === "string" && /^[0-9a-f]{128}$/.test(parsed.secretKey)) {
4362
+ return { publicKey: parsed.publicKey, secretKey: parsed.secretKey };
4363
+ }
4364
+ } catch {}
4365
+ return null;
4366
+ }
4367
+ async function loadOrCreateSessionKeypair(meshSlug, sessionId) {
4368
+ if (!SLUG_RE.test(meshSlug) || !UUID_RE.test(sessionId)) {
4369
+ return generateKeypair3();
4370
+ }
4371
+ const file = keyFilePath(meshSlug, sessionId);
4372
+ const existing = readValidKeypair(file);
4373
+ if (existing)
4374
+ return existing;
4375
+ const kp = await generateKeypair3();
4376
+ try {
4377
+ mkdirSync4(join5(sessionsDir(), meshSlug), { recursive: true, mode: 448 });
4378
+ const stored = {
4379
+ version: 1,
4380
+ meshSlug,
4381
+ sessionId,
4382
+ publicKey: kp.publicKey,
4383
+ secretKey: kp.secretKey,
4384
+ createdAt: new Date().toISOString()
4385
+ };
4386
+ const tmp = `${file}.${randomBytes6(6).toString("hex")}.tmp`;
4387
+ writeFileSync7(tmp, JSON.stringify(stored), { mode: 384 });
4388
+ try {
4389
+ if (existsSync8(file)) {
4390
+ const won = readValidKeypair(file);
4391
+ if (won) {
4392
+ try {
4393
+ rmSync(tmp, { force: true });
4394
+ } catch {}
4395
+ return won;
4396
+ }
4397
+ }
4398
+ renameSync2(tmp, file);
4399
+ } catch {}
4400
+ } catch {}
4401
+ return kp;
4402
+ }
4403
+ var UUID_RE, SLUG_RE;
4404
+ var init_keypair_store = __esm(() => {
4405
+ init_facade7();
4406
+ UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4407
+ SLUG_RE = /^[a-z0-9._-]+$/i;
4408
+ });
4409
+
4340
4410
  // src/commands/launch.ts
4341
4411
  var exports_launch = {};
4342
4412
  __export(exports_launch, {
@@ -4344,10 +4414,33 @@ __export(exports_launch, {
4344
4414
  });
4345
4415
  import { spawnSync as spawnSync2 } from "node:child_process";
4346
4416
  import { randomUUID } from "node:crypto";
4347
- import { mkdtempSync, writeFileSync as writeFileSync7, rmSync, readdirSync, statSync as statSync2, existsSync as existsSync8, readFileSync as readFileSync7 } from "node:fs";
4348
- import { tmpdir, hostname as hostname2, homedir as homedir5 } from "node:os";
4349
- import { join as join5 } from "node:path";
4417
+ import { mkdtempSync, writeFileSync as writeFileSync8, rmSync as rmSync2, readdirSync, statSync as statSync2, existsSync as existsSync9, readFileSync as readFileSync8 } from "node:fs";
4418
+ import { tmpdir, hostname as hostname2, homedir as homedir6 } from "node:os";
4419
+ import { join as join6 } from "node:path";
4350
4420
  import { createInterface as createInterface4 } from "node:readline";
4421
+ function resolveLatestSessionUuid(cwd) {
4422
+ try {
4423
+ const slug = cwd.replace(/\//g, "-");
4424
+ const dir = join6(homedir6(), ".claude", "projects", slug);
4425
+ if (!existsSync9(dir))
4426
+ return;
4427
+ const uuidRe = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i;
4428
+ let newest = null;
4429
+ for (const entry of readdirSync(dir)) {
4430
+ const m = uuidRe.exec(entry);
4431
+ if (!m)
4432
+ continue;
4433
+ try {
4434
+ const mtime = statSync2(join6(dir, entry)).mtimeMs;
4435
+ if (!newest || mtime > newest.mtime)
4436
+ newest = { id: m[1], mtime };
4437
+ } catch {}
4438
+ }
4439
+ return newest?.id;
4440
+ } catch {
4441
+ return;
4442
+ }
4443
+ }
4351
4444
  async function ensureDaemonRunning(meshSlug, quiet) {
4352
4445
  const { ensureDaemonReady: ensureDaemonReady2 } = await Promise.resolve().then(() => (init_lifecycle(), exports_lifecycle));
4353
4446
  if (!quiet)
@@ -4743,17 +4836,17 @@ async function runLaunch(flags, rawArgs) {
4743
4836
  for (const entry of readdirSync(tmpBase)) {
4744
4837
  if (!entry.startsWith("claudemesh-"))
4745
4838
  continue;
4746
- const full = join5(tmpBase, entry);
4839
+ const full = join6(tmpBase, entry);
4747
4840
  const age = Date.now() - statSync2(full).mtimeMs;
4748
4841
  if (age > 3600000)
4749
- rmSync(full, { recursive: true, force: true });
4842
+ rmSync2(full, { recursive: true, force: true });
4750
4843
  }
4751
4844
  } catch {}
4752
4845
  await ensureDaemonRunning(mesh.slug, args.quiet);
4753
4846
  try {
4754
- const claudeConfigPath = join5(homedir5(), ".claude.json");
4755
- if (existsSync8(claudeConfigPath)) {
4756
- const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
4847
+ const claudeConfigPath = join6(homedir6(), ".claude.json");
4848
+ if (existsSync9(claudeConfigPath)) {
4849
+ const claudeConfig = JSON.parse(readFileSync8(claudeConfigPath, "utf-8"));
4757
4850
  const mcpServers = claudeConfig.mcpServers ?? {};
4758
4851
  let cleaned = 0;
4759
4852
  for (const key of Object.keys(mcpServers)) {
@@ -4771,7 +4864,7 @@ async function runLaunch(flags, rawArgs) {
4771
4864
  }
4772
4865
  if (cleaned > 0) {
4773
4866
  claudeConfig.mcpServers = mcpServers;
4774
- writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4867
+ writeFileSync8(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4775
4868
  `, "utf-8");
4776
4869
  }
4777
4870
  }
@@ -4788,7 +4881,7 @@ async function runLaunch(flags, rawArgs) {
4788
4881
  console.log(" (Could not fetch service catalog — mesh services won't be natively available)");
4789
4882
  }
4790
4883
  }
4791
- const tmpDir = mkdtempSync(join5(tmpdir(), "claudemesh-"));
4884
+ const tmpDir = mkdtempSync(join6(tmpdir(), "claudemesh-"));
4792
4885
  const sessionConfig = {
4793
4886
  version: 1,
4794
4887
  meshes: [mesh],
@@ -4797,10 +4890,18 @@ async function runLaunch(flags, rawArgs) {
4797
4890
  ...parsedGroups.length > 0 ? { groups: parsedGroups } : {},
4798
4891
  messageMode
4799
4892
  };
4800
- writeFileSync7(join5(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
4893
+ writeFileSync8(join6(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
4801
4894
  `, "utf-8");
4802
4895
  const isResume = args.resume !== null || args.continueSession;
4803
- const claudeSessionId = isResume ? undefined : randomUUID();
4896
+ let claudeSessionId;
4897
+ if (args.resume) {
4898
+ claudeSessionId = args.resume;
4899
+ } else if (args.continueSession) {
4900
+ claudeSessionId = resolveLatestSessionUuid(process.cwd());
4901
+ } else {
4902
+ claudeSessionId = randomUUID();
4903
+ }
4904
+ const passSessionIdFlag = !isResume;
4804
4905
  let sessionTokenFilePath = null;
4805
4906
  let sessionTokenForCleanup = null;
4806
4907
  try {
@@ -4812,7 +4913,7 @@ async function runLaunch(flags, rawArgs) {
4812
4913
  try {
4813
4914
  const { generateKeypair: generateKeypair4 } = await Promise.resolve().then(() => (init_facade7(), exports_facade4));
4814
4915
  const { signParentAttestation: signParentAttestation2 } = await Promise.resolve().then(() => (init_session_hello_sig(), exports_session_hello_sig));
4815
- const sessionKp = await generateKeypair4();
4916
+ const sessionKp = claudeSessionId ? await (await Promise.resolve().then(() => (init_keypair_store(), exports_keypair_store))).loadOrCreateSessionKeypair(mesh.slug, claudeSessionId) : await generateKeypair4();
4816
4917
  const att = await signParentAttestation2({
4817
4918
  parentMemberPubkey: mesh.pubkey,
4818
4919
  parentSecretKey: mesh.secretKey,
@@ -4858,10 +4959,10 @@ async function runLaunch(flags, rawArgs) {
4858
4959
  }
4859
4960
  const meshMcpEntries = [];
4860
4961
  if (serviceCatalog.length > 0) {
4861
- const claudeConfigPath = join5(homedir5(), ".claude.json");
4962
+ const claudeConfigPath = join6(homedir6(), ".claude.json");
4862
4963
  let claudeConfig = {};
4863
4964
  try {
4864
- claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
4965
+ claudeConfig = JSON.parse(readFileSync8(claudeConfigPath, "utf-8"));
4865
4966
  } catch {
4866
4967
  claudeConfig = {};
4867
4968
  }
@@ -4888,7 +4989,7 @@ async function runLaunch(flags, rawArgs) {
4888
4989
  meshMcpEntries.push({ key: entryKey, entry });
4889
4990
  }
4890
4991
  claudeConfig.mcpServers = mcpServers;
4891
- writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4992
+ writeFileSync8(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4892
4993
  `, "utf-8");
4893
4994
  if (!args.quiet && meshMcpEntries.length > 0) {
4894
4995
  console.log(` ${meshMcpEntries.length} mesh service(s) registered as native MCPs:`);
@@ -4912,7 +5013,7 @@ async function runLaunch(flags, rawArgs) {
4912
5013
  const claudeArgs = [
4913
5014
  "--dangerously-load-development-channels",
4914
5015
  "server:claudemesh",
4915
- ...claudeSessionId ? ["--session-id", claudeSessionId] : [],
5016
+ ...passSessionIdFlag && claudeSessionId ? ["--session-id", claudeSessionId] : [],
4916
5017
  ...args.resume ? ["--resume", args.resume] : [],
4917
5018
  ...args.continueSession ? ["--continue"] : [],
4918
5019
  ...args.skipPermConfirm ? ["--dangerously-skip-permissions"] : [],
@@ -4923,12 +5024,12 @@ async function runLaunch(flags, rawArgs) {
4923
5024
  let claudeBin = "claude";
4924
5025
  if (!isWindows2) {
4925
5026
  const candidates = [
4926
- join5(homedir5(), ".local", "bin", "claude"),
5027
+ join6(homedir6(), ".local", "bin", "claude"),
4927
5028
  "/usr/local/bin/claude",
4928
- join5(homedir5(), ".claude", "bin", "claude")
5029
+ join6(homedir6(), ".claude", "bin", "claude")
4929
5030
  ];
4930
5031
  for (const c of candidates) {
4931
- if (existsSync8(c)) {
5032
+ if (existsSync9(c)) {
4932
5033
  claudeBin = c;
4933
5034
  break;
4934
5035
  }
@@ -4937,19 +5038,19 @@ async function runLaunch(flags, rawArgs) {
4937
5038
  const cleanup = () => {
4938
5039
  if (meshMcpEntries.length > 0) {
4939
5040
  try {
4940
- const claudeConfigPath = join5(homedir5(), ".claude.json");
4941
- const claudeConfig = JSON.parse(readFileSync7(claudeConfigPath, "utf-8"));
5041
+ const claudeConfigPath = join6(homedir6(), ".claude.json");
5042
+ const claudeConfig = JSON.parse(readFileSync8(claudeConfigPath, "utf-8"));
4942
5043
  const mcpServers = claudeConfig.mcpServers ?? {};
4943
5044
  for (const { key } of meshMcpEntries) {
4944
5045
  delete mcpServers[key];
4945
5046
  }
4946
5047
  claudeConfig.mcpServers = mcpServers;
4947
- writeFileSync7(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
5048
+ writeFileSync8(claudeConfigPath, JSON.stringify(claudeConfig, null, 2) + `
4948
5049
  `, "utf-8");
4949
5050
  } catch {}
4950
5051
  }
4951
5052
  try {
4952
- rmSync(tmpDir, { recursive: true, force: true });
5053
+ rmSync2(tmpDir, { recursive: true, force: true });
4953
5054
  } catch {}
4954
5055
  };
4955
5056
  process.on("exit", cleanup);
@@ -5642,9 +5743,9 @@ __export(exports_join, {
5642
5743
  runJoin: () => runJoin
5643
5744
  });
5644
5745
  import sodium3 from "libsodium-wrappers";
5645
- import { writeFileSync as writeFileSync8, mkdirSync as mkdirSync4 } from "node:fs";
5646
- import { join as join6, dirname as dirname3 } from "node:path";
5647
- import { homedir as homedir6, hostname as hostname3 } from "node:os";
5746
+ import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync5 } from "node:fs";
5747
+ import { join as join7, dirname as dirname3 } from "node:path";
5748
+ import { homedir as homedir7, hostname as hostname3 } from "node:os";
5648
5749
  function deriveAppBaseUrl() {
5649
5750
  const override = process.env.CLAUDEMESH_APP_URL;
5650
5751
  if (override)
@@ -5763,11 +5864,11 @@ async function runJoin(args) {
5763
5864
  joinedAt: new Date().toISOString()
5764
5865
  });
5765
5866
  writeConfig(config);
5766
- const configDir = env.CLAUDEMESH_CONFIG_DIR ?? join6(homedir6(), ".claudemesh");
5767
- const inviteFile = join6(configDir, `invite-${payload.mesh_slug}.txt`);
5867
+ const configDir = env.CLAUDEMESH_CONFIG_DIR ?? join7(homedir7(), ".claudemesh");
5868
+ const inviteFile = join7(configDir, `invite-${payload.mesh_slug}.txt`);
5768
5869
  try {
5769
- mkdirSync4(dirname3(inviteFile), { recursive: true });
5770
- writeFileSync8(inviteFile, link, "utf-8");
5870
+ mkdirSync5(dirname3(inviteFile), { recursive: true });
5871
+ writeFileSync9(inviteFile, link, "utf-8");
5771
5872
  } catch {}
5772
5873
  console.log("");
5773
5874
  console.log(`✓ Joined "${payload.mesh_slug}" as ${displayName}${enroll.alreadyMember ? " (already a member — re-enrolled with same pubkey)" : ""}`);
@@ -6013,7 +6114,7 @@ async function rename(oldSlug, newSlug) {
6013
6114
  console.error(` ${icons.cross} Usage: ${bold("claudemesh rename")} <old-slug> <new-slug>`);
6014
6115
  return EXIT.INVALID_ARGS;
6015
6116
  }
6016
- if (!SLUG_RE.test(newSlug)) {
6117
+ if (!SLUG_RE2.test(newSlug)) {
6017
6118
  console.error(` ${icons.cross} Invalid slug: must be 2-32 chars, lowercase alnum + hyphens, start with alnum`);
6018
6119
  return EXIT.INVALID_ARGS;
6019
6120
  }
@@ -6064,7 +6165,7 @@ async function rename(oldSlug, newSlug) {
6064
6165
  return EXIT.INTERNAL_ERROR;
6065
6166
  }
6066
6167
  }
6067
- var SLUG_RE;
6168
+ var SLUG_RE2;
6068
6169
  var init_rename2 = __esm(() => {
6069
6170
  init_facade10();
6070
6171
  init_facade6();
@@ -6072,7 +6173,7 @@ var init_rename2 = __esm(() => {
6072
6173
  init_facade();
6073
6174
  init_styles();
6074
6175
  init_exit_codes();
6075
- SLUG_RE = /^[a-z0-9][a-z0-9-]{1,31}$/;
6176
+ SLUG_RE2 = /^[a-z0-9][a-z0-9-]{1,31}$/;
6076
6177
  });
6077
6178
 
6078
6179
  // src/services/clipboard/read.ts
@@ -9272,12 +9373,12 @@ var init_whoami = __esm(() => {
9272
9373
  });
9273
9374
 
9274
9375
  // src/daemon/lock.ts
9275
- import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync8, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "node:fs";
9376
+ import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync9, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "node:fs";
9276
9377
  import { dirname as dirname4 } from "node:path";
9277
9378
  function acquireSingletonLock() {
9278
- mkdirSync5(dirname4(DAEMON_PATHS.PID_FILE), { recursive: true, mode: 448 });
9279
- if (existsSync9(DAEMON_PATHS.PID_FILE)) {
9280
- const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
9379
+ mkdirSync6(dirname4(DAEMON_PATHS.PID_FILE), { recursive: true, mode: 448 });
9380
+ if (existsSync10(DAEMON_PATHS.PID_FILE)) {
9381
+ const raw = readFileSync9(DAEMON_PATHS.PID_FILE, "utf8").trim();
9281
9382
  const oldPid = Number.parseInt(raw, 10);
9282
9383
  if (Number.isFinite(oldPid) && oldPid > 0 && isProcessAlive(oldPid)) {
9283
9384
  return { result: "already-running", pid: oldPid };
@@ -9285,22 +9386,22 @@ function acquireSingletonLock() {
9285
9386
  try {
9286
9387
  unlinkSync3(DAEMON_PATHS.PID_FILE);
9287
9388
  } catch {}
9288
- writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
9389
+ writeFileSync10(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
9289
9390
  return { result: "stale", pid: process.pid };
9290
9391
  }
9291
- writeFileSync9(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
9392
+ writeFileSync10(DAEMON_PATHS.PID_FILE, String(process.pid), { mode: 384 });
9292
9393
  return { result: "acquired", pid: process.pid };
9293
9394
  }
9294
9395
  function releaseSingletonLock() {
9295
9396
  try {
9296
- const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
9397
+ const raw = readFileSync9(DAEMON_PATHS.PID_FILE, "utf8").trim();
9297
9398
  if (Number.parseInt(raw, 10) === process.pid)
9298
9399
  unlinkSync3(DAEMON_PATHS.PID_FILE);
9299
9400
  } catch {}
9300
9401
  }
9301
9402
  function readRunningPid() {
9302
9403
  try {
9303
- const raw = readFileSync8(DAEMON_PATHS.PID_FILE, "utf8").trim();
9404
+ const raw = readFileSync9(DAEMON_PATHS.PID_FILE, "utf8").trim();
9304
9405
  const pid = Number.parseInt(raw, 10);
9305
9406
  if (Number.isFinite(pid) && pid > 0 && isProcessAlive(pid))
9306
9407
  return pid;
@@ -9990,7 +10091,7 @@ var init_session_registry = __esm(() => {
9990
10091
 
9991
10092
  // src/daemon/ipc/server.ts
9992
10093
  import { createServer as createServer2 } from "node:http";
9993
- import { chmodSync as chmodSync3, existsSync as existsSync10, unlinkSync as unlinkSync4 } from "node:fs";
10094
+ import { chmodSync as chmodSync3, existsSync as existsSync11, unlinkSync as unlinkSync4 } from "node:fs";
9994
10095
  import { timingSafeEqual } from "node:crypto";
9995
10096
  import { randomUUID as randomUUID3 } from "node:crypto";
9996
10097
  function startIpcServer(opts) {
@@ -10006,7 +10107,7 @@ function startIpcServer(opts) {
10006
10107
  meshConfigs: opts.meshConfigs,
10007
10108
  onPendingInserted: opts.onPendingInserted
10008
10109
  });
10009
- if (existsSync10(DAEMON_PATHS.SOCK_FILE)) {
10110
+ if (existsSync11(DAEMON_PATHS.SOCK_FILE)) {
10010
10111
  try {
10011
10112
  unlinkSync4(DAEMON_PATHS.SOCK_FILE);
10012
10113
  } catch {}
@@ -10833,16 +10934,16 @@ function parseSendRequest(body, idempotencyHeader) {
10833
10934
  }
10834
10935
  async function resolveAndEncrypt(req, broker, meshSecretKey, meshSlug) {
10835
10936
  const { encryptDirect: encryptDirect2 } = await Promise.resolve().then(() => (init_box(), exports_box));
10836
- const { randomBytes: randomBytes6 } = await import("node:crypto");
10937
+ const { randomBytes: randomBytes7 } = await import("node:crypto");
10837
10938
  const to = req.to.trim();
10838
10939
  if (to.startsWith("#") && /^#[0-9a-z_-]{20,}$/i.test(to)) {
10839
10940
  const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
10840
- const nonce = randomBytes6(24).toString("base64");
10941
+ const nonce = randomBytes7(24).toString("base64");
10841
10942
  return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
10842
10943
  }
10843
10944
  if (to.startsWith("@") || to === "*") {
10844
10945
  const ciphertext = Buffer.from(req.message, "utf8").toString("base64");
10845
- const nonce = randomBytes6(24).toString("base64");
10946
+ const nonce = randomBytes7(24).toString("base64");
10846
10947
  return { target_spec: to, ciphertext, nonce, mesh: meshSlug ?? "" };
10847
10948
  }
10848
10949
  if (/^[0-9a-f]{64}$/i.test(to)) {
@@ -11863,8 +11964,8 @@ function bufferToHex(b) {
11863
11964
  return s;
11864
11965
  }
11865
11966
  async function randomNonce2() {
11866
- const { randomBytes: randomBytes6 } = await import("node:crypto");
11867
- return randomBytes6(24).toString("base64");
11967
+ const { randomBytes: randomBytes7 } = await import("node:crypto");
11968
+ return randomBytes7(24).toString("base64");
11868
11969
  }
11869
11970
  function defaultLog4(level, msg, meta) {
11870
11971
  const line = JSON.stringify({ level, msg, ...meta, ts: new Date().toISOString() });
@@ -12031,24 +12132,28 @@ var init_inbound = __esm(() => {
12031
12132
  // src/daemon/identity.ts
12032
12133
  var exports_identity = {};
12033
12134
  __export(exports_identity, {
12135
+ pickStableMacFromInterfaces: () => pickStableMacFromInterfaces,
12136
+ fingerprintV2: () => fingerprintV2,
12034
12137
  computeCurrentFingerprint: () => computeCurrentFingerprint,
12035
12138
  checkFingerprint: () => checkFingerprint,
12036
- acceptCurrentHost: () => acceptCurrentHost
12139
+ acceptCurrentHost: () => acceptCurrentHost,
12140
+ __resetHostIdCacheForTests: () => __resetHostIdCacheForTests,
12141
+ __computeV1FingerprintForTests: () => __computeV1FingerprintForTests
12037
12142
  });
12038
- import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "node:fs";
12039
- import { join as join7 } from "node:path";
12143
+ import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "node:fs";
12144
+ import { join as join8 } from "node:path";
12040
12145
  import { createHash as createHash2 } from "node:crypto";
12146
+ import { execFileSync } from "node:child_process";
12041
12147
  import { networkInterfaces } from "node:os";
12042
12148
  function path() {
12043
- return join7(DAEMON_PATHS.DAEMON_DIR, FILE_NAME);
12149
+ return join8(DAEMON_PATHS.DAEMON_DIR, FILE_NAME);
12044
12150
  }
12045
12151
  function computeCurrentFingerprint() {
12046
- const host_id = readHostId() ?? "";
12047
- const stable_mac = pickStableMac() ?? "";
12048
- const fp = createHash2("sha256").update(host_id, "utf8").update("\x00").update(stable_mac, "utf8").digest("hex");
12152
+ const host_id = readHostIdV2() ?? "";
12153
+ const stable_mac = pickStableMacFromInterfaces(networkInterfaces()) ?? "";
12049
12154
  return {
12050
- schema_version: 1,
12051
- fingerprint: fp,
12155
+ schema_version: CURRENT_SCHEMA,
12156
+ fingerprint: fingerprintV2(host_id, stable_mac),
12052
12157
  host_id,
12053
12158
  stable_mac,
12054
12159
  written_at: new Date().toISOString()
@@ -12056,48 +12161,103 @@ function computeCurrentFingerprint() {
12056
12161
  }
12057
12162
  function checkFingerprint() {
12058
12163
  const current = computeCurrentFingerprint();
12059
- if (!existsSync11(path())) {
12060
- writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
12164
+ if (!existsSync12(path())) {
12165
+ writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12061
12166
  return { result: "first_run", current };
12062
12167
  }
12063
12168
  let stored;
12064
12169
  try {
12065
- stored = JSON.parse(readFileSync9(path(), "utf8"));
12170
+ stored = JSON.parse(readFileSync10(path(), "utf8"));
12066
12171
  } catch {
12067
12172
  return { result: "unavailable", current };
12068
12173
  }
12069
- if (stored.fingerprint === current.fingerprint)
12070
- return { result: "match", current, stored };
12071
- return { result: "mismatch", current, stored };
12174
+ if (stored.schema_version === 2) {
12175
+ if (stored.fingerprint === current.fingerprint)
12176
+ return { result: "match", current, stored };
12177
+ if (stored.host_id && stored.host_id === current.host_id) {
12178
+ writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12179
+ return { result: "match", current, stored };
12180
+ }
12181
+ return { result: "mismatch", current, stored };
12182
+ }
12183
+ if (stored.schema_version === 1) {
12184
+ const v1 = computeCurrentFingerprintV1();
12185
+ if (stored.fingerprint === v1.fingerprint) {
12186
+ writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12187
+ return { result: "match", current, stored };
12188
+ }
12189
+ return { result: "mismatch", current, stored };
12190
+ }
12191
+ return { result: "unavailable", current };
12072
12192
  }
12073
12193
  function acceptCurrentHost() {
12074
12194
  const current = computeCurrentFingerprint();
12075
- writeFileSync10(path(), JSON.stringify(current, null, 2), { mode: 384 });
12195
+ writeFileSync11(path(), JSON.stringify(current, null, 2), { mode: 384 });
12076
12196
  return current;
12077
12197
  }
12078
- function readHostId() {
12198
+ function fingerprintV2(host_id, stable_mac) {
12199
+ return createHash2("sha256").update("v2", "utf8").update("\x00").update(host_id, "utf8").update("\x00").update(stable_mac, "utf8").digest("hex");
12200
+ }
12201
+ function pickStableMacFromInterfaces(ifs) {
12202
+ const hardware = [];
12203
+ const fallback = [];
12204
+ for (const [name, addrs] of Object.entries(ifs)) {
12205
+ if (!addrs)
12206
+ continue;
12207
+ if (isIgnoredInterface(name))
12208
+ continue;
12209
+ for (const a of addrs) {
12210
+ if (a.internal)
12211
+ continue;
12212
+ if (!a.mac || a.mac === "00:00:00:00:00:00")
12213
+ continue;
12214
+ const entry = { name, mac: a.mac };
12215
+ if (isLocallyAdministered(a.mac)) {
12216
+ fallback.push(entry);
12217
+ } else {
12218
+ hardware.push(entry);
12219
+ }
12220
+ break;
12221
+ }
12222
+ }
12223
+ const pool = hardware.length > 0 ? hardware : fallback;
12224
+ if (pool.length === 0)
12225
+ return null;
12226
+ pool.sort((a, b) => a.name.localeCompare(b.name));
12227
+ return pool[0].mac;
12228
+ }
12229
+ function computeCurrentFingerprintV1() {
12230
+ const host_id = readHostIdV1() ?? "";
12231
+ const stable_mac = pickStableMacV1() ?? "";
12232
+ const fp = createHash2("sha256").update(host_id, "utf8").update("\x00").update(stable_mac, "utf8").digest("hex");
12233
+ return {
12234
+ schema_version: 1,
12235
+ fingerprint: fp,
12236
+ host_id,
12237
+ stable_mac,
12238
+ written_at: new Date().toISOString()
12239
+ };
12240
+ }
12241
+ function readHostIdV1() {
12079
12242
  if (process.platform === "linux") {
12080
12243
  for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
12081
12244
  try {
12082
- const raw = readFileSync9(p, "utf8").trim();
12245
+ const raw = readFileSync10(p, "utf8").trim();
12083
12246
  if (raw)
12084
12247
  return `linux:${raw}`;
12085
12248
  } catch {}
12086
12249
  }
12087
12250
  return null;
12088
12251
  }
12089
- if (process.platform === "darwin") {
12090
- return null;
12091
- }
12092
12252
  return null;
12093
12253
  }
12094
- function pickStableMac() {
12254
+ function pickStableMacV1() {
12095
12255
  const ifs = networkInterfaces();
12096
12256
  const candidates = [];
12097
12257
  for (const [name, addrs] of Object.entries(ifs)) {
12098
12258
  if (!addrs)
12099
12259
  continue;
12100
- if (isIgnoredInterface(name))
12260
+ if (isIgnoredInterfaceV1(name))
12101
12261
  continue;
12102
12262
  for (const a of addrs) {
12103
12263
  if (a.internal)
@@ -12115,32 +12275,79 @@ function pickStableMac() {
12115
12275
  const idx = first.indexOf("::");
12116
12276
  return idx >= 0 ? first.slice(idx + 2) : first;
12117
12277
  }
12118
- function isIgnoredInterface(name) {
12278
+ function isIgnoredInterfaceV1(name) {
12119
12279
  return /^(lo|docker|br-|veth|tap|tun|tailscale|wg|utun|ppp|vboxnet|vmnet|awdl|llw)/i.test(name);
12120
12280
  }
12121
- var FILE_NAME = "host_fingerprint.json";
12281
+ function readHostIdV2() {
12282
+ if (cachedHostIdV2 !== undefined)
12283
+ return cachedHostIdV2;
12284
+ cachedHostIdV2 = readHostIdV2Uncached();
12285
+ return cachedHostIdV2;
12286
+ }
12287
+ function readHostIdV2Uncached() {
12288
+ if (process.platform === "linux") {
12289
+ for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
12290
+ try {
12291
+ const raw = readFileSync10(p, "utf8").trim();
12292
+ if (raw)
12293
+ return `linux:${raw}`;
12294
+ } catch {}
12295
+ }
12296
+ return null;
12297
+ }
12298
+ if (process.platform === "darwin") {
12299
+ try {
12300
+ const out = execFileSync("/usr/sbin/ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"], {
12301
+ encoding: "utf8",
12302
+ timeout: 2000,
12303
+ stdio: ["ignore", "pipe", "ignore"]
12304
+ });
12305
+ const m = out.match(/"IOPlatformUUID"\s*=\s*"([0-9A-Fa-f-]+)"/);
12306
+ if (m && m[1])
12307
+ return `darwin:${m[1]}`;
12308
+ } catch {}
12309
+ return null;
12310
+ }
12311
+ return null;
12312
+ }
12313
+ function isLocallyAdministered(mac) {
12314
+ const firstByte = parseInt(mac.split(":")[0] ?? "0", 16);
12315
+ if (Number.isNaN(firstByte))
12316
+ return false;
12317
+ return (firstByte & 2) !== 0;
12318
+ }
12319
+ function isIgnoredInterface(name) {
12320
+ return /^(lo|docker|br-|bridge|veth|tap|tun|tailscale|wg|utun|ppp|vboxnet|vmnet|awdl|llw|anpi|ap\d)/i.test(name);
12321
+ }
12322
+ function __resetHostIdCacheForTests() {
12323
+ cachedHostIdV2 = undefined;
12324
+ }
12325
+ function __computeV1FingerprintForTests() {
12326
+ return computeCurrentFingerprintV1();
12327
+ }
12328
+ var FILE_NAME = "host_fingerprint.json", CURRENT_SCHEMA = 2, cachedHostIdV2;
12122
12329
  var init_identity = __esm(() => {
12123
12330
  init_paths2();
12124
12331
  });
12125
12332
 
12126
12333
  // src/daemon/run.ts
12127
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10 } from "node:fs";
12334
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync11 } from "node:fs";
12128
12335
  function detectContainer() {
12129
12336
  if (process.env.KUBERNETES_SERVICE_HOST)
12130
12337
  return true;
12131
12338
  if (process.env.CONTAINER === "1")
12132
12339
  return true;
12133
12340
  try {
12134
- if (existsSync12("/.dockerenv"))
12341
+ if (existsSync13("/.dockerenv"))
12135
12342
  return true;
12136
- const cg = readFileSync10("/proc/1/cgroup", "utf8");
12343
+ const cg = readFileSync11("/proc/1/cgroup", "utf8");
12137
12344
  if (/(docker|kubepods|containerd)/.test(cg))
12138
12345
  return true;
12139
12346
  } catch {}
12140
12347
  return false;
12141
12348
  }
12142
12349
  async function runDaemon(opts = {}) {
12143
- mkdirSync6(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12350
+ mkdirSync7(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12144
12351
  const lock = acquireSingletonLock();
12145
12352
  if (lock.result === "already-running") {
12146
12353
  process.stderr.write(`daemon already running (pid ${lock.pid})
@@ -12283,6 +12490,17 @@ async function runDaemon(opts = {}) {
12283
12490
  }
12284
12491
  prior.close().catch(() => {});
12285
12492
  }
12493
+ const priorByPubkey = sessionBrokersByPubkey.get(info.presence.sessionPubkey);
12494
+ if (priorByPubkey && priorByPubkey !== prior) {
12495
+ for (const [tok, c] of sessionBrokers) {
12496
+ if (c === priorByPubkey) {
12497
+ sessionBrokers.delete(tok);
12498
+ break;
12499
+ }
12500
+ }
12501
+ sessionBrokersByPubkey.delete(info.presence.sessionPubkey);
12502
+ priorByPubkey.close().catch(() => {});
12503
+ }
12286
12504
  const sessionSecretKeyHex = info.presence.sessionSecretKey;
12287
12505
  const sessionPubkeyHex = info.presence.sessionPubkey;
12288
12506
  const client = new SessionBrokerClient({
@@ -12419,10 +12637,10 @@ __export(exports_service_install, {
12419
12637
  installService: () => installService,
12420
12638
  detectPlatform: () => detectPlatform
12421
12639
  });
12422
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, writeFileSync as writeFileSync11, unlinkSync as unlinkSync5, readFileSync as readFileSync11 } from "node:fs";
12640
+ import { existsSync as existsSync14, mkdirSync as mkdirSync8, writeFileSync as writeFileSync12, unlinkSync as unlinkSync5, readFileSync as readFileSync12 } from "node:fs";
12423
12641
  import { execSync as execSync2 } from "node:child_process";
12424
- import { homedir as homedir7 } from "node:os";
12425
- import { join as join8, dirname as dirname5 } from "node:path";
12642
+ import { homedir as homedir8 } from "node:os";
12643
+ import { join as join9, dirname as dirname5 } from "node:path";
12426
12644
  function detectPlatform() {
12427
12645
  if (process.platform === "darwin")
12428
12646
  return "darwin";
@@ -12440,10 +12658,10 @@ function installService(args) {
12440
12658
  if (isCi() && !args.allowCi) {
12441
12659
  throw new Error("Refusing to install persistent service in CI; pass --allow-ci-persistent to override.");
12442
12660
  }
12443
- if (!existsSync13(args.binaryPath)) {
12661
+ if (!existsSync14(args.binaryPath)) {
12444
12662
  throw new Error(`binary not found at ${args.binaryPath}`);
12445
12663
  }
12446
- mkdirSync7(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12664
+ mkdirSync8(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12447
12665
  if (platform5 === "darwin")
12448
12666
  return installDarwin(args);
12449
12667
  return installLinux(args);
@@ -12456,7 +12674,7 @@ function uninstallService() {
12456
12674
  try {
12457
12675
  execSync2(`launchctl bootout gui/$(id -u)/${SERVICE_LABEL2}`, { stdio: "ignore" });
12458
12676
  } catch {}
12459
- if (existsSync13(p)) {
12677
+ if (existsSync14(p)) {
12460
12678
  unlinkSync5(p);
12461
12679
  removed.push(p);
12462
12680
  }
@@ -12465,7 +12683,7 @@ function uninstallService() {
12465
12683
  try {
12466
12684
  execSync2(`systemctl --user disable --now ${SYSTEMD_UNIT2}`, { stdio: "ignore" });
12467
12685
  } catch {}
12468
- if (existsSync13(p)) {
12686
+ if (existsSync14(p)) {
12469
12687
  unlinkSync5(p);
12470
12688
  removed.push(p);
12471
12689
  }
@@ -12473,11 +12691,11 @@ function uninstallService() {
12473
12691
  return { platform: platform5, removed };
12474
12692
  }
12475
12693
  function darwinPlistPath() {
12476
- return join8(homedir7(), "Library", "LaunchAgents", `${SERVICE_LABEL2}.plist`);
12694
+ return join9(homedir8(), "Library", "LaunchAgents", `${SERVICE_LABEL2}.plist`);
12477
12695
  }
12478
12696
  function installDarwin(args) {
12479
12697
  const plist = darwinPlistPath();
12480
- mkdirSync7(dirname5(plist), { recursive: true });
12698
+ mkdirSync8(dirname5(plist), { recursive: true });
12481
12699
  const log2 = DAEMON_PATHS.LOG_FILE;
12482
12700
  const nodeBin = process.execPath;
12483
12701
  const meshArgs = [
@@ -12509,25 +12727,25 @@ function installDarwin(args) {
12509
12727
  <key>StandardErrorPath</key>
12510
12728
  <string>${escapeXml(log2)}</string>
12511
12729
  <key>WorkingDirectory</key>
12512
- <string>${escapeXml(homedir7())}</string>
12730
+ <string>${escapeXml(homedir8())}</string>
12513
12731
  <key>EnvironmentVariables</key>
12514
12732
  <dict>
12515
12733
  <key>HOME</key>
12516
- <string>${escapeXml(homedir7())}</string>
12734
+ <string>${escapeXml(homedir8())}</string>
12517
12735
  <key>PATH</key>
12518
12736
  <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
12519
12737
  </dict>
12520
12738
  </dict>
12521
12739
  </plist>
12522
12740
  `;
12523
- writeFileSync11(plist, xml, { mode: 420 });
12741
+ writeFileSync12(plist, xml, { mode: 420 });
12524
12742
  try {
12525
12743
  execSync2(`launchctl bootout gui/$(id -u)/${SERVICE_LABEL2}`, { stdio: "ignore" });
12526
12744
  } catch {}
12527
12745
  try {
12528
12746
  const pidPath = DAEMON_PATHS.PID_FILE;
12529
- if (existsSync13(pidPath)) {
12530
- const pid = parseInt(readFileSync11(pidPath, "utf8").trim(), 10);
12747
+ if (existsSync14(pidPath)) {
12748
+ const pid = parseInt(readFileSync12(pidPath, "utf8").trim(), 10);
12531
12749
  if (Number.isFinite(pid) && pid > 0) {
12532
12750
  try {
12533
12751
  process.kill(pid, "SIGTERM");
@@ -12542,11 +12760,11 @@ function installDarwin(args) {
12542
12760
  };
12543
12761
  }
12544
12762
  function linuxUnitPath() {
12545
- return join8(homedir7(), ".config", "systemd", "user", SYSTEMD_UNIT2);
12763
+ return join9(homedir8(), ".config", "systemd", "user", SYSTEMD_UNIT2);
12546
12764
  }
12547
12765
  function installLinux(args) {
12548
12766
  const unit = linuxUnitPath();
12549
- mkdirSync7(dirname5(unit), { recursive: true });
12767
+ mkdirSync8(dirname5(unit), { recursive: true });
12550
12768
  const nodeBin = process.execPath;
12551
12769
  const execArgs = [
12552
12770
  "daemon",
@@ -12572,14 +12790,14 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin
12572
12790
  [Install]
12573
12791
  WantedBy=default.target
12574
12792
  `;
12575
- writeFileSync11(unit, content, { mode: 420 });
12793
+ writeFileSync12(unit, content, { mode: 420 });
12576
12794
  try {
12577
12795
  execSync2(`systemctl --user stop ${SYSTEMD_UNIT2}`, { stdio: "ignore" });
12578
12796
  } catch {}
12579
12797
  try {
12580
12798
  const pidPath = DAEMON_PATHS.PID_FILE;
12581
- if (existsSync13(pidPath)) {
12582
- const pid = parseInt(readFileSync11(pidPath, "utf8").trim(), 10);
12799
+ if (existsSync14(pidPath)) {
12800
+ const pid = parseInt(readFileSync12(pidPath, "utf8").trim(), 10);
12583
12801
  if (Number.isFinite(pid) && pid > 0) {
12584
12802
  try {
12585
12803
  process.kill(pid, "SIGTERM");
@@ -12606,10 +12824,10 @@ function readInstalledUnit() {
12606
12824
  if (!platform5)
12607
12825
  return { platform: null, path: null, content: null };
12608
12826
  const path2 = platform5 === "darwin" ? darwinPlistPath() : linuxUnitPath();
12609
- if (!existsSync13(path2))
12827
+ if (!existsSync14(path2))
12610
12828
  return { platform: platform5, path: null, content: null };
12611
12829
  try {
12612
- return { platform: platform5, path: path2, content: readFileSync11(path2, "utf8") };
12830
+ return { platform: platform5, path: path2, content: readFileSync12(path2, "utf8") };
12613
12831
  } catch {
12614
12832
  return { platform: platform5, path: path2, content: null };
12615
12833
  }
@@ -12625,8 +12843,8 @@ __export(exports_daemon, {
12625
12843
  runDaemonCommand: () => runDaemonCommand
12626
12844
  });
12627
12845
  import { spawn } from "node:child_process";
12628
- import { existsSync as existsSync14, openSync as openSync3, mkdirSync as mkdirSync8 } from "node:fs";
12629
- import { join as join9 } from "node:path";
12846
+ import { existsSync as existsSync15, openSync as openSync3, mkdirSync as mkdirSync9 } from "node:fs";
12847
+ import { join as join10 } from "node:path";
12630
12848
  async function runDaemonCommand(sub, opts, rest = []) {
12631
12849
  switch (sub) {
12632
12850
  case undefined:
@@ -12948,8 +13166,8 @@ async function runStop(opts) {
12948
13166
  return 1;
12949
13167
  }
12950
13168
  async function spawnDetachedDaemon(opts) {
12951
- mkdirSync8(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
12952
- const logPath = join9(DAEMON_PATHS.DAEMON_DIR, "daemon.log");
13169
+ mkdirSync9(DAEMON_PATHS.DAEMON_DIR, { recursive: true, mode: 448 });
13170
+ const logPath = join10(DAEMON_PATHS.DAEMON_DIR, "daemon.log");
12953
13171
  const binary = process.argv[1] ?? "claudemesh";
12954
13172
  const args = ["daemon", "up", "--foreground"];
12955
13173
  if (opts.noTcp)
@@ -12967,7 +13185,7 @@ async function spawnDetachedDaemon(opts) {
12967
13185
  const sockPath = DAEMON_PATHS.SOCK_FILE;
12968
13186
  const startedAt = Date.now();
12969
13187
  while (Date.now() - startedAt < 3000) {
12970
- if (existsSync14(sockPath)) {
13188
+ if (existsSync15(sockPath)) {
12971
13189
  if (opts.json) {
12972
13190
  process.stdout.write(JSON.stringify({ ok: true, detached: true, pid: child.pid, log: logPath }) + `
12973
13191
  `);
@@ -13012,19 +13230,19 @@ __export(exports_install, {
13012
13230
  import {
13013
13231
  chmodSync as chmodSync4,
13014
13232
  copyFileSync,
13015
- existsSync as existsSync15,
13016
- mkdirSync as mkdirSync9,
13017
- readFileSync as readFileSync12,
13018
- writeFileSync as writeFileSync12
13233
+ existsSync as existsSync16,
13234
+ mkdirSync as mkdirSync10,
13235
+ readFileSync as readFileSync13,
13236
+ writeFileSync as writeFileSync13
13019
13237
  } from "node:fs";
13020
- import { homedir as homedir8, platform as platform5 } from "node:os";
13021
- import { dirname as dirname6, join as join10, resolve } from "node:path";
13238
+ import { homedir as homedir9, platform as platform5 } from "node:os";
13239
+ import { dirname as dirname6, join as join11, resolve } from "node:path";
13022
13240
  import { fileURLToPath } from "node:url";
13023
13241
  import { spawnSync as spawnSync3 } from "node:child_process";
13024
13242
  function readClaudeConfig() {
13025
- if (!existsSync15(CLAUDE_CONFIG))
13243
+ if (!existsSync16(CLAUDE_CONFIG))
13026
13244
  return {};
13027
- const text = readFileSync12(CLAUDE_CONFIG, "utf-8").trim();
13245
+ const text = readFileSync13(CLAUDE_CONFIG, "utf-8").trim();
13028
13246
  if (!text)
13029
13247
  return {};
13030
13248
  try {
@@ -13034,12 +13252,12 @@ function readClaudeConfig() {
13034
13252
  }
13035
13253
  }
13036
13254
  function backupClaudeConfig() {
13037
- if (!existsSync15(CLAUDE_CONFIG))
13255
+ if (!existsSync16(CLAUDE_CONFIG))
13038
13256
  return;
13039
- const backupDir = join10(dirname6(CLAUDE_CONFIG), ".claude", "backups");
13040
- mkdirSync9(backupDir, { recursive: true });
13257
+ const backupDir = join11(dirname6(CLAUDE_CONFIG), ".claude", "backups");
13258
+ mkdirSync10(backupDir, { recursive: true });
13041
13259
  const ts = Date.now();
13042
- const dest = join10(backupDir, `.claude.json.pre-claudemesh.${ts}`);
13260
+ const dest = join11(backupDir, `.claude.json.pre-claudemesh.${ts}`);
13043
13261
  copyFileSync(CLAUDE_CONFIG, dest);
13044
13262
  }
13045
13263
  function patchMcpServer(entry) {
@@ -13063,7 +13281,7 @@ function patchMcpServer(entry) {
13063
13281
  return action;
13064
13282
  }
13065
13283
  function removeMcpServer() {
13066
- if (!existsSync15(CLAUDE_CONFIG))
13284
+ if (!existsSync16(CLAUDE_CONFIG))
13067
13285
  return false;
13068
13286
  backupClaudeConfig();
13069
13287
  const cfg = readClaudeConfig();
@@ -13076,8 +13294,8 @@ function removeMcpServer() {
13076
13294
  return true;
13077
13295
  }
13078
13296
  function flushClaudeConfig(obj) {
13079
- mkdirSync9(dirname6(CLAUDE_CONFIG), { recursive: true });
13080
- writeFileSync12(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
13297
+ mkdirSync10(dirname6(CLAUDE_CONFIG), { recursive: true });
13298
+ writeFileSync13(CLAUDE_CONFIG, JSON.stringify(obj, null, 2) + `
13081
13299
  `, "utf-8");
13082
13300
  try {
13083
13301
  chmodSync4(CLAUDE_CONFIG, 384);
@@ -13099,8 +13317,8 @@ function resolveEntry() {
13099
13317
  function resolveBundledSkillsDir() {
13100
13318
  const here = fileURLToPath(import.meta.url);
13101
13319
  const pkgRoot = resolve(dirname6(here), "..", "..");
13102
- const skillsDir = join10(pkgRoot, "skills");
13103
- if (existsSync15(skillsDir))
13320
+ const skillsDir = join11(pkgRoot, "skills");
13321
+ if (existsSync16(skillsDir))
13104
13322
  return skillsDir;
13105
13323
  return null;
13106
13324
  }
@@ -13113,13 +13331,13 @@ function installSkills() {
13113
13331
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
13114
13332
  if (!entry.isDirectory())
13115
13333
  continue;
13116
- const srcDir = join10(src, entry.name);
13117
- const dstDir = join10(CLAUDE_SKILLS_ROOT, entry.name);
13118
- mkdirSync9(dstDir, { recursive: true });
13334
+ const srcDir = join11(src, entry.name);
13335
+ const dstDir = join11(CLAUDE_SKILLS_ROOT, entry.name);
13336
+ mkdirSync10(dstDir, { recursive: true });
13119
13337
  for (const file of fs.readdirSync(srcDir, { withFileTypes: true })) {
13120
13338
  if (!file.isFile())
13121
13339
  continue;
13122
- copyFileSync(join10(srcDir, file.name), join10(dstDir, file.name));
13340
+ copyFileSync(join11(srcDir, file.name), join11(dstDir, file.name));
13123
13341
  }
13124
13342
  installed.push(entry.name);
13125
13343
  }
@@ -13134,8 +13352,8 @@ function uninstallSkills() {
13134
13352
  for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
13135
13353
  if (!entry.isDirectory())
13136
13354
  continue;
13137
- const dstDir = join10(CLAUDE_SKILLS_ROOT, entry.name);
13138
- if (existsSync15(dstDir)) {
13355
+ const dstDir = join11(CLAUDE_SKILLS_ROOT, entry.name);
13356
+ if (existsSync16(dstDir)) {
13139
13357
  try {
13140
13358
  fs.rmSync(dstDir, { recursive: true, force: true });
13141
13359
  removed.push(entry.name);
@@ -13160,9 +13378,9 @@ function entriesEqual(a, b) {
13160
13378
  return a.command === b.command && JSON.stringify(a.args ?? []) === JSON.stringify(b.args ?? []);
13161
13379
  }
13162
13380
  function readClaudeSettings() {
13163
- if (!existsSync15(CLAUDE_SETTINGS))
13381
+ if (!existsSync16(CLAUDE_SETTINGS))
13164
13382
  return {};
13165
- const text = readFileSync12(CLAUDE_SETTINGS, "utf-8").trim();
13383
+ const text = readFileSync13(CLAUDE_SETTINGS, "utf-8").trim();
13166
13384
  if (!text)
13167
13385
  return {};
13168
13386
  try {
@@ -13172,8 +13390,8 @@ function readClaudeSettings() {
13172
13390
  }
13173
13391
  }
13174
13392
  function writeClaudeSettings(obj) {
13175
- mkdirSync9(dirname6(CLAUDE_SETTINGS), { recursive: true });
13176
- writeFileSync12(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
13393
+ mkdirSync10(dirname6(CLAUDE_SETTINGS), { recursive: true });
13394
+ writeFileSync13(CLAUDE_SETTINGS, JSON.stringify(obj, null, 2) + `
13177
13395
  `, "utf-8");
13178
13396
  }
13179
13397
  function installAllowedTools() {
@@ -13187,7 +13405,7 @@ function installAllowedTools() {
13187
13405
  return { added: toAdd, unchanged: CLAUDEMESH_TOOLS.length - toAdd.length };
13188
13406
  }
13189
13407
  function uninstallAllowedTools() {
13190
- if (!existsSync15(CLAUDE_SETTINGS))
13408
+ if (!existsSync16(CLAUDE_SETTINGS))
13191
13409
  return 0;
13192
13410
  const settings = readClaudeSettings();
13193
13411
  const existing = settings.allowedTools ?? [];
@@ -13222,7 +13440,7 @@ function installHooks() {
13222
13440
  return { added, unchanged };
13223
13441
  }
13224
13442
  function uninstallHooks() {
13225
- if (!existsSync15(CLAUDE_SETTINGS))
13443
+ if (!existsSync16(CLAUDE_SETTINGS))
13226
13444
  return 0;
13227
13445
  const settings = readClaudeSettings();
13228
13446
  const hooks2 = settings.hooks;
@@ -13272,7 +13490,7 @@ async function runInstall(args = []) {
13272
13490
  render.err("`bun` is not on PATH.", "Install Bun first: https://bun.com");
13273
13491
  process.exit(1);
13274
13492
  }
13275
- if (!existsSync15(entry)) {
13493
+ if (!existsSync16(entry)) {
13276
13494
  render.err(`MCP entry not found at ${entry}`);
13277
13495
  process.exit(1);
13278
13496
  }
@@ -13323,7 +13541,7 @@ async function runInstall(args = []) {
13323
13541
  const installed = installSkills();
13324
13542
  if (installed.length > 0) {
13325
13543
  render.ok(`Claude skill${installed.length === 1 ? "" : "s"} installed`, installed.join(", "));
13326
- render.info(dim(` ${join10(CLAUDE_SKILLS_ROOT, installed[0])}/SKILL.md`));
13544
+ render.info(dim(` ${join11(CLAUDE_SKILLS_ROOT, installed[0])}/SKILL.md`));
13327
13545
  }
13328
13546
  } catch (e) {
13329
13547
  render.warn(`skill install failed: ${e instanceof Error ? e.message : String(e)}`);
@@ -13486,9 +13704,9 @@ var init_install = __esm(() => {
13486
13704
  init_facade();
13487
13705
  init_render();
13488
13706
  init_styles();
13489
- CLAUDE_CONFIG = join10(homedir8(), ".claude.json");
13490
- CLAUDE_SETTINGS = join10(homedir8(), ".claude", "settings.json");
13491
- CLAUDE_SKILLS_ROOT = join10(homedir8(), ".claude", "skills");
13707
+ CLAUDE_CONFIG = join11(homedir9(), ".claude.json");
13708
+ CLAUDE_SETTINGS = join11(homedir9(), ".claude", "settings.json");
13709
+ CLAUDE_SKILLS_ROOT = join11(homedir9(), ".claude", "skills");
13492
13710
  CLAUDEMESH_TOOLS = [
13493
13711
  "mcp__claudemesh__cancel_scheduled",
13494
13712
  "mcp__claudemesh__check_messages",
@@ -13543,35 +13761,35 @@ var exports_uninstall = {};
13543
13761
  __export(exports_uninstall, {
13544
13762
  uninstall: () => uninstall
13545
13763
  });
13546
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync13, existsSync as existsSync16, rmSync as rmSync2, readdirSync as readdirSync2 } from "node:fs";
13547
- import { join as join11, dirname as dirname7 } from "node:path";
13548
- import { homedir as homedir9 } from "node:os";
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";
13766
+ import { homedir as homedir10 } from "node:os";
13549
13767
  import { fileURLToPath as fileURLToPath2 } from "node:url";
13550
13768
  function bundledSkillsDir() {
13551
13769
  const here = fileURLToPath2(import.meta.url);
13552
- const pkgRoot = join11(dirname7(here), "..", "..");
13553
- const skillsDir = join11(pkgRoot, "skills");
13554
- return existsSync16(skillsDir) ? skillsDir : null;
13770
+ const pkgRoot = join12(dirname7(here), "..", "..");
13771
+ const skillsDir = join12(pkgRoot, "skills");
13772
+ return existsSync17(skillsDir) ? skillsDir : null;
13555
13773
  }
13556
13774
  async function uninstall() {
13557
13775
  let removed = 0;
13558
- if (existsSync16(PATHS.CLAUDE_JSON)) {
13776
+ if (existsSync17(PATHS.CLAUDE_JSON)) {
13559
13777
  try {
13560
- const raw = readFileSync13(PATHS.CLAUDE_JSON, "utf-8");
13778
+ const raw = readFileSync14(PATHS.CLAUDE_JSON, "utf-8");
13561
13779
  const config = JSON.parse(raw);
13562
13780
  const servers = config.mcpServers;
13563
13781
  if (servers && "claudemesh" in servers) {
13564
13782
  delete servers.claudemesh;
13565
- writeFileSync13(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
13783
+ writeFileSync14(PATHS.CLAUDE_JSON, JSON.stringify(config, null, 2) + `
13566
13784
  `, "utf-8");
13567
13785
  render.ok("removed MCP server", dim("~/.claude.json"));
13568
13786
  removed++;
13569
13787
  }
13570
13788
  } catch {}
13571
13789
  }
13572
- if (existsSync16(PATHS.CLAUDE_SETTINGS)) {
13790
+ if (existsSync17(PATHS.CLAUDE_SETTINGS)) {
13573
13791
  try {
13574
- const raw = readFileSync13(PATHS.CLAUDE_SETTINGS, "utf-8");
13792
+ const raw = readFileSync14(PATHS.CLAUDE_SETTINGS, "utf-8");
13575
13793
  const config = JSON.parse(raw);
13576
13794
  const hooks2 = config.hooks;
13577
13795
  if (hooks2) {
@@ -13592,7 +13810,7 @@ async function uninstall() {
13592
13810
  }
13593
13811
  }
13594
13812
  if (removedHooks > 0) {
13595
- writeFileSync13(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
13813
+ writeFileSync14(PATHS.CLAUDE_SETTINGS, JSON.stringify(config, null, 2) + `
13596
13814
  `, "utf-8");
13597
13815
  render.ok(`removed ${removedHooks} claudemesh hook${removedHooks === 1 ? "" : "s"}`, dim("settings.json"));
13598
13816
  removed++;
@@ -13607,10 +13825,10 @@ async function uninstall() {
13607
13825
  for (const entry of readdirSync2(src, { withFileTypes: true })) {
13608
13826
  if (!entry.isDirectory())
13609
13827
  continue;
13610
- const dst = join11(CLAUDE_SKILLS_ROOT2, entry.name);
13611
- if (existsSync16(dst)) {
13828
+ const dst = join12(CLAUDE_SKILLS_ROOT2, entry.name);
13829
+ if (existsSync17(dst)) {
13612
13830
  try {
13613
- rmSync2(dst, { recursive: true, force: true });
13831
+ rmSync3(dst, { recursive: true, force: true });
13614
13832
  removedSkills.push(entry.name);
13615
13833
  } catch {}
13616
13834
  }
@@ -13632,7 +13850,7 @@ var init_uninstall = __esm(() => {
13632
13850
  init_render();
13633
13851
  init_styles();
13634
13852
  init_exit_codes();
13635
- CLAUDE_SKILLS_ROOT2 = join11(homedir9(), ".claude", "skills");
13853
+ CLAUDE_SKILLS_ROOT2 = join12(homedir10(), ".claude", "skills");
13636
13854
  });
13637
13855
 
13638
13856
  // src/commands/doctor.ts
@@ -13640,9 +13858,9 @@ var exports_doctor = {};
13640
13858
  __export(exports_doctor, {
13641
13859
  runDoctor: () => runDoctor
13642
13860
  });
13643
- import { existsSync as existsSync17, readFileSync as readFileSync14, statSync as statSync3 } from "node:fs";
13644
- import { homedir as homedir10, platform as platform6 } from "node:os";
13645
- import { join as join12 } from "node:path";
13861
+ import { existsSync as existsSync18, readFileSync as readFileSync15, statSync as statSync3 } from "node:fs";
13862
+ import { homedir as homedir11, platform as platform6 } from "node:os";
13863
+ import { join as join13 } from "node:path";
13646
13864
  import { spawnSync as spawnSync4 } from "node:child_process";
13647
13865
  function checkNode() {
13648
13866
  const major = Number(process.versions.node.split(".")[0]);
@@ -13666,8 +13884,8 @@ function checkClaudeOnPath() {
13666
13884
  };
13667
13885
  }
13668
13886
  function checkMcpRegistered() {
13669
- const claudeConfig = join12(homedir10(), ".claude.json");
13670
- if (!existsSync17(claudeConfig)) {
13887
+ const claudeConfig = join13(homedir11(), ".claude.json");
13888
+ if (!existsSync18(claudeConfig)) {
13671
13889
  return {
13672
13890
  name: "claudemesh MCP registered in ~/.claude.json",
13673
13891
  pass: false,
@@ -13675,7 +13893,7 @@ function checkMcpRegistered() {
13675
13893
  };
13676
13894
  }
13677
13895
  try {
13678
- const cfg = JSON.parse(readFileSync14(claudeConfig, "utf-8"));
13896
+ const cfg = JSON.parse(readFileSync15(claudeConfig, "utf-8"));
13679
13897
  const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
13680
13898
  return {
13681
13899
  name: "claudemesh MCP registered in ~/.claude.json",
@@ -13692,8 +13910,8 @@ function checkMcpRegistered() {
13692
13910
  }
13693
13911
  }
13694
13912
  function checkHooksRegistered() {
13695
- const settings = join12(homedir10(), ".claude", "settings.json");
13696
- if (!existsSync17(settings)) {
13913
+ const settings = join13(homedir11(), ".claude", "settings.json");
13914
+ if (!existsSync18(settings)) {
13697
13915
  return {
13698
13916
  name: "Status hooks registered in ~/.claude/settings.json",
13699
13917
  pass: false,
@@ -13701,7 +13919,7 @@ function checkHooksRegistered() {
13701
13919
  };
13702
13920
  }
13703
13921
  try {
13704
- const raw = readFileSync14(settings, "utf-8");
13922
+ const raw = readFileSync15(settings, "utf-8");
13705
13923
  const has = raw.includes("claudemesh hook ");
13706
13924
  return {
13707
13925
  name: "Status hooks registered in ~/.claude/settings.json",
@@ -13718,7 +13936,7 @@ function checkHooksRegistered() {
13718
13936
  }
13719
13937
  function checkConfigFile() {
13720
13938
  const path2 = getConfigPath();
13721
- if (!existsSync17(path2)) {
13939
+ if (!existsSync18(path2)) {
13722
13940
  return {
13723
13941
  name: "~/.claudemesh/config.json exists and parses",
13724
13942
  pass: true,
@@ -13901,7 +14119,7 @@ var exports_status = {};
13901
14119
  __export(exports_status, {
13902
14120
  runStatus: () => runStatus2
13903
14121
  });
13904
- import { statSync as statSync4, existsSync as existsSync18 } from "node:fs";
14122
+ import { statSync as statSync4, existsSync as existsSync19 } from "node:fs";
13905
14123
  import WebSocket3 from "ws";
13906
14124
  async function probeBroker(url, timeoutMs = 4000) {
13907
14125
  return new Promise((resolve2) => {
@@ -13931,7 +14149,7 @@ async function runStatus2() {
13931
14149
  render.section(`status (v${VERSION})`);
13932
14150
  const configPath = getConfigPath();
13933
14151
  let configPermsNote = "missing";
13934
- if (existsSync18(configPath)) {
14152
+ if (existsSync19(configPath)) {
13935
14153
  const mode = (statSync4(configPath).mode & 511).toString(8).padStart(4, "0");
13936
14154
  configPermsNote = mode === "0600" ? `${mode}` : `${mode} — expected 0600`;
13937
14155
  }
@@ -14077,13 +14295,13 @@ var init_check_claude_binary = __esm(() => {
14077
14295
  });
14078
14296
 
14079
14297
  // src/services/health/check-mcp-registered.ts
14080
- import { existsSync as existsSync19, readFileSync as readFileSync15 } from "node:fs";
14298
+ import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
14081
14299
  function checkMcpRegistered2() {
14082
14300
  try {
14083
- if (!existsSync19(PATHS.CLAUDE_JSON)) {
14301
+ if (!existsSync20(PATHS.CLAUDE_JSON)) {
14084
14302
  return { name: "mcp-registered", ok: false, message: "~/.claude.json not found" };
14085
14303
  }
14086
- const raw = readFileSync15(PATHS.CLAUDE_JSON, "utf-8");
14304
+ const raw = readFileSync16(PATHS.CLAUDE_JSON, "utf-8");
14087
14305
  const config = JSON.parse(raw);
14088
14306
  if (config.mcpServers && "claudemesh" in config.mcpServers) {
14089
14307
  return { name: "mcp-registered", ok: true, message: "MCP server registered" };
@@ -14098,13 +14316,13 @@ var init_check_mcp_registered = __esm(() => {
14098
14316
  });
14099
14317
 
14100
14318
  // src/services/health/check-hooks-registered.ts
14101
- import { existsSync as existsSync20, readFileSync as readFileSync16 } from "node:fs";
14319
+ import { existsSync as existsSync21, readFileSync as readFileSync17 } from "node:fs";
14102
14320
  function checkHooksRegistered2() {
14103
14321
  try {
14104
- if (!existsSync20(PATHS.CLAUDE_SETTINGS)) {
14322
+ if (!existsSync21(PATHS.CLAUDE_SETTINGS)) {
14105
14323
  return { name: "hooks-registered", ok: false, message: "~/.claude/settings.json not found" };
14106
14324
  }
14107
- const raw = readFileSync16(PATHS.CLAUDE_SETTINGS, "utf-8");
14325
+ const raw = readFileSync17(PATHS.CLAUDE_SETTINGS, "utf-8");
14108
14326
  const config = JSON.parse(raw);
14109
14327
  if (config.hooks) {
14110
14328
  return { name: "hooks-registered", ok: true, message: "Hooks configured" };
@@ -14119,10 +14337,10 @@ var init_check_hooks_registered = __esm(() => {
14119
14337
  });
14120
14338
 
14121
14339
  // src/services/health/check-config-perms.ts
14122
- import { existsSync as existsSync21, statSync as statSync5 } from "node:fs";
14340
+ import { existsSync as existsSync22, statSync as statSync5 } from "node:fs";
14123
14341
  function checkConfigPerms() {
14124
14342
  const configFile = PATHS.CONFIG_FILE;
14125
- if (!existsSync21(configFile)) {
14343
+ if (!existsSync22(configFile)) {
14126
14344
  return { name: "config-perms", ok: true, message: "No config file yet (first run)" };
14127
14345
  }
14128
14346
  try {
@@ -14140,13 +14358,13 @@ var init_check_config_perms = __esm(() => {
14140
14358
  });
14141
14359
 
14142
14360
  // src/services/health/check-keypairs-valid.ts
14143
- import { existsSync as existsSync22, readFileSync as readFileSync17 } from "node:fs";
14361
+ import { existsSync as existsSync23, readFileSync as readFileSync18 } from "node:fs";
14144
14362
  function checkKeypairsValid() {
14145
- if (!existsSync22(PATHS.CONFIG_FILE)) {
14363
+ if (!existsSync23(PATHS.CONFIG_FILE)) {
14146
14364
  return { name: "keypairs-valid", ok: true, message: "No config (first run)" };
14147
14365
  }
14148
14366
  try {
14149
- const raw = readFileSync17(PATHS.CONFIG_FILE, "utf-8");
14367
+ const raw = readFileSync18(PATHS.CONFIG_FILE, "utf-8");
14150
14368
  const config = JSON.parse(raw);
14151
14369
  const meshes = config.meshes ?? [];
14152
14370
  if (meshes.length === 0) {
@@ -14626,19 +14844,19 @@ var exports_url_handler = {};
14626
14844
  __export(exports_url_handler, {
14627
14845
  runUrlHandler: () => runUrlHandler
14628
14846
  });
14629
- import { platform as platform7, homedir as homedir11 } from "node:os";
14630
- import { existsSync as existsSync23, mkdirSync as mkdirSync10, writeFileSync as writeFileSync14, rmSync as rmSync3, chmodSync as chmodSync5 } from "node:fs";
14631
- import { join as join13 } from "node:path";
14847
+ 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";
14849
+ import { join as join14 } from "node:path";
14632
14850
  import { spawnSync as spawnSync5 } from "node:child_process";
14633
14851
  function resolveClaudemeshBin() {
14634
14852
  return process.argv[1] ?? "claudemesh";
14635
14853
  }
14636
14854
  function installDarwin2() {
14637
14855
  const binPath = resolveClaudemeshBin();
14638
- const appDir = join13(homedir11(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
14639
- const contents = join13(appDir, "Contents");
14640
- const macOS = join13(contents, "MacOS");
14641
- mkdirSync10(macOS, { recursive: true });
14856
+ const appDir = join14(homedir12(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
14857
+ const contents = join14(appDir, "Contents");
14858
+ const macOS = join14(contents, "MacOS");
14859
+ mkdirSync11(macOS, { recursive: true });
14642
14860
  const plist = `<?xml version="1.0" encoding="UTF-8"?>
14643
14861
  <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
14644
14862
  <plist version="1.0">
@@ -14661,7 +14879,7 @@ function installDarwin2() {
14661
14879
  </array>
14662
14880
  </dict>
14663
14881
  </plist>`;
14664
- writeFileSync14(join13(contents, "Info.plist"), plist);
14882
+ writeFileSync15(join14(contents, "Info.plist"), plist);
14665
14883
  const shim = `#!/bin/sh
14666
14884
  URL="$1"
14667
14885
  CODE=\${URL#claudemesh://}
@@ -14675,8 +14893,8 @@ tell application "Terminal"
14675
14893
  end tell
14676
14894
  EOF
14677
14895
  `;
14678
- const shimPath = join13(macOS, "open-url");
14679
- writeFileSync14(shimPath, shim);
14896
+ const shimPath = join14(macOS, "open-url");
14897
+ writeFileSync15(shimPath, shim);
14680
14898
  chmodSync5(shimPath, 493);
14681
14899
  const lsreg = spawnSync5("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", ["-f", appDir], { encoding: "utf-8" });
14682
14900
  if (lsreg.status !== 0) {
@@ -14687,8 +14905,8 @@ EOF
14687
14905
  }
14688
14906
  function installLinux2() {
14689
14907
  const binPath = resolveClaudemeshBin();
14690
- const appsDir = join13(homedir11(), ".local", "share", "applications");
14691
- mkdirSync10(appsDir, { recursive: true });
14908
+ const appsDir = join14(homedir12(), ".local", "share", "applications");
14909
+ mkdirSync11(appsDir, { recursive: true });
14692
14910
  const desktop = `[Desktop Entry]
14693
14911
  Type=Application
14694
14912
  Name=Claudemesh
@@ -14699,8 +14917,8 @@ Terminal=true
14699
14917
  MimeType=x-scheme-handler/claudemesh;
14700
14918
  NoDisplay=true
14701
14919
  `;
14702
- const desktopPath = join13(appsDir, "claudemesh.desktop");
14703
- writeFileSync14(desktopPath, desktop);
14920
+ const desktopPath = join14(appsDir, "claudemesh.desktop");
14921
+ writeFileSync15(desktopPath, desktop);
14704
14922
  const xdg1 = spawnSync5("xdg-mime", ["default", "claudemesh.desktop", "x-scheme-handler/claudemesh"], { encoding: "utf-8" });
14705
14923
  if (xdg1.status !== 0) {
14706
14924
  render.warn("xdg-mime not available — skipped mime default registration");
@@ -14722,8 +14940,8 @@ function installWindows() {
14722
14940
  `[HKEY_CURRENT_USER\\Software\\Classes\\claudemesh\\shell\\open\\command]`,
14723
14941
  `@="\\"${binPath.replace(/\\/g, "\\\\")}\\" \\"%1\\""`
14724
14942
  ];
14725
- const regPath = join13(homedir11(), "claudemesh-handler.reg");
14726
- writeFileSync14(regPath, lines.join(`\r
14943
+ const regPath = join14(homedir12(), "claudemesh-handler.reg");
14944
+ writeFileSync15(regPath, lines.join(`\r
14727
14945
  `));
14728
14946
  const res = spawnSync5("reg.exe", ["import", regPath], { encoding: "utf-8" });
14729
14947
  if (res.status !== 0) {
@@ -14734,16 +14952,16 @@ function installWindows() {
14734
14952
  return EXIT.SUCCESS;
14735
14953
  }
14736
14954
  function uninstallDarwin() {
14737
- const appDir = join13(homedir11(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
14738
- if (existsSync23(appDir))
14739
- rmSync3(appDir, { recursive: true, force: true });
14955
+ const appDir = join14(homedir12(), "Library", "Application Support", "claudemesh", "ClaudemeshHandler.app");
14956
+ if (existsSync24(appDir))
14957
+ rmSync4(appDir, { recursive: true, force: true });
14740
14958
  render.ok("removed claudemesh:// handler on macOS");
14741
14959
  return EXIT.SUCCESS;
14742
14960
  }
14743
14961
  function uninstallLinux() {
14744
- const desktopPath = join13(homedir11(), ".local", "share", "applications", "claudemesh.desktop");
14745
- if (existsSync23(desktopPath))
14746
- rmSync3(desktopPath, { force: true });
14962
+ const desktopPath = join14(homedir12(), ".local", "share", "applications", "claudemesh.desktop");
14963
+ if (existsSync24(desktopPath))
14964
+ rmSync4(desktopPath, { force: true });
14747
14965
  render.ok("removed claudemesh:// handler on Linux");
14748
14966
  return EXIT.SUCCESS;
14749
14967
  }
@@ -14787,9 +15005,9 @@ var exports_status_line = {};
14787
15005
  __export(exports_status_line, {
14788
15006
  runStatusLine: () => runStatusLine
14789
15007
  });
14790
- import { existsSync as existsSync24, readFileSync as readFileSync18 } from "node:fs";
14791
- import { join as join14 } from "node:path";
14792
- import { homedir as homedir12 } from "node:os";
15008
+ import { existsSync as existsSync25, readFileSync as readFileSync19 } from "node:fs";
15009
+ import { join as join15 } from "node:path";
15010
+ import { homedir as homedir13 } from "node:os";
14793
15011
  async function runStatusLine() {
14794
15012
  try {
14795
15013
  const config = readConfig();
@@ -14797,11 +15015,11 @@ async function runStatusLine() {
14797
15015
  process.stdout.write("◇ claudemesh (not joined)");
14798
15016
  return EXIT.SUCCESS;
14799
15017
  }
14800
- const cachePath = join14(homedir12(), ".claudemesh", "peer-cache.json");
15018
+ const cachePath = join15(homedir13(), ".claudemesh", "peer-cache.json");
14801
15019
  let cache = {};
14802
- if (existsSync24(cachePath)) {
15020
+ if (existsSync25(cachePath)) {
14803
15021
  try {
14804
- cache = JSON.parse(readFileSync18(cachePath, "utf-8"));
15022
+ cache = JSON.parse(readFileSync19(cachePath, "utf-8"));
14805
15023
  } catch {}
14806
15024
  }
14807
15025
  const pick = config.meshes[0];
@@ -14832,7 +15050,7 @@ __export(exports_backup, {
14832
15050
  runRestore: () => runRestore,
14833
15051
  runBackup: () => runBackup
14834
15052
  });
14835
- import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, existsSync as existsSync25 } from "node:fs";
15053
+ import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, existsSync as existsSync26 } from "node:fs";
14836
15054
  import { createInterface as createInterface11 } from "node:readline";
14837
15055
  function readHidden(prompt5) {
14838
15056
  return new Promise((resolve2) => {
@@ -14874,11 +15092,11 @@ async function deriveKey(pass, salt, s) {
14874
15092
  }
14875
15093
  async function runBackup(outPath) {
14876
15094
  const configPath = getConfigPath();
14877
- if (!existsSync25(configPath)) {
15095
+ if (!existsSync26(configPath)) {
14878
15096
  console.error(" No config found — nothing to back up. Join a mesh first.");
14879
15097
  return EXIT.NOT_FOUND;
14880
15098
  }
14881
- const plaintext = readFileSync19(configPath);
15099
+ const plaintext = readFileSync20(configPath);
14882
15100
  const pass = await readHidden(" Passphrase (min 12 chars): ");
14883
15101
  if (pass.length < 12) {
14884
15102
  console.error(" ✗ Passphrase too short.");
@@ -14896,7 +15114,7 @@ async function runBackup(outPath) {
14896
15114
  const ciphertext = Buffer.from(s.crypto_aead_xchacha20poly1305_ietf_encrypt(plaintext, null, null, nonce, key));
14897
15115
  const blob = Buffer.concat([MAGIC, salt, nonce, ciphertext]);
14898
15116
  const file = outPath ?? `claudemesh-backup-${new Date().toISOString().replace(/[:.]/g, "-")}.cmb`;
14899
- writeFileSync15(file, blob, { mode: 384 });
15117
+ writeFileSync16(file, blob, { mode: 384 });
14900
15118
  console.log(`
14901
15119
  ✓ Backup saved: ${file}`);
14902
15120
  console.log(` Size: ${blob.length} bytes. Guard the passphrase — there is no recovery.
@@ -14908,11 +15126,11 @@ async function runRestore(inPath) {
14908
15126
  console.error(" Usage: claudemesh restore <backup-file>");
14909
15127
  return EXIT.INVALID_ARGS;
14910
15128
  }
14911
- if (!existsSync25(inPath)) {
15129
+ if (!existsSync26(inPath)) {
14912
15130
  console.error(` ✗ File not found: ${inPath}`);
14913
15131
  return EXIT.NOT_FOUND;
14914
15132
  }
14915
- const blob = readFileSync19(inPath);
15133
+ const blob = readFileSync20(inPath);
14916
15134
  if (blob.length < 4 + 16 + 24 + 17 || !blob.subarray(0, 4).equals(MAGIC)) {
14917
15135
  console.error(" ✗ Not a claudemesh backup file (bad magic).");
14918
15136
  return EXIT.INVALID_ARGS;
@@ -14931,12 +15149,12 @@ async function runRestore(inPath) {
14931
15149
  return EXIT.INTERNAL_ERROR;
14932
15150
  }
14933
15151
  const configPath = getConfigPath();
14934
- if (existsSync25(configPath)) {
15152
+ if (existsSync26(configPath)) {
14935
15153
  const backupOld = `${configPath}.before-restore.${Date.now()}`;
14936
- writeFileSync15(backupOld, readFileSync19(configPath), { mode: 384 });
15154
+ writeFileSync16(backupOld, readFileSync20(configPath), { mode: 384 });
14937
15155
  console.log(` ↻ Existing config saved to ${backupOld}`);
14938
15156
  }
14939
- writeFileSync15(configPath, Buffer.from(plaintext), { mode: 384 });
15157
+ writeFileSync16(configPath, Buffer.from(plaintext), { mode: 384 });
14940
15158
  console.log(`
14941
15159
  ✓ Config restored to ${configPath}`);
14942
15160
  console.log(" Run `claudemesh list` to verify your meshes.\n");
@@ -14956,8 +15174,8 @@ __export(exports_upgrade, {
14956
15174
  runUpgrade: () => runUpgrade
14957
15175
  });
14958
15176
  import { spawnSync as spawnSync6 } from "node:child_process";
14959
- import { existsSync as existsSync26 } from "node:fs";
14960
- import { dirname as dirname8, join as join15, resolve as resolve2 } from "node:path";
15177
+ import { existsSync as existsSync27 } from "node:fs";
15178
+ import { dirname as dirname8, join as join16, resolve as resolve2 } from "node:path";
14961
15179
  async function latestVersion() {
14962
15180
  try {
14963
15181
  const res = await fetch(URLS.NPM_REGISTRY, { signal: AbortSignal.timeout(8000) });
@@ -14970,15 +15188,15 @@ async function latestVersion() {
14970
15188
  }
14971
15189
  }
14972
15190
  function findNpm() {
14973
- const portable = join15(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
14974
- if (existsSync26(portable)) {
14975
- return { npm: portable, prefix: join15(process.env.HOME ?? "", ".claudemesh") };
15191
+ const portable = join16(process.env.HOME ?? "", ".claudemesh", "node", "bin", "npm");
15192
+ if (existsSync27(portable)) {
15193
+ return { npm: portable, prefix: join16(process.env.HOME ?? "", ".claudemesh") };
14976
15194
  }
14977
15195
  let cur = resolve2(process.argv[1] ?? ".");
14978
15196
  for (let i = 0;i < 6; i++) {
14979
15197
  cur = dirname8(cur);
14980
- const candidate = join15(cur, "bin", "npm");
14981
- if (existsSync26(candidate))
15198
+ const candidate = join16(cur, "bin", "npm");
15199
+ if (existsSync27(candidate))
14982
15200
  return { npm: candidate };
14983
15201
  }
14984
15202
  return { npm: "npm" };
@@ -15040,9 +15258,9 @@ __export(exports_grants, {
15040
15258
  runBlock: () => runBlock,
15041
15259
  isAllowed: () => isAllowed
15042
15260
  });
15043
- import { existsSync as existsSync27, mkdirSync as mkdirSync11, readFileSync as readFileSync20, writeFileSync as writeFileSync16 } from "node:fs";
15044
- import { homedir as homedir13 } from "node:os";
15045
- import { join as join16 } from "node:path";
15261
+ import { existsSync as existsSync28, mkdirSync as mkdirSync12, readFileSync as readFileSync21, writeFileSync as writeFileSync17 } from "node:fs";
15262
+ import { homedir as homedir14 } from "node:os";
15263
+ import { join as join17 } from "node:path";
15046
15264
  async function syncToBroker(meshSlug, grants) {
15047
15265
  const auth = getStoredToken();
15048
15266
  if (!auth)
@@ -15060,19 +15278,19 @@ async function syncToBroker(meshSlug, grants) {
15060
15278
  }
15061
15279
  }
15062
15280
  function readGrants() {
15063
- if (!existsSync27(GRANT_FILE))
15281
+ if (!existsSync28(GRANT_FILE))
15064
15282
  return {};
15065
15283
  try {
15066
- return JSON.parse(readFileSync20(GRANT_FILE, "utf-8"));
15284
+ return JSON.parse(readFileSync21(GRANT_FILE, "utf-8"));
15067
15285
  } catch {
15068
15286
  return {};
15069
15287
  }
15070
15288
  }
15071
15289
  function writeGrants(g) {
15072
- const dir = join16(homedir13(), ".claudemesh");
15073
- if (!existsSync27(dir))
15074
- mkdirSync11(dir, { recursive: true });
15075
- writeFileSync16(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
15290
+ 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 });
15076
15294
  }
15077
15295
  function resolveCaps(input) {
15078
15296
  if (input.includes("all"))
@@ -15228,7 +15446,7 @@ var init_grants = __esm(() => {
15228
15446
  BROKER_HTTP7 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
15229
15447
  ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
15230
15448
  DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
15231
- GRANT_FILE = join16(homedir13(), ".claudemesh", "grants.json");
15449
+ GRANT_FILE = join17(homedir14(), ".claudemesh", "grants.json");
15232
15450
  });
15233
15451
 
15234
15452
  // src/commands/profile.ts
@@ -16949,7 +17167,7 @@ __export(exports_file, {
16949
17167
  });
16950
17168
  import { hostname as osHostname2 } from "node:os";
16951
17169
  import { resolve as resolvePath, basename, dirname as dirname9 } from "node:path";
16952
- import { statSync as statSync7, existsSync as existsSync28, writeFileSync as writeFileSync17, mkdirSync as mkdirSync12 } from "node:fs";
17170
+ import { statSync as statSync7, existsSync as existsSync29, writeFileSync as writeFileSync18, mkdirSync as mkdirSync13 } from "node:fs";
16953
17171
  function emitJson2(data) {
16954
17172
  console.log(JSON.stringify(data, null, 2));
16955
17173
  }
@@ -16966,7 +17184,7 @@ async function runFileShare(filePath, opts) {
16966
17184
  return EXIT.INVALID_ARGS;
16967
17185
  }
16968
17186
  const absPath = resolvePath(filePath);
16969
- if (!existsSync28(absPath)) {
17187
+ if (!existsSync29(absPath)) {
16970
17188
  render.err(`File not found: ${absPath}`);
16971
17189
  return EXIT.INVALID_ARGS;
16972
17190
  }
@@ -17045,8 +17263,8 @@ async function runFileGet(fileId, opts) {
17045
17263
  }
17046
17264
  const buf = Buffer.from(await res.arrayBuffer());
17047
17265
  const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
17048
- mkdirSync12(dirname9(outPath), { recursive: true });
17049
- writeFileSync17(outPath, buf);
17266
+ mkdirSync13(dirname9(outPath), { recursive: true });
17267
+ writeFileSync18(outPath, buf);
17050
17268
  if (opts.json) {
17051
17269
  emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
17052
17270
  } else {
@@ -17656,7 +17874,7 @@ __export(exports_bridge, {
17656
17874
  runBridge: () => runBridge,
17657
17875
  bridgeConfigTemplate: () => bridgeConfigTemplate
17658
17876
  });
17659
- import { readFileSync as readFileSync21, existsSync as existsSync29 } from "node:fs";
17877
+ import { readFileSync as readFileSync22, existsSync as existsSync30 } from "node:fs";
17660
17878
  function parseConfig(text) {
17661
17879
  const trimmed = text.trim();
17662
17880
  if (trimmed.startsWith("{"))
@@ -17700,13 +17918,13 @@ async function runBridge(configPath) {
17700
17918
  render.err("Usage: claudemesh bridge run <config.yaml>");
17701
17919
  return EXIT.INVALID_ARGS;
17702
17920
  }
17703
- if (!existsSync29(configPath)) {
17921
+ if (!existsSync30(configPath)) {
17704
17922
  render.err(`config file not found: ${configPath}`);
17705
17923
  return EXIT.NOT_FOUND;
17706
17924
  }
17707
17925
  let cfg;
17708
17926
  try {
17709
- cfg = parseConfig(readFileSync21(configPath, "utf-8"));
17927
+ cfg = parseConfig(readFileSync22(configPath, "utf-8"));
17710
17928
  } catch (e) {
17711
17929
  render.err(`failed to parse ${configPath}: ${e instanceof Error ? e.message : String(e)}`);
17712
17930
  return EXIT.INVALID_ARGS;
@@ -18680,12 +18898,12 @@ import {
18680
18898
  ListResourcesRequestSchema,
18681
18899
  ReadResourceRequestSchema
18682
18900
  } from "@modelcontextprotocol/sdk/types.js";
18683
- import { existsSync as existsSync30, appendFileSync as appendFileSync2 } from "node:fs";
18901
+ import { existsSync as existsSync31, appendFileSync as appendFileSync2 } from "node:fs";
18684
18902
  import { request as httpRequest2 } from "node:http";
18685
- import { join as join17 } from "node:path";
18903
+ import { join as join18 } from "node:path";
18686
18904
  async function daemonReady() {
18687
18905
  for (let i = 0;i < DAEMON_BOOT_RETRIES; i++) {
18688
- if (existsSync30(DAEMON_PATHS.SOCK_FILE))
18906
+ if (existsSync31(DAEMON_PATHS.SOCK_FILE))
18689
18907
  return true;
18690
18908
  await new Promise((r) => setTimeout(r, DAEMON_BOOT_RETRY_MS));
18691
18909
  }
@@ -18959,7 +19177,7 @@ ${mf.allowed_tools.map((t) => ` - ${t}`).join(`
18959
19177
  return { contents: [{ uri, mimeType: "text/markdown", text: fm.join(`
18960
19178
  `) + skill.instructions }] };
18961
19179
  });
18962
- const mcpLogPath = join17(DAEMON_PATHS.DAEMON_DIR, `mcp-${process.pid}.log`);
19180
+ const mcpLogPath = join18(DAEMON_PATHS.DAEMON_DIR, `mcp-${process.pid}.log`);
18963
19181
  const mcpLog = (msg, meta) => {
18964
19182
  const line = JSON.stringify({ ts: new Date().toISOString(), pid: process.pid, msg, ...meta }) + `
18965
19183
  `;
@@ -21286,4 +21504,4 @@ main().catch((err) => {
21286
21504
  process.exit(EXIT.INTERNAL_ERROR);
21287
21505
  });
21288
21506
 
21289
- //# debugId=8D95F82FF933574E64756E2164756E21
21507
+ //# debugId=8E61E2D1C10135BF64756E2164756E21