claudemesh-cli 1.19.3 → 1.20.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.19.3", env;
91
+ var URLS, VERSION = "1.20.1", env;
92
92
  var init_urls = __esm(() => {
93
93
  URLS = {
94
94
  BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
@@ -398,6 +398,7 @@ var init_client = __esm(() => {
398
398
  var exports_my = {};
399
399
  __export(exports_my, {
400
400
  revokeSession: () => revokeSession,
401
+ reslugMesh: () => reslugMesh,
401
402
  renameMesh: () => renameMesh,
402
403
  getProfile: () => getProfile,
403
404
  getMeshes: () => getMeshes,
@@ -422,6 +423,14 @@ async function renameMesh(token, slug, newName) {
422
423
  token
423
424
  });
424
425
  }
426
+ async function reslugMesh(token, oldSlug, newSlug) {
427
+ return request({
428
+ path: `/api/cli/meshes/${oldSlug}`,
429
+ method: "PATCH",
430
+ body: { slug: newSlug },
431
+ token
432
+ });
433
+ }
425
434
  async function createInvite(token, meshSlug, body) {
426
435
  return post(`/api/my/meshes/${meshSlug}/invites`, body, token);
427
436
  }
@@ -3658,14 +3667,15 @@ async function runLaunchWizard(opts) {
3658
3667
  spinner.stop();
3659
3668
  const choice = await menuSelect({
3660
3669
  title: "Select mesh",
3661
- items: opts.meshes.map((m) => m.slug),
3670
+ items: opts.meshes.map((m) => m.name && m.name !== m.slug ? `${m.name} \x1B[2m(${m.slug})\x1B[0m` : m.slug),
3662
3671
  row
3663
3672
  });
3664
3673
  mesh = opts.meshes[choice];
3665
3674
  for (let i = 0;i < opts.meshes.length + 1; i++) {
3666
3675
  writeCentered(row + i, " ");
3667
3676
  }
3668
- writeCentered(row, `Mesh ${green("✓")} ${mesh.slug}`);
3677
+ const meshLabel = mesh.name && mesh.name !== mesh.slug ? `${mesh.name} (${mesh.slug})` : mesh.slug;
3678
+ writeCentered(row, `Mesh ${green("✓")} ${meshLabel}`);
3669
3679
  spinner.start();
3670
3680
  row++;
3671
3681
  }
@@ -4393,6 +4403,18 @@ var init_rename = __esm(() => {
4393
4403
  init_facade6();
4394
4404
  });
4395
4405
 
4406
+ // src/services/mesh/reslug.ts
4407
+ async function reslugMesh2(oldSlug, newSlug) {
4408
+ const auth = getStoredToken();
4409
+ if (!auth)
4410
+ throw new Error("Not signed in");
4411
+ return await exports_my.reslugMesh(auth.session_token, oldSlug, newSlug);
4412
+ }
4413
+ var init_reslug = __esm(() => {
4414
+ init_facade3();
4415
+ init_facade6();
4416
+ });
4417
+
4396
4418
  // src/services/mesh/leave.ts
4397
4419
  function leaveMesh(slug) {
4398
4420
  return removeMeshConfig(slug);
@@ -4434,6 +4456,7 @@ var init_facade10 = __esm(() => {
4434
4456
  init_list();
4435
4457
  init_create();
4436
4458
  init_rename();
4459
+ init_reslug();
4437
4460
  init_leave();
4438
4461
  init_join();
4439
4462
  init_resolve_target();
@@ -5178,6 +5201,76 @@ var init_rename2 = __esm(() => {
5178
5201
  init_exit_codes();
5179
5202
  });
5180
5203
 
5204
+ // src/commands/slug.ts
5205
+ var exports_slug = {};
5206
+ __export(exports_slug, {
5207
+ slug: () => slug
5208
+ });
5209
+ async function slug(oldSlug, newSlug) {
5210
+ if (!oldSlug || !newSlug) {
5211
+ console.error(` ${icons.cross} Usage: ${bold("claudemesh slug")} <old-slug> <new-slug>`);
5212
+ return EXIT.INVALID_ARGS;
5213
+ }
5214
+ if (!SLUG_RE.test(newSlug)) {
5215
+ console.error(` ${icons.cross} Invalid slug: must be 2-32 chars, lowercase alnum + hyphens, start with alnum`);
5216
+ return EXIT.INVALID_ARGS;
5217
+ }
5218
+ if (oldSlug === newSlug) {
5219
+ console.error(` ${icons.cross} Old and new slug are the same.`);
5220
+ return EXIT.INVALID_ARGS;
5221
+ }
5222
+ const auth = getStoredToken();
5223
+ if (!auth) {
5224
+ console.error(` ${icons.cross} Renaming a mesh requires a claudemesh.com account session.`);
5225
+ console.error(` ${dim("Run")} ${bold("claudemesh login")} ${dim("first.")}`);
5226
+ return EXIT.AUTH_FAILED;
5227
+ }
5228
+ const cfg = readConfig();
5229
+ const collision = cfg.meshes.find((m) => m.slug === newSlug && m.slug !== oldSlug);
5230
+ if (collision) {
5231
+ console.error(` ${icons.cross} Slug "${newSlug}" already used locally by another joined mesh.`);
5232
+ console.error(` ${dim("Pick a different slug, or leave the other mesh first.")}`);
5233
+ return EXIT.ALREADY_EXISTS;
5234
+ }
5235
+ try {
5236
+ const updated = await reslugMesh2(oldSlug, newSlug);
5237
+ const local = cfg.meshes.find((m) => m.slug === oldSlug);
5238
+ if (local) {
5239
+ removeMeshConfig(oldSlug);
5240
+ setMeshConfig(updated.slug, { ...local, slug: updated.slug, name: updated.name });
5241
+ }
5242
+ console.log(` ${green(icons.check)} Slug changed: "${oldSlug}" → "${updated.slug}"`);
5243
+ console.log(` ${dim("Other peers will pick up the new slug after they run")} ${bold("claudemesh sync")}`);
5244
+ return EXIT.SUCCESS;
5245
+ } catch (err) {
5246
+ if (err instanceof ApiError) {
5247
+ const body = err.body;
5248
+ console.error(` ${icons.cross} ${body?.error ?? err.statusText}`);
5249
+ if (err.status === 401)
5250
+ return EXIT.AUTH_FAILED;
5251
+ if (err.status === 403)
5252
+ return EXIT.PERMISSION_DENIED;
5253
+ if (err.status === 404)
5254
+ return EXIT.NOT_FOUND;
5255
+ if (err.status === 400)
5256
+ return EXIT.INVALID_ARGS;
5257
+ return EXIT.INTERNAL_ERROR;
5258
+ }
5259
+ console.error(` ${icons.cross} Failed: ${err instanceof Error ? err.message : err}`);
5260
+ return EXIT.INTERNAL_ERROR;
5261
+ }
5262
+ }
5263
+ var SLUG_RE;
5264
+ var init_slug = __esm(() => {
5265
+ init_facade10();
5266
+ init_facade6();
5267
+ init_facade3();
5268
+ init_facade();
5269
+ init_styles();
5270
+ init_exit_codes();
5271
+ SLUG_RE = /^[a-z0-9][a-z0-9-]{1,31}$/;
5272
+ });
5273
+
5181
5274
  // src/services/clipboard/read.ts
5182
5275
  import { execSync } from "node:child_process";
5183
5276
  import { platform as platform4 } from "node:os";
@@ -6725,17 +6818,17 @@ function projectFields(record, fields) {
6725
6818
  }
6726
6819
  return out;
6727
6820
  }
6728
- async function listPeersForMesh(slug) {
6821
+ async function listPeersForMesh(slug2) {
6729
6822
  const config = readConfig();
6730
- const joined = config.meshes.find((m) => m.slug === slug);
6823
+ const joined = config.meshes.find((m) => m.slug === slug2);
6731
6824
  const selfMemberPubkey = joined?.pubkey ?? null;
6732
- const bridged = await tryBridge(slug, "peers");
6825
+ const bridged = await tryBridge(slug2, "peers");
6733
6826
  if (bridged && bridged.ok) {
6734
6827
  const peers = bridged.result;
6735
6828
  return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
6736
6829
  }
6737
6830
  let result = [];
6738
- await withMesh({ meshSlug: slug }, async (client) => {
6831
+ await withMesh({ meshSlug: slug2 }, async (client) => {
6739
6832
  const all = await client.listPeers();
6740
6833
  const selfSessionPubkey = client.getSessionPubkey();
6741
6834
  result = all.map((p) => annotateSelf(p, selfMemberPubkey, selfSessionPubkey));
@@ -6758,15 +6851,15 @@ async function runPeers(flags) {
6758
6851
  const fieldList = typeof flags.json === "string" && flags.json.length > 0 ? flags.json.split(",").map((s) => s.trim()).filter(Boolean) : null;
6759
6852
  const wantsJson = flags.json !== undefined && flags.json !== false;
6760
6853
  const allJson = [];
6761
- for (const slug of slugs) {
6854
+ for (const slug2 of slugs) {
6762
6855
  try {
6763
- const peers = await listPeersForMesh(slug);
6856
+ const peers = await listPeersForMesh(slug2);
6764
6857
  if (wantsJson) {
6765
6858
  const projected = fieldList ? peers.map((p) => projectFields(p, fieldList)) : peers;
6766
- allJson.push({ mesh: slug, peers: projected });
6859
+ allJson.push({ mesh: slug2, peers: projected });
6767
6860
  continue;
6768
6861
  }
6769
- render.section(`peers on ${slug} (${peers.length})`);
6862
+ render.section(`peers on ${slug2} (${peers.length})`);
6770
6863
  if (peers.length === 0) {
6771
6864
  render.info(dim(" (no peers connected)"));
6772
6865
  continue;
@@ -6791,7 +6884,7 @@ async function runPeers(flags) {
6791
6884
  render.info(dim(` cwd: ${p.cwd}`));
6792
6885
  }
6793
6886
  } catch (e) {
6794
- render.err(`${slug}: ${e instanceof Error ? e.message : String(e)}`);
6887
+ render.err(`${slug2}: ${e instanceof Error ? e.message : String(e)}`);
6795
6888
  }
6796
6889
  }
6797
6890
  if (wantsJson) {
@@ -7080,11 +7173,11 @@ async function runMe(flags) {
7080
7173
  }
7081
7174
  const slugWidth = Math.max(...ws.meshes.map((m) => m.slug.length), 8);
7082
7175
  for (const m of ws.meshes) {
7083
- const slug = cyan(m.slug.padEnd(slugWidth));
7176
+ const slug2 = cyan(m.slug.padEnd(slugWidth));
7084
7177
  const peers = `${m.online}/${m.peers}`;
7085
7178
  const role = dim(m.myRole);
7086
7179
  const unread = m.unreadMentions > 0 ? " " + yellow(`${m.unreadMentions} @you`) : "";
7087
- process.stdout.write(` ${slug} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
7180
+ process.stdout.write(` ${slug2} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
7088
7181
  `);
7089
7182
  }
7090
7183
  return EXIT.SUCCESS;
@@ -7114,11 +7207,11 @@ async function runMeTopics(flags) {
7114
7207
  const slugWidth = Math.max(...visible.map((t) => t.meshSlug.length), 6);
7115
7208
  const nameWidth = Math.max(...visible.map((t) => t.name.length), 8);
7116
7209
  for (const t of visible) {
7117
- const slug = dim(t.meshSlug.padEnd(slugWidth));
7210
+ const slug2 = dim(t.meshSlug.padEnd(slugWidth));
7118
7211
  const name = cyan(t.name.padEnd(nameWidth));
7119
7212
  const unread = t.unread > 0 ? yellow(`${t.unread} unread`.padStart(10)) : dim("·".padStart(10));
7120
7213
  const last = t.lastMessageAt ? dim(formatRelativeTime(t.lastMessageAt)) : dim("never");
7121
- process.stdout.write(` ${slug} ${name} ${unread} ${last}
7214
+ process.stdout.write(` ${slug2} ${name} ${unread} ${last}
7122
7215
  `);
7123
7216
  }
7124
7217
  return EXIT.SUCCESS;
@@ -7154,13 +7247,13 @@ async function runMeNotifications(flags) {
7154
7247
  }
7155
7248
  const slugWidth = Math.max(...ws.notifications.map((n) => n.meshSlug.length), 6);
7156
7249
  for (const n of ws.notifications) {
7157
- const slug = dim(n.meshSlug.padEnd(slugWidth));
7250
+ const slug2 = dim(n.meshSlug.padEnd(slugWidth));
7158
7251
  const topic = cyan(`#${n.topicName}`);
7159
7252
  const sender = n.senderName ? `from ${n.senderName}` : "from ?";
7160
7253
  const ago = formatRelativeTime(n.createdAt);
7161
7254
  const dot = n.read ? dim("·") : yellow("●");
7162
7255
  const snippet = n.snippet ?? (n.ciphertext ? dim("[encrypted]") : dim("[empty]"));
7163
- process.stdout.write(` ${dot} ${slug} ${topic} ${dim(sender)} ${dim(ago)}
7256
+ process.stdout.write(` ${dot} ${slug2} ${topic} ${dim(sender)} ${dim(ago)}
7164
7257
  ` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
7165
7258
  `);
7166
7259
  }
@@ -7193,12 +7286,12 @@ async function runMeActivity(flags) {
7193
7286
  }
7194
7287
  const slugWidth = Math.max(...ws.activity.map((a) => a.meshSlug.length), 6);
7195
7288
  for (const a of ws.activity) {
7196
- const slug = dim(a.meshSlug.padEnd(slugWidth));
7289
+ const slug2 = dim(a.meshSlug.padEnd(slugWidth));
7197
7290
  const topic = cyan(`#${a.topicName}`);
7198
7291
  const sender = a.senderName ?? "?";
7199
7292
  const ago = formatRelativeTime(a.createdAt);
7200
7293
  const snippet = a.snippet ?? (a.ciphertext ? dim("[encrypted]") : dim("[empty]"));
7201
- process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7294
+ process.stdout.write(` ${slug2} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7202
7295
  ` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
7203
7296
  `);
7204
7297
  }
@@ -7237,10 +7330,10 @@ async function runMeSearch(flags) {
7237
7330
  `));
7238
7331
  const slugWidth = Math.max(...ws.topics.map((t) => t.meshSlug.length), 6);
7239
7332
  for (const t of ws.topics) {
7240
- const slug = dim(t.meshSlug.padEnd(slugWidth));
7333
+ const slug2 = dim(t.meshSlug.padEnd(slugWidth));
7241
7334
  const name = cyan(`#${t.name}`);
7242
7335
  const desc = t.description ? dim(` — ${t.description}`) : "";
7243
- process.stdout.write(` ${slug} ${name}${desc}
7336
+ process.stdout.write(` ${slug2} ${name}${desc}
7244
7337
  `);
7245
7338
  }
7246
7339
  }
@@ -7250,13 +7343,13 @@ async function runMeSearch(flags) {
7250
7343
  `));
7251
7344
  const slugWidth = Math.max(...ws.messages.map((m) => m.meshSlug.length), 6);
7252
7345
  for (const m of ws.messages) {
7253
- const slug = dim(m.meshSlug.padEnd(slugWidth));
7346
+ const slug2 = dim(m.meshSlug.padEnd(slugWidth));
7254
7347
  const topic = cyan(`#${m.topicName}`);
7255
7348
  const sender = m.senderName;
7256
7349
  const ago = formatRelativeTime(m.createdAt);
7257
7350
  const snippet = m.snippet ?? (m.bodyVersion === 2 ? dim("[encrypted — open the topic to decrypt]") : dim("[empty]"));
7258
7351
  const highlighted = m.snippet ? highlightMatch(snippet, flags.query) : snippet;
7259
- process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7352
+ process.stdout.write(` ${slug2} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7260
7353
  ` + ` ${highlighted}
7261
7354
  `);
7262
7355
  }
@@ -7301,11 +7394,11 @@ async function runMeTasks(flags) {
7301
7394
  }
7302
7395
  const slugWidth = Math.max(...ws.tasks.map((t) => t.meshSlug.length), 6);
7303
7396
  for (const t of ws.tasks) {
7304
- const slug = dim(t.meshSlug.padEnd(slugWidth));
7397
+ const slug2 = dim(t.meshSlug.padEnd(slugWidth));
7305
7398
  const status = t.status === "open" ? yellow("open ") : t.status === "claimed" ? cyan("working ") : green("done ");
7306
7399
  const prio = t.priority === "urgent" ? yellow("!") : t.priority === "low" ? dim("·") : " ";
7307
7400
  const claimer = t.claimedByName ? dim(` ← ${t.claimedByName}`) : "";
7308
- process.stdout.write(` ${slug} ${prio} ${status} ${t.title}${claimer}
7401
+ process.stdout.write(` ${slug2} ${prio} ${status} ${t.title}${claimer}
7309
7402
  `);
7310
7403
  }
7311
7404
  return EXIT.SUCCESS;
@@ -7338,12 +7431,12 @@ async function runMeState(flags) {
7338
7431
  const slugWidth = Math.max(...ws.entries.map((e) => e.meshSlug.length), 6);
7339
7432
  const keyWidth = Math.max(...ws.entries.map((e) => e.key.length), 8);
7340
7433
  for (const e of ws.entries) {
7341
- const slug = dim(e.meshSlug.padEnd(slugWidth));
7434
+ const slug2 = dim(e.meshSlug.padEnd(slugWidth));
7342
7435
  const key = cyan(e.key.padEnd(keyWidth));
7343
7436
  const valueStr = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
7344
7437
  const trimmed = valueStr.length > 80 ? valueStr.slice(0, 80) + "…" : valueStr;
7345
7438
  const ago = dim(formatRelativeTime(e.updatedAt));
7346
- process.stdout.write(` ${slug} ${key} ${trimmed} ${ago}
7439
+ process.stdout.write(` ${slug2} ${key} ${trimmed} ${ago}
7347
7440
  `);
7348
7441
  }
7349
7442
  return EXIT.SUCCESS;
@@ -7376,11 +7469,11 @@ async function runMeMemory(flags) {
7376
7469
  }
7377
7470
  const slugWidth = Math.max(...ws.memories.map((m) => m.meshSlug.length), 6);
7378
7471
  for (const m of ws.memories) {
7379
- const slug = dim(m.meshSlug.padEnd(slugWidth));
7472
+ const slug2 = dim(m.meshSlug.padEnd(slugWidth));
7380
7473
  const ago = dim(formatRelativeTime(m.rememberedAt));
7381
7474
  const tags = m.tags.length > 0 ? " " + dim("[" + m.tags.join(", ") + "]") : "";
7382
7475
  const content = m.content.length > 240 ? m.content.slice(0, 240) + "…" : m.content;
7383
- process.stdout.write(` ${slug} ${ago}${tags}
7476
+ process.stdout.write(` ${slug2} ${ago}${tags}
7384
7477
  ${content}
7385
7478
  `);
7386
7479
  }
@@ -10164,10 +10257,10 @@ async function resolvePeer(meshSlug, name) {
10164
10257
  return { displayName: match.displayName, pubkey: key };
10165
10258
  });
10166
10259
  }
10167
- function pickMesh2(slug) {
10260
+ function pickMesh2(slug2) {
10168
10261
  const cfg = readConfig();
10169
- if (slug)
10170
- return cfg.meshes.find((m) => m.slug === slug) ? slug : null;
10262
+ if (slug2)
10263
+ return cfg.meshes.find((m) => m.slug === slug2) ? slug2 : null;
10171
10264
  return cfg.meshes[0]?.slug ?? null;
10172
10265
  }
10173
10266
  async function runGrant(peer, caps, opts = {}) {
@@ -14439,26 +14532,26 @@ __export(exports_seed_test_mesh, {
14439
14532
  runSeedTestMesh: () => runSeedTestMesh
14440
14533
  });
14441
14534
  function runSeedTestMesh(args) {
14442
- const [brokerUrl, meshId, memberId, pubkey, slug] = args;
14443
- if (!brokerUrl || !meshId || !memberId || !pubkey || !slug) {
14535
+ const [brokerUrl, meshId, memberId, pubkey, slug2] = args;
14536
+ if (!brokerUrl || !meshId || !memberId || !pubkey || !slug2) {
14444
14537
  render.err("Usage: claudemesh seed-test-mesh <broker-ws-url> <mesh-id> <member-id> <pubkey> <slug>");
14445
14538
  render.info(dim('Example: claudemesh seed-test-mesh "ws://localhost:7900/ws" mesh-123 member-abc aaa..aaa smoke-test'));
14446
14539
  process.exit(1);
14447
14540
  }
14448
14541
  const config = readConfig();
14449
- config.meshes = config.meshes.filter((m) => m.slug !== slug);
14542
+ config.meshes = config.meshes.filter((m) => m.slug !== slug2);
14450
14543
  config.meshes.push({
14451
14544
  meshId,
14452
14545
  memberId,
14453
- slug,
14454
- name: `Test: ${slug}`,
14546
+ slug: slug2,
14547
+ name: `Test: ${slug2}`,
14455
14548
  pubkey,
14456
14549
  secretKey: "dev-only-stub",
14457
14550
  brokerUrl,
14458
14551
  joinedAt: new Date().toISOString()
14459
14552
  });
14460
14553
  writeConfig(config);
14461
- render.ok(`seeded ${bold(slug)}`, dim(meshId));
14554
+ render.ok(`seeded ${bold(slug2)}`, dim(meshId));
14462
14555
  render.hint(`run ${bold("claudemesh mcp")} to connect, or register with Claude Code via ${bold("claudemesh install")}`);
14463
14556
  }
14464
14557
  var init_seed_test_mesh = __esm(() => {
@@ -15044,7 +15137,8 @@ Mesh
15044
15137
  claudemesh launch [slug] launch Claude Code on a mesh (alias: connect)
15045
15138
  claudemesh list show your meshes (alias: ls)
15046
15139
  claudemesh delete [slug] delete a mesh (alias: rm)
15047
- claudemesh rename <slug> <name> rename a mesh
15140
+ claudemesh rename <slug> <name> rename a mesh's display name (slug stays)
15141
+ claudemesh slug <old> <new> change a mesh's slug (URL-safe identifier)
15048
15142
  claudemesh share [email] share mesh (invite link / send email)
15049
15143
 
15050
15144
  Peer (resource form, recommended)
@@ -15295,6 +15389,11 @@ async function main() {
15295
15389
  process.exit(await rename2(positionals[0] ?? "", positionals[1] ?? ""));
15296
15390
  break;
15297
15391
  }
15392
+ case "slug": {
15393
+ const { slug: slug2 } = await Promise.resolve().then(() => (init_slug(), exports_slug));
15394
+ process.exit(await slug2(positionals[0] ?? "", positionals[1] ?? ""));
15395
+ break;
15396
+ }
15298
15397
  case "share":
15299
15398
  case "invite": {
15300
15399
  const { invite: invite2 } = await Promise.resolve().then(() => (init_invite(), exports_invite));
@@ -16108,4 +16207,4 @@ main().catch((err) => {
16108
16207
  process.exit(EXIT.INTERNAL_ERROR);
16109
16208
  });
16110
16209
 
16111
- //# debugId=77BC12B35C8B56DE64756E2164756E21
16210
+ //# debugId=F81EA97B92E1F36F64756E2164756E21