claudemesh-cli 1.0.0-alpha.27 → 1.0.0-alpha.29
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.
- package/dist/entrypoints/cli.js +6128 -3979
- package/dist/entrypoints/cli.js.map +48 -28
- package/dist/entrypoints/mcp.js +401 -20
- package/dist/entrypoints/mcp.js.map +9 -4
- package/package.json +3 -1
package/dist/entrypoints/mcp.js
CHANGED
|
@@ -15,6 +15,7 @@ var __toESM = (mod, isNodeMode, target) => {
|
|
|
15
15
|
});
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
|
+
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
18
19
|
var __export = (target, all) => {
|
|
19
20
|
for (var name in all)
|
|
20
21
|
__defProp(target, name, {
|
|
@@ -3285,6 +3286,359 @@ var init_facade3 = __esm(() => {
|
|
|
3285
3286
|
init_errors();
|
|
3286
3287
|
});
|
|
3287
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
|
+
|
|
3288
3642
|
// src/mcp/server.ts
|
|
3289
3643
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3290
3644
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -3709,9 +4063,16 @@ ${manifest.allowed_tools.map((t) => ` - ${t}`).join(`
|
|
|
3709
4063
|
if (clients2.length === 0)
|
|
3710
4064
|
return text(mesh_slug ? `list_peers: no joined mesh "${mesh_slug}"` : "list_peers: no joined meshes", true);
|
|
3711
4065
|
const sections = [];
|
|
4066
|
+
const statusCache = {};
|
|
3712
4067
|
for (const c of clients2) {
|
|
3713
4068
|
const peers = await c.listPeers();
|
|
3714
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
|
+
};
|
|
3715
4076
|
if (peers.length === 0) {
|
|
3716
4077
|
sections.push(`${header}
|
|
3717
4078
|
No peers connected.`);
|
|
@@ -3740,6 +4101,15 @@ ${peerLines.join(`
|
|
|
3740
4101
|
`)}`);
|
|
3741
4102
|
}
|
|
3742
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 {}
|
|
3743
4113
|
return text(sections.join(`
|
|
3744
4114
|
|
|
3745
4115
|
`));
|
|
@@ -3761,8 +4131,8 @@ ${peerLines.join(`
|
|
|
3761
4131
|
return text(`Message ${id} not found or timed out.`);
|
|
3762
4132
|
const recipientLines = result.recipients.map((r) => ` - ${r.name} (${r.pubkey.slice(0, 12)}…): ${r.status}`);
|
|
3763
4133
|
return text(`Message ${id.slice(0, 12)}… → ${result.targetSpec}
|
|
3764
|
-
|
|
3765
|
-
|
|
4134
|
+
Delivered: ${result.delivered}${result.deliveredAt ? ` at ${result.deliveredAt}` : ""}
|
|
4135
|
+
Recipients:
|
|
3766
4136
|
${recipientLines.join(`
|
|
3767
4137
|
`)}`);
|
|
3768
4138
|
}
|
|
@@ -3980,23 +4350,23 @@ ${lines.join(`
|
|
|
3980
4350
|
const { path: filePath, name: fileName, tags, to: fileTo } = args ?? {};
|
|
3981
4351
|
if (!filePath)
|
|
3982
4352
|
return text("share_file: `path` required", true);
|
|
3983
|
-
const { existsSync:
|
|
3984
|
-
if (!
|
|
4353
|
+
const { existsSync: existsSync3 } = await import("node:fs");
|
|
4354
|
+
if (!existsSync3(filePath))
|
|
3985
4355
|
return text(`share_file: file not found: ${filePath}`, true);
|
|
3986
4356
|
const client = allClients()[0];
|
|
3987
4357
|
if (!client)
|
|
3988
4358
|
return text("share_file: not connected", true);
|
|
3989
4359
|
if (fileTo) {
|
|
3990
4360
|
const { encryptFile: encryptFile2, sealKeyForPeer: sealKeyForPeer2 } = await Promise.resolve().then(() => (init_file_crypto(), exports_file_crypto));
|
|
3991
|
-
const { readFileSync:
|
|
4361
|
+
const { readFileSync: readFileSync3, writeFileSync: writeFileSync3, mkdtempSync, unlinkSync, rmdirSync } = await import("node:fs");
|
|
3992
4362
|
const { tmpdir } = await import("node:os");
|
|
3993
|
-
const { join:
|
|
4363
|
+
const { join: join3, basename } = await import("node:path");
|
|
3994
4364
|
const peers = await client.listPeers();
|
|
3995
4365
|
const targetPeer = peers.find((p) => p.pubkey === fileTo || p.displayName === fileTo);
|
|
3996
4366
|
if (!targetPeer) {
|
|
3997
4367
|
return text(`share_file: peer not found: ${fileTo}`, true);
|
|
3998
4368
|
}
|
|
3999
|
-
const plaintext =
|
|
4369
|
+
const plaintext = readFileSync3(filePath);
|
|
4000
4370
|
const { ciphertext, nonce, key } = await encryptFile2(new Uint8Array(plaintext));
|
|
4001
4371
|
const sealedForTarget = await sealKeyForPeer2(key, targetPeer.pubkey);
|
|
4002
4372
|
const myPubkey = client.getSessionPubkey();
|
|
@@ -4013,9 +4383,9 @@ ${lines.join(`
|
|
|
4013
4383
|
combined.set(ciphertext, nonceBytes.length);
|
|
4014
4384
|
const rawName = fileName ?? basename(filePath);
|
|
4015
4385
|
const baseName = basename(rawName).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 255);
|
|
4016
|
-
const tmpDir = mkdtempSync(
|
|
4017
|
-
const tmpPath =
|
|
4018
|
-
|
|
4386
|
+
const tmpDir = mkdtempSync(join3(tmpdir(), "cm-"));
|
|
4387
|
+
const tmpPath = join3(tmpDir, baseName);
|
|
4388
|
+
writeFileSync3(tmpPath, combined);
|
|
4019
4389
|
try {
|
|
4020
4390
|
const fileId = await client.uploadFile(tmpPath, client.meshId, client.meshSlug, {
|
|
4021
4391
|
name: baseName,
|
|
@@ -4090,10 +4460,10 @@ ${lines.join(`
|
|
|
4090
4460
|
const plaintext = await decryptFile2(ciphertext, nonce, kf);
|
|
4091
4461
|
if (!plaintext)
|
|
4092
4462
|
return text(genericErr, true);
|
|
4093
|
-
const { writeFileSync:
|
|
4463
|
+
const { writeFileSync: writeFileSync4, mkdirSync: mkdirSync4 } = await import("node:fs");
|
|
4094
4464
|
const { dirname: dirname2 } = await import("node:path");
|
|
4095
|
-
|
|
4096
|
-
|
|
4465
|
+
mkdirSync4(dirname2(save_to), { recursive: true });
|
|
4466
|
+
writeFileSync4(save_to, plaintext);
|
|
4097
4467
|
return text(`Downloaded and decrypted: ${result.name} → ${save_to}`);
|
|
4098
4468
|
}
|
|
4099
4469
|
let res = await fetch(result.url, { signal: AbortSignal.timeout(1e4) }).catch(() => null);
|
|
@@ -4103,10 +4473,10 @@ ${lines.join(`
|
|
|
4103
4473
|
}
|
|
4104
4474
|
if (!res.ok)
|
|
4105
4475
|
return text(`get_file: download failed (${res.status})`, true);
|
|
4106
|
-
const { writeFileSync:
|
|
4476
|
+
const { writeFileSync: writeFileSync3, mkdirSync: mkdirSync3 } = await import("node:fs");
|
|
4107
4477
|
const { dirname } = await import("node:path");
|
|
4108
|
-
|
|
4109
|
-
|
|
4478
|
+
mkdirSync3(dirname(save_to), { recursive: true });
|
|
4479
|
+
writeFileSync3(save_to, Buffer.from(await res.arrayBuffer()));
|
|
4110
4480
|
return text(`Downloaded: ${result.name} → ${save_to}`);
|
|
4111
4481
|
}
|
|
4112
4482
|
case "list_files": {
|
|
@@ -4864,10 +5234,10 @@ ${lines.join(`
|
|
|
4864
5234
|
const entryType = vType ?? "env";
|
|
4865
5235
|
let plaintextBytes;
|
|
4866
5236
|
if (entryType === "file") {
|
|
4867
|
-
const { existsSync:
|
|
4868
|
-
if (!
|
|
5237
|
+
const { existsSync: existsSync3, readFileSync: readFileSync3 } = await import("node:fs");
|
|
5238
|
+
if (!existsSync3(value))
|
|
4869
5239
|
return text(`vault_set: file not found: ${value}`, true);
|
|
4870
|
-
plaintextBytes = new Uint8Array(
|
|
5240
|
+
plaintextBytes = new Uint8Array(readFileSync3(value));
|
|
4871
5241
|
} else {
|
|
4872
5242
|
plaintextBytes = new TextEncoder().encode(value);
|
|
4873
5243
|
}
|
|
@@ -5195,6 +5565,17 @@ ${lines.join(`
|
|
|
5195
5565
|
}
|
|
5196
5566
|
const fromPubkey = msg.senderPubkey || "";
|
|
5197
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
|
+
}
|
|
5198
5579
|
if (messageMode === "inbox") {
|
|
5199
5580
|
try {
|
|
5200
5581
|
await server.notification({
|
|
@@ -5420,4 +5801,4 @@ startMcpServer().catch((err) => {
|
|
|
5420
5801
|
process.exit(1);
|
|
5421
5802
|
});
|
|
5422
5803
|
|
|
5423
|
-
//# debugId=
|
|
5804
|
+
//# debugId=342A89449EA1CD7764756E2164756E21
|