claudemesh-cli 1.18.0 → 1.19.1

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.
@@ -88,7 +88,7 @@ __export(exports_urls, {
88
88
  VERSION: () => VERSION,
89
89
  URLS: () => URLS
90
90
  });
91
- var URLS, VERSION = "1.18.0", env;
91
+ var URLS, VERSION = "1.19.1", env;
92
92
  var init_urls = __esm(() => {
93
93
  URLS = {
94
94
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -416,7 +416,7 @@ async function createMesh(token, body) {
416
416
  }
417
417
  async function renameMesh(token, slug, newName) {
418
418
  return request({
419
- path: `/api/my/meshes/${slug}`,
419
+ path: `/api/cli/meshes/${slug}`,
420
420
  method: "PATCH",
421
421
  body: { name: newName },
422
422
  token
@@ -5135,6 +5135,14 @@ __export(exports_rename, {
5135
5135
  rename: () => rename
5136
5136
  });
5137
5137
  async function rename(slug, newName) {
5138
+ const auth = getStoredToken();
5139
+ if (!auth) {
5140
+ console.error(` ${icons.cross} Renaming a mesh requires a claudemesh.com account session.`);
5141
+ console.error(` ${dim("Joining via invite signs you in to the mesh, not to a web account.")}`);
5142
+ console.error(` ${dim("Run")} ${bold("claudemesh login")} ${dim("first, then retry, or rename from the dashboard:")}`);
5143
+ console.error(` https://claudemesh.com/dashboard`);
5144
+ return EXIT.AUTH_FAILED;
5145
+ }
5138
5146
  try {
5139
5147
  await renameMesh2(slug, newName);
5140
5148
  console.log(` ${green(icons.check)} Renamed "${slug}" to "${newName}"`);
@@ -5146,6 +5154,7 @@ async function rename(slug, newName) {
5146
5154
  }
5147
5155
  var init_rename2 = __esm(() => {
5148
5156
  init_facade10();
5157
+ init_facade6();
5149
5158
  init_styles();
5150
5159
  init_exit_codes();
5151
5160
  });
@@ -11578,12 +11587,30 @@ claudemesh webhook delete <name>
11578
11587
  ### \`file\` — shared mesh files
11579
11588
 
11580
11589
  \`\`\`bash
11581
- claudemesh file list [search-query] # list files
11582
- claudemesh file status <file-id> # who has accessed
11590
+ claudemesh file share <path> # upload to mesh (visible to all members)
11591
+ claudemesh file share <path> --to <peer> # share with one peer (same-host fast path if co-located)
11592
+ claudemesh file share <path> --to <peer> --message "see line 42"
11593
+ claudemesh file share <path> --upload # force network upload, skip same-host fast path
11594
+ claudemesh file get <file-id> # download by id (saves to ./<name>)
11595
+ claudemesh file get <file-id> --out /tmp/foo.bin # download to explicit path
11596
+ claudemesh file list [search-query] # browse mesh files
11597
+ claudemesh file status <file-id> # who has accessed
11583
11598
  claudemesh file delete <file-id>
11584
- # Upload + retrieval currently via MCP \`share_file\` / \`get_file\` (binary streams)
11585
11599
  \`\`\`
11586
11600
 
11601
+ **Same-host fast path** (v0.6.0+): when \`--to <peer>\` resolves to a session
11602
+ running on the same hostname as you, \`claudemesh file share\` skips MinIO
11603
+ entirely and sends a DM with the absolute filepath. The receiver reads it
11604
+ directly off disk. No 50 MB cap, no upload latency, nothing in the bucket.
11605
+ Falls back to encrypted upload when the peer is remote, or always when
11606
+ \`--upload\` is set. Routes by session pubkey, so sibling sessions of the
11607
+ same member work without tripping the self-DM guard.
11608
+
11609
+ **Network upload cap**: 50 MB. Same-host fast path has no cap.
11610
+
11611
+ **\`--to\` accepts**: display name, member pubkey, session pubkey, or any
11612
+ ≥8-char prefix of a pubkey. Prefer pubkey when multiple peers share a name.
11613
+
11587
11614
  ### \`mesh-mcp\` — call MCP servers other peers deployed to the mesh
11588
11615
 
11589
11616
  \`\`\`bash
@@ -11729,6 +11756,129 @@ var init_skill = __esm(() => {
11729
11756
  init_exit_codes();
11730
11757
  });
11731
11758
 
11759
+ // src/commands/file.ts
11760
+ var exports_file = {};
11761
+ __export(exports_file, {
11762
+ runFileShare: () => runFileShare,
11763
+ runFileGet: () => runFileGet
11764
+ });
11765
+ import { hostname as osHostname } from "node:os";
11766
+ import { resolve as resolvePath, basename, dirname as dirname6 } from "node:path";
11767
+ import { statSync as statSync6, existsSync as existsSync20, writeFileSync as writeFileSync11, mkdirSync as mkdirSync7 } from "node:fs";
11768
+ function emitJson2(data) {
11769
+ console.log(JSON.stringify(data, null, 2));
11770
+ }
11771
+ function formatSize(bytes) {
11772
+ if (bytes < 1024)
11773
+ return `${bytes} B`;
11774
+ if (bytes < 1024 * 1024)
11775
+ return `${(bytes / 1024).toFixed(1)} KB`;
11776
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
11777
+ }
11778
+ async function runFileShare(filePath, opts) {
11779
+ if (!filePath) {
11780
+ render.err('Usage: claudemesh file share <path> [--to <peer>] [--tags a,b] [--message "..."] [--upload]');
11781
+ return EXIT.INVALID_ARGS;
11782
+ }
11783
+ const absPath = resolvePath(filePath);
11784
+ if (!existsSync20(absPath)) {
11785
+ render.err(`File not found: ${absPath}`);
11786
+ return EXIT.INVALID_ARGS;
11787
+ }
11788
+ const stat = statSync6(absPath);
11789
+ if (!stat.isFile()) {
11790
+ render.err(`Not a regular file: ${absPath}`);
11791
+ return EXIT.INVALID_ARGS;
11792
+ }
11793
+ const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
11794
+ return await withMesh({ meshSlug: opts.mesh ?? null }, async (client, mesh) => {
11795
+ if (opts.to && !opts.upload) {
11796
+ const peers = await client.listPeers();
11797
+ const myHost = osHostname();
11798
+ const target = peers.find((p) => {
11799
+ if (!p.hostname || p.hostname !== myHost)
11800
+ return false;
11801
+ return p.displayName === opts.to || p.memberPubkey === opts.to || p.pubkey === opts.to || typeof opts.to === "string" && opts.to.length >= 8 && p.pubkey.startsWith(opts.to);
11802
+ });
11803
+ if (target) {
11804
+ const note = opts.message ? `
11805
+ ${opts.message}` : "";
11806
+ const body = `\uD83D\uDCCE file://${absPath} (${formatSize(stat.size)} · same host, no upload)${note}`;
11807
+ const result = await client.send(target.pubkey, body, "next");
11808
+ if (!result.ok) {
11809
+ render.err(`Send failed: ${result.error ?? "unknown"}`);
11810
+ return EXIT.NETWORK_ERROR;
11811
+ }
11812
+ if (opts.json) {
11813
+ emitJson2({ mode: "local", path: absPath, to: target.displayName, hostname: myHost, sizeBytes: stat.size });
11814
+ } else {
11815
+ render.ok(`shared ${bold(basename(absPath))} ${dim(`(${formatSize(stat.size)})`)} → ${green(target.displayName)} ${dim("[same host, no upload]")}`);
11816
+ }
11817
+ return EXIT.SUCCESS;
11818
+ }
11819
+ }
11820
+ const fileId = await client.uploadFile(absPath, mesh.meshId, mesh.memberId, {
11821
+ name: basename(absPath),
11822
+ tags,
11823
+ persistent: true,
11824
+ targetSpec: opts.to
11825
+ });
11826
+ if (opts.to) {
11827
+ const note = opts.message ? `
11828
+ ${opts.message}` : "";
11829
+ const body = `\uD83D\uDCCE ${basename(absPath)} (${formatSize(stat.size)})
11830
+ claudemesh file get ${fileId}${note}`;
11831
+ await client.send(opts.to, body, "next");
11832
+ }
11833
+ if (opts.json) {
11834
+ emitJson2({ mode: "upload", fileId, name: basename(absPath), sizeBytes: stat.size, to: opts.to ?? null });
11835
+ } else {
11836
+ render.ok(`uploaded ${bold(basename(absPath))} ${dim(`(${formatSize(stat.size)})`)} ${dim("· id=" + fileId.slice(0, 12))}`);
11837
+ if (opts.to)
11838
+ render.info(dim(` notified ${opts.to}`));
11839
+ else
11840
+ render.info(dim(` retrieve: claudemesh file get ${fileId}`));
11841
+ }
11842
+ return EXIT.SUCCESS;
11843
+ });
11844
+ }
11845
+ async function runFileGet(fileId, opts) {
11846
+ if (!fileId) {
11847
+ render.err("Usage: claudemesh file get <file-id> [--out <path>]");
11848
+ return EXIT.INVALID_ARGS;
11849
+ }
11850
+ return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
11851
+ const meta = await client.getFile(fileId);
11852
+ if (!meta) {
11853
+ render.err(`File not found or not accessible: ${fileId}`);
11854
+ return EXIT.NOT_FOUND;
11855
+ }
11856
+ const res = await fetch(meta.url, { signal: AbortSignal.timeout(60000) });
11857
+ if (!res.ok) {
11858
+ render.err(`Download failed: HTTP ${res.status}`);
11859
+ return EXIT.NETWORK_ERROR;
11860
+ }
11861
+ const buf = Buffer.from(await res.arrayBuffer());
11862
+ const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
11863
+ mkdirSync7(dirname6(outPath), { recursive: true });
11864
+ writeFileSync11(outPath, buf);
11865
+ if (opts.json) {
11866
+ emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
11867
+ } else {
11868
+ render.ok(`saved ${bold(meta.name)} ${dim(`(${formatSize(buf.length)})`)} → ${dim(outPath)}`);
11869
+ }
11870
+ return EXIT.SUCCESS;
11871
+ });
11872
+ }
11873
+ var MAX_FILE_BYTES;
11874
+ var init_file = __esm(() => {
11875
+ init_connect();
11876
+ init_render();
11877
+ init_styles();
11878
+ init_exit_codes();
11879
+ MAX_FILE_BYTES = 50 * 1024 * 1024;
11880
+ });
11881
+
11732
11882
  // ../../packages/sdk/dist/crypto.js
11733
11883
  var require_crypto = __commonJS((exports) => {
11734
11884
  var __importDefault = exports && exports.__importDefault || function(mod) {
@@ -12321,7 +12471,7 @@ __export(exports_bridge, {
12321
12471
  runBridge: () => runBridge,
12322
12472
  bridgeConfigTemplate: () => bridgeConfigTemplate
12323
12473
  });
12324
- import { readFileSync as readFileSync14, existsSync as existsSync20 } from "node:fs";
12474
+ import { readFileSync as readFileSync14, existsSync as existsSync21 } from "node:fs";
12325
12475
  function parseConfig(text) {
12326
12476
  const trimmed = text.trim();
12327
12477
  if (trimmed.startsWith("{"))
@@ -12365,7 +12515,7 @@ async function runBridge(configPath) {
12365
12515
  render.err("Usage: claudemesh bridge run <config.yaml>");
12366
12516
  return EXIT.INVALID_ARGS;
12367
12517
  }
12368
- if (!existsSync20(configPath)) {
12518
+ if (!existsSync21(configPath)) {
12369
12519
  render.err(`config file not found: ${configPath}`);
12370
12520
  return EXIT.NOT_FOUND;
12371
12521
  }
@@ -13342,7 +13492,7 @@ var init_definitions = __esm(() => {
13342
13492
 
13343
13493
  // src/services/bridge/server.ts
13344
13494
  import { createServer as createServer2 } from "node:net";
13345
- import { mkdirSync as mkdirSync7, unlinkSync as unlinkSync2, existsSync as existsSync21, chmodSync as chmodSync5 } from "node:fs";
13495
+ import { mkdirSync as mkdirSync8, unlinkSync as unlinkSync2, existsSync as existsSync22, chmodSync as chmodSync5 } from "node:fs";
13346
13496
  async function resolveTarget2(client, to) {
13347
13497
  if (to.startsWith("@") || to === "*" || /^[0-9a-f]{64}$/i.test(to)) {
13348
13498
  return { ok: true, spec: to };
@@ -13456,10 +13606,10 @@ function handleConnection(socket, client) {
13456
13606
  function startBridgeServer(client) {
13457
13607
  const path = socketPath(client.meshSlug);
13458
13608
  const dir = socketDir();
13459
- if (!existsSync21(dir)) {
13460
- mkdirSync7(dir, { recursive: true, mode: 448 });
13609
+ if (!existsSync22(dir)) {
13610
+ mkdirSync8(dir, { recursive: true, mode: 448 });
13461
13611
  }
13462
- if (existsSync21(path)) {
13612
+ if (existsSync22(path)) {
13463
13613
  try {
13464
13614
  unlinkSync2(path);
13465
13615
  } catch {}
@@ -13610,11 +13760,11 @@ If the channel meta contains \`subtype: reminder\`, this is a scheduled reminder
13610
13760
  | remember(content, tags?) | Store persistent knowledge with optional tags. |
13611
13761
  | recall(query) | Full-text search over mesh memory. |
13612
13762
  | forget(id) | Soft-delete a memory entry. |
13613
- | share_file(path, name?, tags?) | Share a persistent file with the mesh. |
13614
- | get_file(id, save_to) | Download a shared file to a local path. |
13615
- | list_files(query?, from?) | Find files shared in the mesh. |
13616
- | file_status(id) | Check who has accessed a file. |
13617
- | delete_file(id) | Remove a shared file from the mesh. |
13763
+ | claudemesh file share <path> [--to peer] [--tags a,b] | Share a file with the mesh, or DM it to a specific peer. Same-host fast path: when --to matches a peer on this machine, sends an absolute filepath instead of uploading (no MinIO round-trip). |
13764
+ | claudemesh file get <id> [--out path] | Download a shared file by id. |
13765
+ | claudemesh file list [query] | Find files shared in the mesh. |
13766
+ | claudemesh file status <id> | Check who has accessed a file. |
13767
+ | claudemesh file delete <id> | Remove a shared file from the mesh. |
13618
13768
  | vector_store(collection, text, metadata?) | Store embedding in per-mesh Qdrant collection. |
13619
13769
  | vector_search(collection, query, limit?) | Semantic search over stored embeddings. |
13620
13770
  | vector_delete(collection, id) | Remove an embedding. |
@@ -14961,6 +15111,8 @@ Platform
14961
15111
  claudemesh vault list|delete encrypted secrets
14962
15112
  claudemesh watch list|remove URL change watchers
14963
15113
  claudemesh webhook list|delete outbound HTTP triggers
15114
+ claudemesh file share <path> [--to peer] upload (or local-host fast path if --to matches)
15115
+ claudemesh file get <id> [--out path] download by id
14964
15116
  claudemesh file list|status|delete shared mesh files
14965
15117
  claudemesh mesh-mcp list|call|catalog deployed mesh-MCP servers
14966
15118
  claudemesh clock set|pause|resume mesh logical clock
@@ -15633,7 +15785,19 @@ async function main() {
15633
15785
  case "file": {
15634
15786
  const sub = positionals[0];
15635
15787
  const f = { mesh: flags.mesh, json: !!flags.json };
15636
- if (sub === "list") {
15788
+ if (sub === "share") {
15789
+ const { runFileShare: runFileShare2 } = await Promise.resolve().then(() => (init_file(), exports_file));
15790
+ process.exit(await runFileShare2(positionals[1] ?? "", {
15791
+ ...f,
15792
+ to: flags.to,
15793
+ tags: flags.tags,
15794
+ message: flags.message,
15795
+ upload: !!flags.upload
15796
+ }));
15797
+ } else if (sub === "get") {
15798
+ const { runFileGet: runFileGet2 } = await Promise.resolve().then(() => (init_file(), exports_file));
15799
+ process.exit(await runFileGet2(positionals[1] ?? "", { ...f, out: flags.out }));
15800
+ } else if (sub === "list") {
15637
15801
  const { runFileList: runFileList2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
15638
15802
  process.exit(await runFileList2({ ...f, query: positionals[1] }));
15639
15803
  } else if (sub === "status") {
@@ -15643,7 +15807,7 @@ async function main() {
15643
15807
  const { runFileDelete: runFileDelete2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
15644
15808
  process.exit(await runFileDelete2(positionals[1] ?? "", f));
15645
15809
  } else {
15646
- console.error("Usage: claudemesh file <list|status|delete>");
15810
+ console.error("Usage: claudemesh file <share|get|list|status|delete>");
15647
15811
  process.exit(EXIT.INVALID_ARGS);
15648
15812
  }
15649
15813
  break;
@@ -15925,4 +16089,4 @@ main().catch((err) => {
15925
16089
  process.exit(EXIT.INTERNAL_ERROR);
15926
16090
  });
15927
16091
 
15928
- //# debugId=4F6FEF2D8F81D25B64756E2164756E21
16092
+ //# debugId=3A1675403F5C48F564756E2164756E21