claudemesh-cli 1.19.2 → 1.20.0

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.2", env;
91
+ var URLS, VERSION = "1.20.0", 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
  }
@@ -4393,6 +4402,18 @@ var init_rename = __esm(() => {
4393
4402
  init_facade6();
4394
4403
  });
4395
4404
 
4405
+ // src/services/mesh/reslug.ts
4406
+ async function reslugMesh2(oldSlug, newSlug) {
4407
+ const auth = getStoredToken();
4408
+ if (!auth)
4409
+ throw new Error("Not signed in");
4410
+ return await exports_my.reslugMesh(auth.session_token, oldSlug, newSlug);
4411
+ }
4412
+ var init_reslug = __esm(() => {
4413
+ init_facade3();
4414
+ init_facade6();
4415
+ });
4416
+
4396
4417
  // src/services/mesh/leave.ts
4397
4418
  function leaveMesh(slug) {
4398
4419
  return removeMeshConfig(slug);
@@ -4434,6 +4455,7 @@ var init_facade10 = __esm(() => {
4434
4455
  init_list();
4435
4456
  init_create();
4436
4457
  init_rename();
4458
+ init_reslug();
4437
4459
  init_leave();
4438
4460
  init_join();
4439
4461
  init_resolve_target();
@@ -5145,7 +5167,12 @@ async function rename(slug, newName) {
5145
5167
  }
5146
5168
  try {
5147
5169
  await renameMesh2(slug, newName);
5170
+ const cfg = readConfig();
5171
+ const local = cfg.meshes.find((m) => m.slug === slug);
5172
+ if (local)
5173
+ setMeshConfig(slug, { ...local, name: newName });
5148
5174
  console.log(` ${green(icons.check)} Renamed "${slug}" to "${newName}"`);
5175
+ console.log(` ${dim('(slug stays "' + slug + '" — only the display name changed)')}`);
5149
5176
  return EXIT.SUCCESS;
5150
5177
  } catch (err) {
5151
5178
  if (err instanceof ApiError) {
@@ -5168,8 +5195,79 @@ var init_rename2 = __esm(() => {
5168
5195
  init_facade10();
5169
5196
  init_facade6();
5170
5197
  init_facade3();
5198
+ init_facade();
5199
+ init_styles();
5200
+ init_exit_codes();
5201
+ });
5202
+
5203
+ // src/commands/slug.ts
5204
+ var exports_slug = {};
5205
+ __export(exports_slug, {
5206
+ slug: () => slug
5207
+ });
5208
+ async function slug(oldSlug, newSlug) {
5209
+ if (!oldSlug || !newSlug) {
5210
+ console.error(` ${icons.cross} Usage: ${bold("claudemesh slug")} <old-slug> <new-slug>`);
5211
+ return EXIT.INVALID_ARGS;
5212
+ }
5213
+ if (!SLUG_RE.test(newSlug)) {
5214
+ console.error(` ${icons.cross} Invalid slug: must be 2-32 chars, lowercase alnum + hyphens, start with alnum`);
5215
+ return EXIT.INVALID_ARGS;
5216
+ }
5217
+ if (oldSlug === newSlug) {
5218
+ console.error(` ${icons.cross} Old and new slug are the same.`);
5219
+ return EXIT.INVALID_ARGS;
5220
+ }
5221
+ const auth = getStoredToken();
5222
+ if (!auth) {
5223
+ console.error(` ${icons.cross} Renaming a mesh requires a claudemesh.com account session.`);
5224
+ console.error(` ${dim("Run")} ${bold("claudemesh login")} ${dim("first.")}`);
5225
+ return EXIT.AUTH_FAILED;
5226
+ }
5227
+ const cfg = readConfig();
5228
+ const collision = cfg.meshes.find((m) => m.slug === newSlug && m.slug !== oldSlug);
5229
+ if (collision) {
5230
+ console.error(` ${icons.cross} Slug "${newSlug}" already used locally by another joined mesh.`);
5231
+ console.error(` ${dim("Pick a different slug, or leave the other mesh first.")}`);
5232
+ return EXIT.ALREADY_EXISTS;
5233
+ }
5234
+ try {
5235
+ const updated = await reslugMesh2(oldSlug, newSlug);
5236
+ const local = cfg.meshes.find((m) => m.slug === oldSlug);
5237
+ if (local) {
5238
+ removeMeshConfig(oldSlug);
5239
+ setMeshConfig(updated.slug, { ...local, slug: updated.slug, name: updated.name });
5240
+ }
5241
+ console.log(` ${green(icons.check)} Slug changed: "${oldSlug}" → "${updated.slug}"`);
5242
+ console.log(` ${dim("Other peers will pick up the new slug after they run")} ${bold("claudemesh sync")}`);
5243
+ return EXIT.SUCCESS;
5244
+ } catch (err) {
5245
+ if (err instanceof ApiError) {
5246
+ const body = err.body;
5247
+ console.error(` ${icons.cross} ${body?.error ?? err.statusText}`);
5248
+ if (err.status === 401)
5249
+ return EXIT.AUTH_FAILED;
5250
+ if (err.status === 403)
5251
+ return EXIT.PERMISSION_DENIED;
5252
+ if (err.status === 404)
5253
+ return EXIT.NOT_FOUND;
5254
+ if (err.status === 400)
5255
+ return EXIT.INVALID_ARGS;
5256
+ return EXIT.INTERNAL_ERROR;
5257
+ }
5258
+ console.error(` ${icons.cross} Failed: ${err instanceof Error ? err.message : err}`);
5259
+ return EXIT.INTERNAL_ERROR;
5260
+ }
5261
+ }
5262
+ var SLUG_RE;
5263
+ var init_slug = __esm(() => {
5264
+ init_facade10();
5265
+ init_facade6();
5266
+ init_facade3();
5267
+ init_facade();
5171
5268
  init_styles();
5172
5269
  init_exit_codes();
5270
+ SLUG_RE = /^[a-z0-9][a-z0-9-]{1,31}$/;
5173
5271
  });
5174
5272
 
5175
5273
  // src/services/clipboard/read.ts
@@ -6719,17 +6817,17 @@ function projectFields(record, fields) {
6719
6817
  }
6720
6818
  return out;
6721
6819
  }
6722
- async function listPeersForMesh(slug) {
6820
+ async function listPeersForMesh(slug2) {
6723
6821
  const config = readConfig();
6724
- const joined = config.meshes.find((m) => m.slug === slug);
6822
+ const joined = config.meshes.find((m) => m.slug === slug2);
6725
6823
  const selfMemberPubkey = joined?.pubkey ?? null;
6726
- const bridged = await tryBridge(slug, "peers");
6824
+ const bridged = await tryBridge(slug2, "peers");
6727
6825
  if (bridged && bridged.ok) {
6728
6826
  const peers = bridged.result;
6729
6827
  return peers.map((p) => annotateSelf(p, selfMemberPubkey, null));
6730
6828
  }
6731
6829
  let result = [];
6732
- await withMesh({ meshSlug: slug }, async (client) => {
6830
+ await withMesh({ meshSlug: slug2 }, async (client) => {
6733
6831
  const all = await client.listPeers();
6734
6832
  const selfSessionPubkey = client.getSessionPubkey();
6735
6833
  result = all.map((p) => annotateSelf(p, selfMemberPubkey, selfSessionPubkey));
@@ -6752,15 +6850,15 @@ async function runPeers(flags) {
6752
6850
  const fieldList = typeof flags.json === "string" && flags.json.length > 0 ? flags.json.split(",").map((s) => s.trim()).filter(Boolean) : null;
6753
6851
  const wantsJson = flags.json !== undefined && flags.json !== false;
6754
6852
  const allJson = [];
6755
- for (const slug of slugs) {
6853
+ for (const slug2 of slugs) {
6756
6854
  try {
6757
- const peers = await listPeersForMesh(slug);
6855
+ const peers = await listPeersForMesh(slug2);
6758
6856
  if (wantsJson) {
6759
6857
  const projected = fieldList ? peers.map((p) => projectFields(p, fieldList)) : peers;
6760
- allJson.push({ mesh: slug, peers: projected });
6858
+ allJson.push({ mesh: slug2, peers: projected });
6761
6859
  continue;
6762
6860
  }
6763
- render.section(`peers on ${slug} (${peers.length})`);
6861
+ render.section(`peers on ${slug2} (${peers.length})`);
6764
6862
  if (peers.length === 0) {
6765
6863
  render.info(dim(" (no peers connected)"));
6766
6864
  continue;
@@ -6785,7 +6883,7 @@ async function runPeers(flags) {
6785
6883
  render.info(dim(` cwd: ${p.cwd}`));
6786
6884
  }
6787
6885
  } catch (e) {
6788
- render.err(`${slug}: ${e instanceof Error ? e.message : String(e)}`);
6886
+ render.err(`${slug2}: ${e instanceof Error ? e.message : String(e)}`);
6789
6887
  }
6790
6888
  }
6791
6889
  if (wantsJson) {
@@ -7074,11 +7172,11 @@ async function runMe(flags) {
7074
7172
  }
7075
7173
  const slugWidth = Math.max(...ws.meshes.map((m) => m.slug.length), 8);
7076
7174
  for (const m of ws.meshes) {
7077
- const slug = cyan(m.slug.padEnd(slugWidth));
7175
+ const slug2 = cyan(m.slug.padEnd(slugWidth));
7078
7176
  const peers = `${m.online}/${m.peers}`;
7079
7177
  const role = dim(m.myRole);
7080
7178
  const unread = m.unreadMentions > 0 ? " " + yellow(`${m.unreadMentions} @you`) : "";
7081
- process.stdout.write(` ${slug} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
7179
+ process.stdout.write(` ${slug2} ${peers.padStart(5)} online ${dim(String(m.topics).padStart(2) + " topics")} ${role}${unread}
7082
7180
  `);
7083
7181
  }
7084
7182
  return EXIT.SUCCESS;
@@ -7108,11 +7206,11 @@ async function runMeTopics(flags) {
7108
7206
  const slugWidth = Math.max(...visible.map((t) => t.meshSlug.length), 6);
7109
7207
  const nameWidth = Math.max(...visible.map((t) => t.name.length), 8);
7110
7208
  for (const t of visible) {
7111
- const slug = dim(t.meshSlug.padEnd(slugWidth));
7209
+ const slug2 = dim(t.meshSlug.padEnd(slugWidth));
7112
7210
  const name = cyan(t.name.padEnd(nameWidth));
7113
7211
  const unread = t.unread > 0 ? yellow(`${t.unread} unread`.padStart(10)) : dim("·".padStart(10));
7114
7212
  const last = t.lastMessageAt ? dim(formatRelativeTime(t.lastMessageAt)) : dim("never");
7115
- process.stdout.write(` ${slug} ${name} ${unread} ${last}
7213
+ process.stdout.write(` ${slug2} ${name} ${unread} ${last}
7116
7214
  `);
7117
7215
  }
7118
7216
  return EXIT.SUCCESS;
@@ -7148,13 +7246,13 @@ async function runMeNotifications(flags) {
7148
7246
  }
7149
7247
  const slugWidth = Math.max(...ws.notifications.map((n) => n.meshSlug.length), 6);
7150
7248
  for (const n of ws.notifications) {
7151
- const slug = dim(n.meshSlug.padEnd(slugWidth));
7249
+ const slug2 = dim(n.meshSlug.padEnd(slugWidth));
7152
7250
  const topic = cyan(`#${n.topicName}`);
7153
7251
  const sender = n.senderName ? `from ${n.senderName}` : "from ?";
7154
7252
  const ago = formatRelativeTime(n.createdAt);
7155
7253
  const dot = n.read ? dim("·") : yellow("●");
7156
7254
  const snippet = n.snippet ?? (n.ciphertext ? dim("[encrypted]") : dim("[empty]"));
7157
- process.stdout.write(` ${dot} ${slug} ${topic} ${dim(sender)} ${dim(ago)}
7255
+ process.stdout.write(` ${dot} ${slug2} ${topic} ${dim(sender)} ${dim(ago)}
7158
7256
  ` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
7159
7257
  `);
7160
7258
  }
@@ -7187,12 +7285,12 @@ async function runMeActivity(flags) {
7187
7285
  }
7188
7286
  const slugWidth = Math.max(...ws.activity.map((a) => a.meshSlug.length), 6);
7189
7287
  for (const a of ws.activity) {
7190
- const slug = dim(a.meshSlug.padEnd(slugWidth));
7288
+ const slug2 = dim(a.meshSlug.padEnd(slugWidth));
7191
7289
  const topic = cyan(`#${a.topicName}`);
7192
7290
  const sender = a.senderName ?? "?";
7193
7291
  const ago = formatRelativeTime(a.createdAt);
7194
7292
  const snippet = a.snippet ?? (a.ciphertext ? dim("[encrypted]") : dim("[empty]"));
7195
- process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7293
+ process.stdout.write(` ${slug2} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7196
7294
  ` + ` ${snippet.length > 200 ? snippet.slice(0, 200) + "…" : snippet}
7197
7295
  `);
7198
7296
  }
@@ -7231,10 +7329,10 @@ async function runMeSearch(flags) {
7231
7329
  `));
7232
7330
  const slugWidth = Math.max(...ws.topics.map((t) => t.meshSlug.length), 6);
7233
7331
  for (const t of ws.topics) {
7234
- const slug = dim(t.meshSlug.padEnd(slugWidth));
7332
+ const slug2 = dim(t.meshSlug.padEnd(slugWidth));
7235
7333
  const name = cyan(`#${t.name}`);
7236
7334
  const desc = t.description ? dim(` — ${t.description}`) : "";
7237
- process.stdout.write(` ${slug} ${name}${desc}
7335
+ process.stdout.write(` ${slug2} ${name}${desc}
7238
7336
  `);
7239
7337
  }
7240
7338
  }
@@ -7244,13 +7342,13 @@ async function runMeSearch(flags) {
7244
7342
  `));
7245
7343
  const slugWidth = Math.max(...ws.messages.map((m) => m.meshSlug.length), 6);
7246
7344
  for (const m of ws.messages) {
7247
- const slug = dim(m.meshSlug.padEnd(slugWidth));
7345
+ const slug2 = dim(m.meshSlug.padEnd(slugWidth));
7248
7346
  const topic = cyan(`#${m.topicName}`);
7249
7347
  const sender = m.senderName;
7250
7348
  const ago = formatRelativeTime(m.createdAt);
7251
7349
  const snippet = m.snippet ?? (m.bodyVersion === 2 ? dim("[encrypted — open the topic to decrypt]") : dim("[empty]"));
7252
7350
  const highlighted = m.snippet ? highlightMatch(snippet, flags.query) : snippet;
7253
- process.stdout.write(` ${slug} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7351
+ process.stdout.write(` ${slug2} ${topic} ${dim(sender + " ·")} ${dim(ago)}
7254
7352
  ` + ` ${highlighted}
7255
7353
  `);
7256
7354
  }
@@ -7295,11 +7393,11 @@ async function runMeTasks(flags) {
7295
7393
  }
7296
7394
  const slugWidth = Math.max(...ws.tasks.map((t) => t.meshSlug.length), 6);
7297
7395
  for (const t of ws.tasks) {
7298
- const slug = dim(t.meshSlug.padEnd(slugWidth));
7396
+ const slug2 = dim(t.meshSlug.padEnd(slugWidth));
7299
7397
  const status = t.status === "open" ? yellow("open ") : t.status === "claimed" ? cyan("working ") : green("done ");
7300
7398
  const prio = t.priority === "urgent" ? yellow("!") : t.priority === "low" ? dim("·") : " ";
7301
7399
  const claimer = t.claimedByName ? dim(` ← ${t.claimedByName}`) : "";
7302
- process.stdout.write(` ${slug} ${prio} ${status} ${t.title}${claimer}
7400
+ process.stdout.write(` ${slug2} ${prio} ${status} ${t.title}${claimer}
7303
7401
  `);
7304
7402
  }
7305
7403
  return EXIT.SUCCESS;
@@ -7332,12 +7430,12 @@ async function runMeState(flags) {
7332
7430
  const slugWidth = Math.max(...ws.entries.map((e) => e.meshSlug.length), 6);
7333
7431
  const keyWidth = Math.max(...ws.entries.map((e) => e.key.length), 8);
7334
7432
  for (const e of ws.entries) {
7335
- const slug = dim(e.meshSlug.padEnd(slugWidth));
7433
+ const slug2 = dim(e.meshSlug.padEnd(slugWidth));
7336
7434
  const key = cyan(e.key.padEnd(keyWidth));
7337
7435
  const valueStr = typeof e.value === "string" ? e.value : JSON.stringify(e.value);
7338
7436
  const trimmed = valueStr.length > 80 ? valueStr.slice(0, 80) + "…" : valueStr;
7339
7437
  const ago = dim(formatRelativeTime(e.updatedAt));
7340
- process.stdout.write(` ${slug} ${key} ${trimmed} ${ago}
7438
+ process.stdout.write(` ${slug2} ${key} ${trimmed} ${ago}
7341
7439
  `);
7342
7440
  }
7343
7441
  return EXIT.SUCCESS;
@@ -7370,11 +7468,11 @@ async function runMeMemory(flags) {
7370
7468
  }
7371
7469
  const slugWidth = Math.max(...ws.memories.map((m) => m.meshSlug.length), 6);
7372
7470
  for (const m of ws.memories) {
7373
- const slug = dim(m.meshSlug.padEnd(slugWidth));
7471
+ const slug2 = dim(m.meshSlug.padEnd(slugWidth));
7374
7472
  const ago = dim(formatRelativeTime(m.rememberedAt));
7375
7473
  const tags = m.tags.length > 0 ? " " + dim("[" + m.tags.join(", ") + "]") : "";
7376
7474
  const content = m.content.length > 240 ? m.content.slice(0, 240) + "…" : m.content;
7377
- process.stdout.write(` ${slug} ${ago}${tags}
7475
+ process.stdout.write(` ${slug2} ${ago}${tags}
7378
7476
  ${content}
7379
7477
  `);
7380
7478
  }
@@ -10158,10 +10256,10 @@ async function resolvePeer(meshSlug, name) {
10158
10256
  return { displayName: match.displayName, pubkey: key };
10159
10257
  });
10160
10258
  }
10161
- function pickMesh2(slug) {
10259
+ function pickMesh2(slug2) {
10162
10260
  const cfg = readConfig();
10163
- if (slug)
10164
- return cfg.meshes.find((m) => m.slug === slug) ? slug : null;
10261
+ if (slug2)
10262
+ return cfg.meshes.find((m) => m.slug === slug2) ? slug2 : null;
10165
10263
  return cfg.meshes[0]?.slug ?? null;
10166
10264
  }
10167
10265
  async function runGrant(peer, caps, opts = {}) {
@@ -14433,26 +14531,26 @@ __export(exports_seed_test_mesh, {
14433
14531
  runSeedTestMesh: () => runSeedTestMesh
14434
14532
  });
14435
14533
  function runSeedTestMesh(args) {
14436
- const [brokerUrl, meshId, memberId, pubkey, slug] = args;
14437
- if (!brokerUrl || !meshId || !memberId || !pubkey || !slug) {
14534
+ const [brokerUrl, meshId, memberId, pubkey, slug2] = args;
14535
+ if (!brokerUrl || !meshId || !memberId || !pubkey || !slug2) {
14438
14536
  render.err("Usage: claudemesh seed-test-mesh <broker-ws-url> <mesh-id> <member-id> <pubkey> <slug>");
14439
14537
  render.info(dim('Example: claudemesh seed-test-mesh "ws://localhost:7900/ws" mesh-123 member-abc aaa..aaa smoke-test'));
14440
14538
  process.exit(1);
14441
14539
  }
14442
14540
  const config = readConfig();
14443
- config.meshes = config.meshes.filter((m) => m.slug !== slug);
14541
+ config.meshes = config.meshes.filter((m) => m.slug !== slug2);
14444
14542
  config.meshes.push({
14445
14543
  meshId,
14446
14544
  memberId,
14447
- slug,
14448
- name: `Test: ${slug}`,
14545
+ slug: slug2,
14546
+ name: `Test: ${slug2}`,
14449
14547
  pubkey,
14450
14548
  secretKey: "dev-only-stub",
14451
14549
  brokerUrl,
14452
14550
  joinedAt: new Date().toISOString()
14453
14551
  });
14454
14552
  writeConfig(config);
14455
- render.ok(`seeded ${bold(slug)}`, dim(meshId));
14553
+ render.ok(`seeded ${bold(slug2)}`, dim(meshId));
14456
14554
  render.hint(`run ${bold("claudemesh mcp")} to connect, or register with Claude Code via ${bold("claudemesh install")}`);
14457
14555
  }
14458
14556
  var init_seed_test_mesh = __esm(() => {
@@ -15038,7 +15136,8 @@ Mesh
15038
15136
  claudemesh launch [slug] launch Claude Code on a mesh (alias: connect)
15039
15137
  claudemesh list show your meshes (alias: ls)
15040
15138
  claudemesh delete [slug] delete a mesh (alias: rm)
15041
- claudemesh rename <slug> <name> rename a mesh
15139
+ claudemesh rename <slug> <name> rename a mesh's display name (slug stays)
15140
+ claudemesh slug <old> <new> change a mesh's slug (URL-safe identifier)
15042
15141
  claudemesh share [email] share mesh (invite link / send email)
15043
15142
 
15044
15143
  Peer (resource form, recommended)
@@ -15289,6 +15388,11 @@ async function main() {
15289
15388
  process.exit(await rename2(positionals[0] ?? "", positionals[1] ?? ""));
15290
15389
  break;
15291
15390
  }
15391
+ case "slug": {
15392
+ const { slug: slug2 } = await Promise.resolve().then(() => (init_slug(), exports_slug));
15393
+ process.exit(await slug2(positionals[0] ?? "", positionals[1] ?? ""));
15394
+ break;
15395
+ }
15292
15396
  case "share":
15293
15397
  case "invite": {
15294
15398
  const { invite: invite2 } = await Promise.resolve().then(() => (init_invite(), exports_invite));
@@ -16102,4 +16206,4 @@ main().catch((err) => {
16102
16206
  process.exit(EXIT.INTERNAL_ERROR);
16103
16207
  });
16104
16208
 
16105
- //# debugId=C19F63EF3417F71E64756E2164756E21
16209
+ //# debugId=E34B419F39DEAC7964756E2164756E21