claudemesh-cli 1.0.0-alpha.30 → 1.0.0-alpha.32

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.0.0-alpha.27", env;
91
+ var URLS, VERSION = "1.0.0-alpha.32", env;
92
92
  var init_urls = __esm(() => {
93
93
  URLS = {
94
94
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -6141,15 +6141,11 @@ __export(exports_peers, {
6141
6141
  runPeers: () => runPeers
6142
6142
  });
6143
6143
  async function runPeers(flags) {
6144
- const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
6145
- const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
6146
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
6147
- const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
6148
- const yellow2 = (s) => useColor ? `\x1B[33m${s}\x1B[39m` : s;
6149
6144
  const config = readConfig();
6150
6145
  const slugs = flags.mesh ? [flags.mesh] : config.meshes.map((m) => m.slug);
6151
6146
  if (slugs.length === 0) {
6152
- console.error("No meshes joined. Run `claudemesh join <url>` first.");
6147
+ render.err("No meshes joined.");
6148
+ render.hint("claudemesh <invite-url> # join + launch");
6153
6149
  process.exit(1);
6154
6150
  }
6155
6151
  const allJson = [];
@@ -6161,44 +6157,43 @@ async function runPeers(flags) {
6161
6157
  allJson.push({ mesh: mesh.slug, peers });
6162
6158
  return;
6163
6159
  }
6164
- console.log(bold2(`Peers on ${mesh.slug}`) + dim2(` (${peers.length})`));
6165
- console.log("");
6160
+ render.section(`peers on ${mesh.slug} (${peers.length})`);
6166
6161
  if (peers.length === 0) {
6167
- console.log(dim2(" No peers connected."));
6168
- } else {
6169
- for (const p of peers) {
6170
- const groups = p.groups.length ? " [" + p.groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
6171
- const statusIcon = p.status === "working" ? yellow2("") : green3("");
6172
- const name = bold2(p.displayName);
6173
- const meta = [];
6174
- if (p.peerType)
6175
- meta.push(p.peerType);
6176
- if (p.channel)
6177
- meta.push(p.channel);
6178
- if (p.model)
6179
- meta.push(p.model);
6180
- const metaStr = meta.length ? dim2(` (${meta.join(", ")})`) : "";
6181
- const cwdStr = p.cwd ? dim2(` cwd: ${p.cwd}`) : "";
6182
- const summary = p.summary ? dim2(` ${p.summary}`) : "";
6183
- console.log(` ${statusIcon} ${name}${groups}${metaStr}${summary}`);
6184
- if (cwdStr)
6185
- console.log(` ${cwdStr}`);
6186
- }
6162
+ render.info(dim(" (no peers connected)"));
6163
+ return;
6164
+ }
6165
+ for (const p of peers) {
6166
+ const groups = p.groups.length ? " [" + p.groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
6167
+ const statusDot = p.status === "working" ? yellow("●") : green("●");
6168
+ const name = bold(p.displayName);
6169
+ const meta = [];
6170
+ if (p.peerType)
6171
+ meta.push(p.peerType);
6172
+ if (p.channel)
6173
+ meta.push(p.channel);
6174
+ if (p.model)
6175
+ meta.push(p.model);
6176
+ const metaStr = meta.length ? dim(` (${meta.join(", ")})`) : "";
6177
+ const summary = p.summary ? dim(` ${p.summary}`) : "";
6178
+ render.info(`${statusDot} ${name}${groups}${metaStr}${summary}`);
6179
+ if (p.cwd)
6180
+ render.info(dim(` cwd: ${p.cwd}`));
6187
6181
  }
6188
- console.log("");
6189
6182
  });
6190
6183
  } catch (e) {
6191
- console.error(dim2(` Could not connect to ${slug}: ${e instanceof Error ? e.message : String(e)}`));
6192
- console.log("");
6184
+ render.err(`${slug}: ${e instanceof Error ? e.message : String(e)}`);
6193
6185
  }
6194
6186
  }
