claudemesh-cli 1.0.0-alpha.3 → 1.0.0-alpha.31

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.
@@ -3286,6 +3286,359 @@ var init_facade3 = __esm(() => {
3286
3286
  init_errors();
3287
3287
  });
3288
3288
 
3289
+ // src/commands/connect.ts
3290
+ import { hostname } from "node:os";
3291
+ import { createInterface } from "node:readline";
3292
+ async function pickMesh(meshes) {
3293
+ console.log(`
3294
+ Select mesh:`);
3295
+ meshes.forEach((m, i) => {
3296
+ console.log(` ${i + 1}) ${m.slug}`);
3297
+ });
3298
+ console.log("");
3299
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
3300
+ return new Promise((resolve) => {
3301
+ rl.question(" Choice [1]: ", (answer) => {
3302
+ rl.close();
3303
+ const idx = parseInt(answer || "1", 10) - 1;
3304
+ if (idx >= 0 && idx < meshes.length) {
3305
+ resolve(meshes[idx]);
3306
+ } else {
3307
+ console.error(" Invalid choice, using first mesh.");
3308
+ resolve(meshes[0]);
3309
+ }
3310
+ });
3311
+ });
3312
+ }
3313
+ async function withMesh(opts, fn) {
3314
+ const config = readConfig();
3315
+ if (config.meshes.length === 0) {
3316
+ console.error("No meshes joined. Run `claudemesh join <url>` first.");
3317
+ process.exit(1);
3318
+ }
3319
+ let mesh;
3320
+ if (opts.meshSlug) {
3321
+ const found = config.meshes.find((m) => m.slug === opts.meshSlug);
3322
+ if (!found) {
3323
+ console.error(`Mesh "${opts.meshSlug}" not found. Joined: ${config.meshes.map((m) => m.slug).join(", ")}`);
3324
+ process.exit(1);
3325
+ }
3326
+ mesh = found;
3327
+ } else if (config.meshes.length === 1) {
3328
+ mesh = config.meshes[0];
3329
+ } else {
3330
+ mesh = await pickMesh(config.meshes);
3331
+ }
3332
+ const displayName = opts.displayName ?? config.displayName ?? `${hostname()}-${process.pid}`;
3333
+ const client = new BrokerClient(mesh, { displayName });
3334
+ try {
3335
+ await client.connect();
3336
+ const result = await fn(client, mesh);
3337
+ return result;
3338
+ } finally {
3339
+ client.close();
3340
+ }
3341
+ }
3342
+ var init_connect = __esm(() => {
3343
+ init_facade3();
3344
+ init_facade();
3345
+ });
3346
+
3347
+ // src/ui/styles.ts
3348
+ function moveTo(row, col) {
3349
+ return isTTY ? `\x1B[${row};${col}H` : "";
3350
+ }
3351
+ function visibleLength(s) {
3352
+ return s.replace(/\x1b\[[^m]*m/g, "").length;
3353
+ }
3354
+ var isTTY, esc = (code) => (s) => isTTY ? `${code}${s}\x1B[0m` : s, orange, clay, amber, bold, dim, green, yellow, red, cyan, boldOrange, HIDE_CURSOR, SHOW_CURSOR, CLEAR_SCREEN, CLEAR_LINE, icons;
3355
+ var init_styles = __esm(() => {
3356
+ isTTY = process.stdout.isTTY && !process.env.NO_COLOR && process.env.TERM !== "dumb";
3357
+ orange = esc("\x1B[38;5;208m");
3358
+ clay = esc("\x1B[38;5;173m");
3359
+ amber = esc("\x1B[38;5;214m");
3360
+ bold = esc("\x1B[1m");
3361
+ dim = esc("\x1B[2m");
3362
+ green = esc("\x1B[32m");
3363
+ yellow = esc("\x1B[33m");
3364
+ red = esc("\x1B[31m");
3365
+ cyan = esc("\x1B[36m");
3366
+ boldOrange = esc("\x1B[1m\x1B[38;5;208m");
3367
+ HIDE_CURSOR = isTTY ? "\x1B[?25l" : "";
3368
+ SHOW_CURSOR = isTTY ? "\x1B[?25h" : "";
3369
+ CLEAR_SCREEN = isTTY ? "\x1B[2J\x1B[H" : "";
3370
+ CLEAR_LINE = isTTY ? "\x1B[K" : "";
3371
+ icons = {
3372
+ check: "✔",
3373
+ cross: "✘",
3374
+ warn: "⚠",
3375
+ arrow: "→",
3376
+ bullet: "●",
3377
+ dash: "—",
3378
+ ellipsis: "…"
3379
+ };
3380
+ });
3381
+
3382
+ // src/ui/render.ts
3383
+ var OUT, ERR, INDENT = " ", render;
3384
+ var init_render = __esm(() => {
3385
+ init_styles();
3386
+ OUT = process.stdout;
3387
+ ERR = process.stderr;
3388
+ render = {
3389
+ blank() {
3390
+ OUT.write(`
3391
+ `);
3392
+ },
3393
+ ok(msg, detail) {
3394
+ const d = detail ? ` ${dim("(" + detail + ")")}` : "";
3395
+ OUT.write(`${INDENT}${green(icons.check)} ${msg}${d}
3396
+ `);
3397
+ },
3398
+ warn(msg, hint) {
3399
+ OUT.write(`${INDENT}${yellow(icons.warn)} ${msg}
3400
+ `);
3401
+ if (hint)
3402
+ OUT.write(`${INDENT} ${dim(hint)}
3403
+ `);
3404
+ },
3405
+ err(msg, hint) {
3406
+ ERR.write(`${INDENT}${red(icons.cross)} ${msg}
3407
+ `);
3408
+ if (hint)
3409
+ ERR.write(`${INDENT} ${dim(hint)}
3410
+ `);
3411
+ },
3412
+ info(msg) {
3413
+ OUT.write(`${INDENT}${msg}
3414
+ `);
3415
+ },
3416
+ section(title) {
3417
+ OUT.write(`
3418
+ ${INDENT}${dim("—")} ${clay(title)}
3419
+
3420
+ `);
3421
+ },
3422
+ heading(title) {
3423
+ OUT.write(`${INDENT}${bold(title)}
3424
+ `);
3425
+ },
3426
+ kv(pairs, opts) {
3427
+ const pad = opts?.padTo ?? Math.max(...pairs.map(([k]) => k.length)) + 2;
3428
+ for (const [k, v] of pairs) {
3429
+ OUT.write(`${INDENT}${dim(k.padEnd(pad, " "))}${v}
3430
+ `);
3431
+ }
3432
+ },
3433
+ code(snippet) {
3434
+ for (const line of snippet.split(`
3435
+ `)) {
3436
+ OUT.write(`${INDENT} ${cyan(line)}
3437
+ `);
3438
+ }
3439
+ },
3440
+ link(url) {
3441
+ OUT.write(`${INDENT}${clay(url)}
3442
+ `);
3443
+ },
3444
+ hint(msg) {
3445
+ OUT.write(`${INDENT}${dim(icons.arrow + " " + msg)}
3446
+ `);
3447
+ }
3448
+ };
3449
+ });
3450
+
3451
+ // src/constants/exit-codes.ts
3452
+ var EXIT;
3453
+ var init_exit_codes = __esm(() => {
3454
+ EXIT = {
3455
+ SUCCESS: 0,
3456
+ USER_CANCELLED: 1,
3457
+ AUTH_FAILED: 2,
3458
+ INVALID_ARGS: 3,
3459
+ NETWORK_ERROR: 4,
3460
+ NOT_FOUND: 5,
3461
+ ALREADY_EXISTS: 6,
3462
+ PERMISSION_DENIED: 7,
3463
+ INTERNAL_ERROR: 8,
3464
+ CLAUDE_MISSING: 9
3465
+ };
3466
+ });
3467
+
3468
+ // src/commands/grants.ts
3469
+ var exports_grants = {};
3470
+ __export(exports_grants, {
3471
+ runRevoke: () => runRevoke,
3472
+ runGrants: () => runGrants,
3473
+ runGrant: () => runGrant,
3474
+ runBlock: () => runBlock,
3475
+ isAllowed: () => isAllowed
3476
+ });
3477
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
3478
+ import { homedir as homedir2 } from "node:os";
3479
+ import { join as join2 } from "node:path";
3480
+ function readGrants() {
3481
+ if (!existsSync2(GRANT_FILE))
3482
+ return {};
3483
+ try {
3484
+ return JSON.parse(readFileSync2(GRANT_FILE, "utf-8"));
3485
+ } catch {
3486
+ return {};
3487
+ }
3488
+ }
3489
+ function writeGrants(g) {
3490
+ const dir = join2(homedir2(), ".claudemesh");
3491
+ if (!existsSync2(dir))
3492
+ mkdirSync2(dir, { recursive: true });
3493
+ writeFileSync2(GRANT_FILE, JSON.stringify(g, null, 2), { mode: 384 });
3494
+ }
3495
+ function resolveCaps(input) {
3496
+ if (input.includes("all"))
3497
+ return [...ALL_CAPS];
3498
+ return input.filter((c) => ALL_CAPS.includes(c));
3499
+ }
3500
+ async function resolvePeer(meshSlug, name) {
3501
+ return await withMesh({ meshSlug }, async (client) => {
3502
+ const peers = await client.listPeers();
3503
+ const match = peers.find((p) => p.displayName === name || p.pubkey === name || p.pubkey.startsWith(name));
3504
+ return match ? { displayName: match.displayName, pubkey: match.pubkey } : null;
3505
+ });
3506
+ }
3507
+ function pickMesh2(slug) {
3508
+ const cfg = readConfig();
3509
+ if (slug)
3510
+ return cfg.meshes.find((m) => m.slug === slug) ? slug : null;
3511
+ return cfg.meshes[0]?.slug ?? null;
3512
+ }
3513
+ async function runGrant(peer, caps, opts = {}) {
3514
+ if (!peer || caps.length === 0) {
3515
+ render.err("Usage: claudemesh grant <peer> <capability...>");
3516
+ render.hint(`Capabilities: ${ALL_CAPS.join(", ")}, all`);
3517
+ return EXIT.INVALID_ARGS;
3518
+ }
3519
+ const mesh = pickMesh2(opts.mesh);
3520
+ if (!mesh) {
3521
+ render.err("No matching mesh — join one first.");
3522
+ return EXIT.NOT_FOUND;
3523
+ }
3524
+ const resolved = await resolvePeer(mesh, peer);
3525
+ if (!resolved) {
3526
+ render.err(`Peer "${peer}" not found on ${mesh}.`);
3527
+ return EXIT.NOT_FOUND;
3528
+ }
3529
+ const wanted = resolveCaps(caps);
3530
+ if (wanted.length === 0) {
3531
+ render.err(`Unknown capabilities: ${caps.join(", ")}`);
3532
+ return EXIT.INVALID_ARGS;
3533
+ }
3534
+ const store = readGrants();
3535
+ const meshGrants = store[mesh] ?? {};
3536
+ const existing = meshGrants[resolved.pubkey] ?? DEFAULT_CAPS.slice();
3537
+ const merged = Array.from(new Set([...existing, ...wanted]));
3538
+ meshGrants[resolved.pubkey] = merged;
3539
+ store[mesh] = meshGrants;
3540
+ writeGrants(store);
3541
+ render.ok(`Granted ${wanted.join(", ")} to ${resolved.displayName} on ${mesh}.`);
3542
+ render.kv([["now", merged.join(", ")]]);
3543
+ return EXIT.SUCCESS;
3544
+ }
3545
+ async function runRevoke(peer, caps, opts = {}) {
3546
+ if (!peer || caps.length === 0) {
3547
+ render.err("Usage: claudemesh revoke <peer> <capability...>");
3548
+ return EXIT.INVALID_ARGS;
3549
+ }
3550
+ const mesh = pickMesh2(opts.mesh);
3551
+ if (!mesh) {
3552
+ render.err("No matching mesh.");
3553
+ return EXIT.NOT_FOUND;
3554
+ }
3555
+ const resolved = await resolvePeer(mesh, peer);
3556
+ if (!resolved) {
3557
+ render.err(`Peer "${peer}" not found on ${mesh}.`);
3558
+ return EXIT.NOT_FOUND;
3559
+ }
3560
+ const wanted = caps.includes("all") ? ALL_CAPS.slice() : resolveCaps(caps);
3561
+ const store = readGrants();
3562
+ const meshGrants = store[mesh] ?? {};
3563
+ const existing = meshGrants[resolved.pubkey] ?? DEFAULT_CAPS.slice();
3564
+ const after = existing.filter((c) => !wanted.includes(c));
3565
+ meshGrants[resolved.pubkey] = after;
3566
+ store[mesh] = meshGrants;
3567
+ writeGrants(store);
3568
+ render.ok(`Revoked ${wanted.join(", ")} from ${resolved.displayName} on ${mesh}.`);
3569
+ render.kv([["now", after.length ? after.join(", ") : "(none)"]]);
3570
+ return EXIT.SUCCESS;
3571
+ }
3572
+ async function runBlock(peer, opts = {}) {
3573
+ if (!peer) {
3574
+ render.err("Usage: claudemesh block <peer>");
3575
+ return EXIT.INVALID_ARGS;
3576
+ }
3577
+ const mesh = pickMesh2(opts.mesh);
3578
+ if (!mesh) {
3579
+ render.err("No matching mesh.");
3580
+ return EXIT.NOT_FOUND;
3581
+ }
3582
+ const resolved = await resolvePeer(mesh, peer);
3583
+ if (!resolved) {
3584
+ render.err(`Peer "${peer}" not found on ${mesh}.`);
3585
+ return EXIT.NOT_FOUND;
3586
+ }
3587
+ const store = readGrants();
3588
+ const meshGrants = store[mesh] ?? {};
3589
+ meshGrants[resolved.pubkey] = [];
3590
+ store[mesh] = meshGrants;
3591
+ writeGrants(store);
3592
+ render.ok(`Blocked ${resolved.displayName} on ${mesh} (all capabilities revoked).`);
3593
+ render.hint(`Undo with: claudemesh grant ${resolved.displayName} all --mesh ${mesh}`);
3594
+ return EXIT.SUCCESS;
3595
+ }
3596
+ async function runGrants(opts = {}) {
3597
+ const mesh = pickMesh2(opts.mesh);
3598
+ if (!mesh) {
3599
+ render.err("No matching mesh.");
3600
+ return EXIT.NOT_FOUND;
3601
+ }
3602
+ const store = readGrants();
3603
+ const meshGrants = store[mesh] ?? {};
3604
+ if (opts.json) {
3605
+ console.log(JSON.stringify({ schema_version: "1.0", mesh, grants: meshGrants }, null, 2));
3606
+ return EXIT.SUCCESS;
3607
+ }
3608
+ render.section(`grants on ${mesh}`);
3609
+ const peerPubkeys = Object.keys(meshGrants);
3610
+ if (peerPubkeys.length === 0) {
3611
+ render.info("(no overrides — all peers use default caps: " + DEFAULT_CAPS.join(", ") + ")");
3612
+ return EXIT.SUCCESS;
3613
+ }
3614
+ await withMesh({ meshSlug: mesh }, async (client) => {
3615
+ const peers = await client.listPeers();
3616
+ const byPk = new Map(peers.map((p) => [p.pubkey, p.displayName]));
3617
+ for (const [pk, caps] of Object.entries(meshGrants)) {
3618
+ const name = byPk.get(pk) ?? `${pk.slice(0, 10)}…`;
3619
+ render.kv([[name, caps.length ? caps.join(", ") : "(blocked)"]]);
3620
+ }
3621
+ });
3622
+ return EXIT.SUCCESS;
3623
+ }
3624
+ function isAllowed(meshSlug, peerPubkey, cap) {
3625
+ const store = readGrants();
3626
+ const entry = store[meshSlug]?.[peerPubkey];
3627
+ if (entry === undefined)
3628
+ return DEFAULT_CAPS.includes(cap);
3629
+ return entry.includes(cap);
3630
+ }
3631
+ var ALL_CAPS, DEFAULT_CAPS, GRANT_FILE;
3632
+ var init_grants = __esm(() => {
3633
+ init_facade();
3634
+ init_connect();
3635
+ init_render();
3636
+ init_exit_codes();
3637
+ ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
3638
+ DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
3639
+ GRANT_FILE = join2(homedir2(), ".claudemesh", "grants.json");
3640
+ });
3641
+
3289
3642
  // src/mcp/server.ts
3290
3643
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3291
3644
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
@@ -3710,9 +4063,16 @@ ${manifest.allowed_tools.map((t) => ` - ${t}`).join(`
3710
4063
  if (clients2.length === 0)
3711
4064
  return text(mesh_slug ? `list_peers: no joined mesh "${mesh_slug}"` : "list_peers: no joined meshes", true);
3712
4065
  const sections = [];
4066
+ const statusCache = {};
3713
4067
  for (const c of clients2) {
3714
4068
  const peers = await c.listPeers();
3715
4069
  const header = `## ${c.meshSlug} (${c.status}, mesh ${c.meshId.slice(0, 8)}…)`;
4070
+ statusCache[c.meshSlug] = {
4071
+ total: peers.length,
4072
+ online: peers.filter((p) => p.status !== "offline").length,
4073
+ updatedAt: new Date().toISOString(),
4074
+ you: process.env.CLAUDEMESH_DISPLAY_NAME ?? undefined
4075
+ };
3716
4076
  if (peers.length === 0) {
3717
4077
  sections.push(`${header}
3718
4078
  No peers connected.`);
@@ -3741,6 +4101,15 @@ ${peerLines.join(`
3741
4101
  `)}`);
3742
4102
  }
3743
4103
  }
4104
+ try {
4105
+ const { writeFileSync: writeFileSync3, mkdirSync: mkdirSync3, existsSync: existsSync3 } = await import("node:fs");
4106
+ const { join: joinPath } = await import("node:path");
4107
+ const { homedir: homedir3 } = await import("node:os");
4108
+ const dir = joinPath(homedir3(), ".claudemesh");
4109
+ if (!existsSync3(dir))
4110
+ mkdirSync3(dir, { recursive: true });
4111
+ writeFileSync3(joinPath(dir, "peer-cache.json"), JSON.stringify(statusCache));
4112
+ } catch {}
3744
4113
  return text(sections.join(`
3745
4114
 
3746
4115
  `));
@@ -3762,8 +4131,8 @@ ${peerLines.join(`
3762
4131
  return text(`Message ${id} not found or timed out.`);
3763
4132
  const recipientLines = result.recipients.map((r) => ` - ${r.name} (${r.pubkey.slice(0, 12)}…): ${r.status}`);
3764
4133
  return text(`Message ${id.slice(0, 12)}… → ${result.targetSpec}
3765
- ` + `Delivered: ${result.delivered}${result.deliveredAt ? ` at ${result.deliveredAt}` : ""}
3766
- ` + `Recipients:
4134
+ Delivered: ${result.delivered}${result.deliveredAt ? ` at ${result.deliveredAt}` : ""}
4135
+ Recipients:
3767
4136
  ${recipientLines.join(`
3768
4137
  `)}`);
3769
4138
  }
@@ -3981,23 +4350,23 @@ ${lines.join(`
3981
4350
  const { path: filePath, name: fileName, tags, to: fileTo } = args ?? {};
3982
4351
  if (!filePath)
3983
4352
  return text("share_file: `path` required", true);
3984
- const { existsSync: existsSync2 } = await import("node:fs");
3985
- if (!existsSync2(filePath))
4353
+ const { existsSync: existsSync3 } = await import("node:fs");
4354
+ if (!existsSync3(filePath))
3986
4355
  return text(`share_file: file not found: ${filePath}`, true);
3987
4356
  const client = allClients()[0];
3988
4357
  if (!client)
3989
4358
  return text("share_file: not connected", true);
3990
4359
  if (fileTo) {
3991
4360
  const { encryptFile: encryptFile2, sealKeyForPeer: sealKeyForPeer2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
3992
- const { readFileSync: readFileSync2, writeFileSync: writeFileSync2, mkdtempSync, unlinkSync, rmdirSync } = await import("node:fs");
4361
+ const { readFileSync: readFileSync3, writeFileSync: writeFileSync3, mkdtempSync, unlinkSync, rmdirSync } = await import("node:fs");
3993
4362
  const { tmpdir } = await import("node:os");
3994
- const { join: join2, basename } = await import("node:path");
4363
+ const { join: join3, basename } = await import("node:path");
3995
4364
  const peers = await client.listPeers();
3996
4365
  const targetPeer = peers.find((p) => p.pubkey === fileTo || p.displayName === fileTo);
3997
4366
  if (!targetPeer) {
3998
4367
  return text(`share_file: peer not found: ${fileTo}`, true);
3999
4368
  }
4000
- const plaintext = readFileSync2(filePath);
4369
+ const plaintext = readFileSync3(filePath);
4001
4370
  const { ciphertext, nonce, key } = await encryptFile2(new Uint8Array(plaintext));
4002
4371
  const sealedForTarget = await sealKeyForPeer2(key, targetPeer.pubkey);
4003
4372
  const myPubkey = client.getSessionPubkey();
@@ -4014,9 +4383,9 @@ ${lines.join(`
4014
4383
  combined.set(ciphertext, nonceBytes.length);
4015
4384
  const rawName = fileName ?? basename(filePath);
4016
4385
  const baseName = basename(rawName).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 255);
4017
- const tmpDir = mkdtempSync(join2(tmpdir(), "cm-"));
4018
- const tmpPath = join2(tmpDir, baseName);
4019
- writeFileSync2(tmpPath, combined);
4386
+ const tmpDir = mkdtempSync(join3(tmpdir(), "cm-"));
4387
+ const tmpPath = join3(tmpDir, baseName);
4388
+ writeFileSync3(tmpPath, combined);
4020
4389
  try {
4021
4390
  const fileId = await client.uploadFile(tmpPath, client.meshId, client.meshSlug, {
4022
4391
  name: baseName,
@@ -4091,10 +4460,10 @@ ${lines.join(`
4091
4460
  const plaintext = await decryptFile2(ciphertext, nonce, kf);
4092
4461
  if (!plaintext)
4093
4462
  return text(genericErr, true);
4094
- const { writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = await import("node:fs");
4463
+ const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync4 } = await import("node:fs");
4095
4464
  const { dirname: dirname2 } = await import("node:path");
4096
- mkdirSync3(dirname2(save_to), { recursive: true });
4097
- writeFileSync3(save_to, plaintext);
4465
+ mkdirSync4(dirname2(save_to), { recursive: true });
4466
+ writeFileSync4(save_to, plaintext);
4098
4467
  return text(`Downloaded and decrypted: ${result.name} → ${save_to}`);
4099
4468
  }
4100
4469
  let res = await fetch(result.url, { signal: AbortSignal.timeout(1e4) }).catch(() => null);
@@ -4104,10 +4473,10 @@ ${lines.join(`
4104
4473
  }
4105
4474
  if (!res.ok)
4106
4475
  return text(`get_file: download failed (${res.status})`, true);
4107
- const { writeFileSync: writeFileSync2, mkdirSync: mkdirSync2 } = await import("node:fs");
4476
+ const { writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = await import("node:fs");
4108
4477
  const { dirname } = await import("node:path");
4109
- mkdirSync2(dirname(save_to), { recursive: true });
4110
- writeFileSync2(save_to, Buffer.from(await res.arrayBuffer()));
4478
+ mkdirSync3(dirname(save_to), { recursive: true });
4479
+ writeFileSync3(save_to, Buffer.from(await res.arrayBuffer()));
4111
4480
  return text(`Downloaded: ${result.name} → ${save_to}`);
4112
4481
  }
4113
4482
  case "list_files": {
@@ -4865,10 +5234,10 @@ ${lines.join(`
4865
5234
  const entryType = vType ?? "env";
4866
5235
  let plaintextBytes;
4867
5236
  if (entryType === "file") {
4868
- const { existsSync: existsSync2, readFileSync: readFileSync2 } = await import("node:fs");
4869
- if (!existsSync2(value))
5237
+ const { existsSync: existsSync3, readFileSync: readFileSync3 } = await import("node:fs");
5238
+ if (!existsSync3(value))
4870
5239
  return text(`vault_set: file not found: ${value}`, true);
4871
- plaintextBytes = new Uint8Array(readFileSync2(value));
5240
+ plaintextBytes = new Uint8Array(readFileSync3(value));
4872
5241
  } else {
4873
5242
  plaintextBytes = new TextEncoder().encode(value);
4874
5243
  }
@@ -5196,6 +5565,17 @@ ${lines.join(`
5196
5565
  }
5197
5566
  const fromPubkey = msg.senderPubkey || "";
5198
5567
  const fromName = fromPubkey ? await resolvePeerName(client, fromPubkey) : "unknown";
5568
+ if (fromPubkey) {
5569
+ try {
5570
+ const { isAllowed: isAllowed2 } = await Promise.resolve().then(() => (init_grants(), exports_grants));
5571
+ const kindCap = msg.kind === "broadcast" ? "broadcast" : "dm";
5572
+ if (!isAllowed2(client.meshSlug, fromPubkey, kindCap)) {
5573
+ process.stderr.write(`[claudemesh] dropped ${kindCap} from ${fromName} (not granted)
5574
+ `);
5575
+ return;
5576
+ }
5577
+ } catch {}
5578
+ }
5199
5579
  if (messageMode === "inbox") {
5200
5580
  try {
5201
5581
  await server.notification({
@@ -5208,7 +5588,10 @@ ${lines.join(`
5208
5588
  } catch {}
5209
5589
  return;
5210
5590
  }
5211
- const content = msg.plaintext ?? decryptFailedWarning(fromPubkey);
5591
+ const body = msg.plaintext ?? decryptFailedWarning(fromPubkey);
5592
+ const prioBadge = msg.priority === "now" ? "[URGENT] " : msg.priority === "low" ? "[low] " : "";
5593
+ const kindBadge = msg.kind === "broadcast" ? " (broadcast)" : "";
5594
+ const content = `${prioBadge}${fromName}${kindBadge}: ${body}`;
5212
5595
  try {
5213
5596
  await server.notification({
5214
5597
  method: "notifications/claude/channel",
@@ -5227,7 +5610,7 @@ ${lines.join(`
5227
5610
  }
5228
5611
  }
5229
5612
  });
5230
- process.stderr.write(`[claudemesh] pushed: from=${fromName} content=${content.slice(0, 60)}
5613
+ process.stderr.write(`[claudemesh] pushed: from=${fromName} content=${body.slice(0, 60)}
5231
5614
  `);
5232
5615
  } catch (pushErr) {
5233
5616
  process.stderr.write(`[claudemesh] push FAILED: ${pushErr}
@@ -5421,4 +5804,4 @@ startMcpServer().catch((err) => {
5421
5804
  process.exit(1);
5422
5805
  });
5423
5806
 
5424
- //# debugId=F4442514279DCE8564756E2164756E21
5807
+ //# debugId=89A595C2EEA0442364756E2164756E21