6195
6187
  if (flags.json) {
6196
- console.log(JSON.stringify(slugs.length === 1 ? allJson[0]?.peers : allJson, null, 2));
6188
+ process.stdout.write(JSON.stringify(slugs.length === 1 ? allJson[0]?.peers : allJson, null, 2) + `
6189
+ `);
6197
6190
  }
6198
6191
  }
6199
6192
  var init_peers = __esm(() => {
6200
6193
  init_connect();
6201
6194
  init_facade();
6195
+ init_render();
6196
+ init_styles();
6202
6197
  });
6203
6198
 
6204
6199
  // src/commands/send.ts
@@ -6238,42 +6233,40 @@ var exports_inbox = {};
6238
6233
  __export(exports_inbox, {
6239
6234
  runInbox: () => runInbox
6240
6235
  });
6241
- function formatMessage(msg, useColor) {
6242
- const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
6243
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
6236
+ function formatMessage(msg) {
6244
6237
  const text = msg.plaintext ?? `[encrypted: ${msg.ciphertext.slice(0, 32)}…]`;
6245
6238
  const from = msg.senderPubkey.slice(0, 8);
6246
6239
  const time = new Date(msg.createdAt).toLocaleTimeString();
6247
6240
  const kindTag = msg.kind === "direct" ? "→ direct" : msg.kind;
6248
- return ` ${bold2(from)} ${dim2(`[${kindTag}] ${time}`)}
6241
+ return ` ${bold(from)} ${dim(`[${kindTag}] ${time}`)}
6249
6242
  ${text}`;
6250
6243
  }
6251
6244
  async function runInbox(flags) {
6252
- const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
6253
- const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
6254
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
6255
6245
  const waitMs = (flags.wait ?? 1) * 1000;
6256
6246
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client, mesh) => {
6257
6247
  await new Promise((resolve) => setTimeout(resolve, waitMs));
6258
6248
  const messages = client.drainPushBuffer();
6259
6249
  if (flags.json) {
6260
- console.log(JSON.stringify(messages, null, 2));
6250
+ process.stdout.write(JSON.stringify(messages, null, 2) + `
6251
+ `);
6261
6252
  return;
6262
6253
  }
6263
6254
  if (messages.length === 0) {
6264
- console.log(dim2(`No messages on mesh "${mesh.slug}".`));
6255
+ render.info(dim(`No messages on mesh "${mesh.slug}".`));
6265
6256
  return;
6266
6257
  }
6267
- console.log(bold2(`Inbox — ${mesh.slug}`) + dim2(` (${messages.length} message${messages.length === 1 ? "" : "s"})`));
6268
- console.log("");
6258
+ render.section(`inbox — ${mesh.slug} (${messages.length} message${messages.length === 1 ? "" : "s"})`);
6269
6259
  for (const msg of messages) {
6270
- console.log(formatMessage(msg, useColor));
6271
- console.log("");
6260
+ process.stdout.write(formatMessage(msg) + `
6261
+
6262
+ `);
6272
6263
  }
6273
6264
  });
6274
6265
  }
6275
6266
  var init_inbox = __esm(() => {
6276
6267
  init_connect();
6268
+ init_render();
6269
+ init_styles();
6277
6270
  });
6278
6271
 
6279
6272
  // src/commands/state.ts
@@ -6344,9 +6337,6 @@ __export(exports_info, {
6344
6337
  runInfo: () => runInfo
6345
6338
  });
6346
6339
  async function runInfo(flags) {
6347
- const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
6348
- const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
6349
- const bold2 = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
6350
6340
  const config = readConfig();
6351
6341
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client, mesh) => {
6352
6342
  const [brokerInfo, peers, state] = await Promise.all([
@@ -6365,26 +6355,33 @@ async function runInfo(flags) {
6365
6355
  ...brokerInfo ?? {}
6366
6356
  };
6367
6357
  if (flags.json) {
6368
- console.log(JSON.stringify(output, null, 2));
6358
+ process.stdout.write(JSON.stringify(output, null, 2) + `
6359
+ `);
6369
6360
  return;
6370
6361
  }
6371
- console.log(bold2(mesh.slug) + dim2(` · ${mesh.brokerUrl}`));
6372
- console.log(dim2(` mesh: ${mesh.meshId}`));
6373
- console.log(dim2(` member: ${mesh.memberId}`));
6374
- console.log(` peers: ${peers.length} connected`);
6375
- console.log(` state: ${state.length} keys`);
6362
+ render.section(`${mesh.slug} · ${mesh.brokerUrl}`);
6363
+ render.kv([
6364
+ ["mesh", mesh.meshId],
6365
+ ["member", mesh.memberId],
6366
+ ["peers", `${peers.length} connected`],
6367
+ ["state", `${state.length} keys`]
6368
+ ]);
6376
6369
  if (brokerInfo && typeof brokerInfo === "object") {
6370
+ const extras = [];
6377
6371
  for (const [k, v] of Object.entries(brokerInfo)) {
6378
6372
  if (["slug", "meshId", "brokerUrl"].includes(k))
6379
6373
  continue;
6380
- console.log(dim2(` ${k}: ${JSON.stringify(v)}`));
6374
+ extras.push([k, JSON.stringify(v)]);
6381
6375
  }
6376
+ if (extras.length)
6377
+ render.kv(extras);
6382
6378
  }
6383
6379
  });
6384
6380
  }
6385
6381
  var init_info2 = __esm(() => {
6386
6382
  init_connect();
6387
6383
  init_facade();
6384
+ init_render();
6388
6385
  });
6389
6386
 
6390
6387
  // src/commands/remember.ts
@@ -7467,6 +7464,7 @@ import { statSync as statSync3, existsSync as existsSync8 } from "node:fs";
7467
7464
  import WebSocket2 from "ws";
7468
7465
  async function probeBroker(url, timeoutMs = 4000) {
7469
7466
  return new Promise((resolve2) => {
7467
+ const started = Date.now();
7470
7468
  const ws = new WebSocket2(url);
7471
7469
  const timer = setTimeout(() => {
7472
7470
  try {
@@ -7476,10 +7474,11 @@ async function probeBroker(url, timeoutMs = 4000) {
7476
7474
  }, timeoutMs);
7477
7475
  ws.on("open", () => {
7478
7476
  clearTimeout(timer);
7477
+ const latency = Date.now() - started;
7479
7478
  try {
7480
7479
  ws.close();
7481
7480
  } catch {}
7482
- resolve2({ ok: true });
7481
+ resolve2({ ok: true, latencyMs: latency });
7483
7482
  });
7484
7483
  ws.on("error", (err) => {
7485
7484
  clearTimeout(timer);
@@ -7488,63 +7487,60 @@ async function probeBroker(url, timeoutMs = 4000) {
7488
7487
  });
7489
7488
  }
7490
7489
  async function runStatus() {
7491
- const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
7492
- const dim2 = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
7493
- const green3 = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
7494
- const red3 = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
7495
- console.log(`claudemesh status (v${VERSION})`);
7496
- console.log("─".repeat(60));
7490
+ render.section(`status (v${VERSION})`);
7497
7491
  const configPath = getConfigPath();
7498
- let configPerms = "missing";
7492
+ let configPermsNote = "missing";
7499
7493
  if (existsSync8(configPath)) {
7500
- const st = statSync3(configPath);
7501
- const mode = (st.mode & 511).toString(8).padStart(4, "0");
7502
- configPerms = mode === "0600" ? `${mode} ✓` : `${mode} ⚠ (expected 0600)`;
7494
+ const mode = (statSync3(configPath).mode & 511).toString(8).padStart(4, "0");
7495
+ configPermsNote = mode === "0600" ? `${mode}` : `${mode} — expected 0600`;
7503
7496
  }
7504
- console.log(`Config: ${configPath} (${configPerms})`);
7497
+ render.kv([["config", configPath], ["perms", configPermsNote]]);
7505
7498
  const config = readConfig();
7506
7499
  if (config.meshes.length === 0) {
7507
- console.log("");
7508
- console.log(dim2("No meshes joined. Run `claudemesh join <invite-url>` to get started."));
7500
+ render.blank();
7501
+ render.info("No meshes joined.");
7502
+ render.hint("claudemesh <invite-url> # join + launch");
7509
7503
  process.exit(0);
7510
7504
  }
7511
- console.log("");
7512
- console.log(`Meshes (${config.meshes.length}):`);
7505
+ render.blank();
7506
+ render.heading(`meshes (${config.meshes.length})`);
7513
7507
  const results = [];
7514
7508
  for (const m of config.meshes) {
7515
- process.stdout.write(` ${m.slug.padEnd(20)} probing ${m.brokerUrl}… `);
7516
7509
  const probe = await probeBroker(m.brokerUrl);
7517
- results.push({
7510
+ const entry = {
7518
7511
  slug: m.slug,
7519
7512
  brokerUrl: m.brokerUrl,
7520
7513
  pubkey: m.pubkey,
7521
7514
  reachable: probe.ok,
7522
- error: probe.error
7523
- });
7515
+ error: probe.error,
7516
+ latencyMs: probe.latencyMs
7517
+ };
7518
+ results.push(entry);
7524
7519
  if (probe.ok) {
7525
- console.log(green3("reachable"));
7520
+ render.ok(`${m.slug}`, `${probe.latencyMs}ms → ${m.brokerUrl}`);
7526
7521
  } else {
7527
- console.log(red3(`unreachable (${probe.error})`));
7522
+ render.err(`${m.slug}`, `unreachable (${probe.error})`);
7528
7523
  }
7529
7524
  }
7530
- console.log("");
7525
+ render.blank();
7531
7526
  for (const r of results) {
7532
- console.log(dim2(` ${r.slug}: pubkey ${r.pubkey.slice(0, 16)}…`));
7527
+ render.kv([[r.slug, `${r.pubkey.slice(0, 16)}…`]]);
7533
7528
  }
7534
7529
  const allOk = results.every((r) => r.reachable);
7535
- console.log("");
7530
+ render.blank();
7536
7531
  if (allOk) {
7537
- console.log(green3("All meshes reachable."));
7532
+ render.ok("all meshes reachable");
7538
7533
  process.exit(0);
7539
7534
  } else {
7540
7535
  const broken = results.filter((r) => !r.reachable).length;
7541
- console.log(red3(`${broken} of ${results.length} mesh(es) unreachable.`));
7536
+ render.err(`${broken} of ${results.length} mesh(es) unreachable`);
7542
7537
  process.exit(1);
7543
7538
  }
7544
7539
  }
7545
7540
  var init_status = __esm(() => {
7546
7541
  init_facade();
7547
7542
  init_urls();
7543
+ init_render();
7548
7544
  });
7549
7545
 
7550
7546
  // src/commands/sync.ts
@@ -8606,6 +8602,30 @@ __export(exports_grants, {
8606
8602
  import { existsSync as existsSync17, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "node:fs";
8607
8603
  import { homedir as homedir8 } from "node:os";
8608
8604
  import { join as join9 } from "node:path";
8605
+ async function syncToBroker(meshSlug, grants) {
8606
+ const auth = getStoredToken();
8607
+ if (!auth)
8608
+ return;
8609
+ let userId = "";
8610
+ try {
8611
+ const payload = JSON.parse(Buffer.from(auth.session_token.split(".")[1], "base64url").toString());
8612
+ userId = payload.sub ?? "";
8613
+ } catch {
8614
+ return;
8615
+ }
8616
+ if (!userId)
8617
+ return;
8618
+ try {
8619
+ await request({
8620
+ path: `/cli/mesh/${meshSlug}/grants`,
8621
+ method: "POST",
8622
+ body: { user_id: userId, grants },
8623
+ baseUrl: BROKER_HTTP7
8624
+ });
8625
+ } catch (e) {
8626
+ render.warn(`broker grant sync failed — client filter still active: ${e instanceof Error ? e.message : e}`);
8627
+ }
8628
+ }
8609
8629
  function readGrants() {
8610
8630
  if (!existsSync17(GRANT_FILE))
8611
8631
  return {};
@@ -8667,6 +8687,7 @@ async function runGrant(peer, caps, opts = {}) {
8667
8687
  meshGrants[resolved.pubkey] = merged;
8668
8688
  store[mesh] = meshGrants;
8669
8689
  writeGrants(store);
8690
+ await syncToBroker(mesh, { [resolved.pubkey]: merged });
8670
8691
  render.ok(`Granted ${wanted.join(", ")} to ${resolved.displayName} on ${mesh}.`);
8671
8692
  render.kv([["now", merged.join(", ")]]);
8672
8693
  return EXIT.SUCCESS;
@@ -8694,6 +8715,7 @@ async function runRevoke(peer, caps, opts = {}) {
8694
8715
  meshGrants[resolved.pubkey] = after;
8695
8716
  store[mesh] = meshGrants;
8696
8717
  writeGrants(store);
8718
+ await syncToBroker(mesh, { [resolved.pubkey]: after });
8697
8719
  render.ok(`Revoked ${wanted.join(", ")} from ${resolved.displayName} on ${mesh}.`);
8698
8720
  render.kv([["now", after.length ? after.join(", ") : "(none)"]]);
8699
8721
  return EXIT.SUCCESS;
@@ -8718,6 +8740,7 @@ async function runBlock(peer, opts = {}) {
8718
8740
  meshGrants[resolved.pubkey] = [];
8719
8741
  store[mesh] = meshGrants;
8720
8742
  writeGrants(store);
8743
+ await syncToBroker(mesh, { [resolved.pubkey]: [] });
8721
8744
  render.ok(`Blocked ${resolved.displayName} on ${mesh} (all capabilities revoked).`);
8722
8745
  render.hint(`Undo with: claudemesh grant ${resolved.displayName} all --mesh ${mesh}`);
8723
8746
  return EXIT.SUCCESS;
@@ -8757,12 +8780,16 @@ function isAllowed(meshSlug, peerPubkey, cap) {
8757
8780
  return DEFAULT_CAPS.includes(cap);
8758
8781
  return entry.includes(cap);
8759
8782
  }
8760
- var ALL_CAPS, DEFAULT_CAPS, GRANT_FILE;
8783
+ var BROKER_HTTP7, ALL_CAPS, DEFAULT_CAPS, GRANT_FILE;
8761
8784
  var init_grants = __esm(() => {
8762
8785
  init_facade();
8763
8786
  init_connect();
8764
8787
  init_render();
8765
8788
  init_exit_codes();
8789
+ init_facade6();
8790
+ init_facade3();
8791
+ init_urls();
8792
+ BROKER_HTTP7 = URLS.BROKER.replace("wss://", "https://").replace("ws://", "http://").replace("/ws", "");
8766
8793
  ALL_CAPS = ["read", "dm", "broadcast", "state-read", "state-write", "file-read"];
8767
8794
  DEFAULT_CAPS = ["read", "dm", "broadcast", "state-read"];
8768
8795
  GRANT_FILE = join9(homedir8(), ".claudemesh", "grants.json");
@@ -12452,4 +12479,4 @@ main().catch((err) => {
12452
12479
  process.exit(EXIT.INTERNAL_ERROR);
12453
12480
  });
12454
12481
 
12455
- //# debugId=AF03F88BC783BD6C64756E2164756E21
12482
+ //# debugId=E80C818349D554BA64756E2164756E21