claudemesh-cli 0.1.16 → 0.2.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.
Files changed (2) hide show
  1. package/dist/index.js +113 -12
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -6514,7 +6514,7 @@ function loadConfig() {
6514
6514
  if (!parsed || !Array.isArray(parsed.meshes)) {
6515
6515
  return { version: 1, meshes: [] };
6516
6516
  }
6517
- return { version: 1, meshes: parsed.meshes, displayName: parsed.displayName };
6517
+ return { version: 1, meshes: parsed.meshes, displayName: parsed.displayName, groups: parsed.groups };
6518
6518
  } catch (e) {
6519
6519
  throw new Error(`Failed to load ${CONFIG_PATH}: ${e instanceof Error ? e.message : String(e)}`);
6520
6520
  }
@@ -46245,13 +46245,13 @@ class StdioServerTransport {
46245
46245
  var TOOLS = [
46246
46246
  {
46247
46247
  name: "send_message",
46248
- description: "Send a message to a peer in one of your joined meshes. `to` can be a peer display name (resolved via list_peers), hex pubkey, `#channel`, or `*` for broadcast. `priority` controls delivery: `now` bypasses busy gates, `next` waits for idle (default), `low` is pull-only.",
46248
+ description: "Send a message to a peer in one of your joined meshes. `to` can be a peer display name (resolved via list_peers), hex pubkey, @group, `#channel`, or `*` for broadcast. `priority` controls delivery: `now` bypasses busy gates, `next` waits for idle (default), `low` is pull-only.",
46249
46249
  inputSchema: {
46250
46250
  type: "object",
46251
46251
  properties: {
46252
46252
  to: {
46253
46253
  type: "string",
46254
- description: "Peer name, pubkey, or #channel"
46254
+ description: "Peer name, pubkey, @group, or #channel"
46255
46255
  },
46256
46256
  message: { type: "string", description: "Message text" },
46257
46257
  priority: {
@@ -46306,6 +46306,32 @@ var TOOLS = [
46306
46306
  },
46307
46307
  required: ["status"]
46308
46308
  }
46309
+ },
46310
+ {
46311
+ name: "join_group",
46312
+ description: "Join a group with an optional role. Other peers see your group membership in list_peers.",
46313
+ inputSchema: {
46314
+ type: "object",
46315
+ properties: {
46316
+ name: { type: "string", description: "Group name (without @)" },
46317
+ role: {
46318
+ type: "string",
46319
+ description: "Your role in the group (e.g. lead, member, observer)"
46320
+ }
46321
+ },
46322
+ required: ["name"]
46323
+ }
46324
+ },
46325
+ {
46326
+ name: "leave_group",
46327
+ description: "Leave a group.",
46328
+ inputSchema: {
46329
+ type: "object",
46330
+ properties: {
46331
+ name: { type: "string", description: "Group name (without @)" }
46332
+ },
46333
+ required: ["name"]
46334
+ }
46309
46335
  }
46310
46336
  ];
46311
46337
 
@@ -46590,6 +46616,16 @@ class BrokerClient {
46590
46616
  return;
46591
46617
  this.ws.send(JSON.stringify({ type: "set_summary", summary }));
46592
46618
  }
46619
+ async joinGroup(name, role) {
46620
+ if (!this.ws || this.ws.readyState !== this.ws.OPEN)
46621
+ return;
46622
+ this.ws.send(JSON.stringify({ type: "join_group", name, role }));
46623
+ }
46624
+ async leaveGroup(name) {
46625
+ if (!this.ws || this.ws.readyState !== this.ws.OPEN)
46626
+ return;
46627
+ this.ws.send(JSON.stringify({ type: "leave_group", name }));
46628
+ }
46593
46629
  close() {
46594
46630
  this.closed = true;
46595
46631
  if (this.helloTimer)
@@ -46786,7 +46822,7 @@ async function resolveClient(to) {
46786
46822
  target = rest;
46787
46823
  }
46788
46824
  }
46789
- if (/^[0-9a-f]{64}$/.test(target) || target.startsWith("#") || target === "*") {
46825
+ if (/^[0-9a-f]{64}$/.test(target) || target.startsWith("#") || target.startsWith("@") || target === "*") {
46790
46826
  if (targetClients.length === 1) {
46791
46827
  return { client: targetClients[0], targetSpec: target };
46792
46828
  }
@@ -46852,14 +46888,16 @@ async function startMcpServer() {
46852
46888
 
46853
46889
  IMPORTANT: When you receive a <channel source="claudemesh" ...> message, RESPOND IMMEDIATELY. Do not wait until your current task is finished. Pause what you are doing, reply to the message using send_message, then resume your work. Treat incoming peer messages like a coworker tapping you on the shoulder — answer right away, even if you're in the middle of something.
46854
46890
 
46855
- Read the from_id, from_name, mesh_slug, and priority attributes to understand context. Reply by calling send_message with to set to the from_name (display name) of the sender.
46891
+ Read the from_id, from_name, mesh_slug, and priority attributes to understand context. Reply by calling send_message with to set to the from_name (display name) of the sender. The \`to\` field can be a peer name, pubkey, @group, or * for broadcast.
46856
46892
 
46857
46893
  Available tools:
46858
46894
  - list_peers: see joined meshes + their connection status
46859
- - send_message: send to a peer by display name, pubkey, #channel, or * broadcast (priority: now/next/low)
46895
+ - send_message: send to a peer by display name, pubkey, @group, #channel, or * broadcast (priority: now/next/low)
46860
46896
  - check_messages: drain buffered inbound messages (usually auto-pushed)
46861
46897
  - set_summary: 1-2 sentence summary of what you're working on
46862
46898
  - set_status: manually override your status (idle/working/dnd)
46899
+ - join_group: join a @group with optional role
46900
+ - leave_group: leave a @group
46863
46901
 
46864
46902
  Message priority:
46865
46903
  - "now": delivered immediately regardless of recipient status (use sparingly)
@@ -46904,7 +46942,8 @@ No peers connected.`);
46904
46942
  } else {
46905
46943
  const peerLines = peers.map((p) => {
46906
46944
  const summary = p.summary ? ` — "${p.summary}"` : "";
46907
- return `- **${p.displayName}** [${p.status}] (${p.pubkey.slice(0, 12)}…)${summary}`;
46945
+ const groupsStr = p.groups?.length ? ` [${p.groups.map((g) => `@${g.name}${g.role ? ":" + g.role : ""}`).join(", ")}]` : "";
46946
+ return `- **${p.displayName}** [${p.status}]${groupsStr} (${p.pubkey.slice(0, 12)}…)${summary}`;
46908
46947
  });
46909
46948
  sections.push(`${header}
46910
46949
  ${peerLines.join(`
@@ -46949,6 +46988,22 @@ ${drained.join(`
46949
46988
  await c.setStatus(s);
46950
46989
  return text(`Status set to ${s} across ${allClients().length} mesh(es).`);
46951
46990
  }
46991
+ case "join_group": {
46992
+ const { name: groupName, role } = args ?? {};
46993
+ if (!groupName)
46994
+ return text("join_group: `name` required", true);
46995
+ for (const c of allClients())
46996
+ await c.joinGroup(groupName, role);
46997
+ return text(`Joined @${groupName}${role ? ` as ${role}` : ""}`);
46998
+ }
46999
+ case "leave_group": {
47000
+ const { name: groupName } = args ?? {};
47001
+ if (!groupName)
47002
+ return text("leave_group: `name` required", true);
47003
+ for (const c of allClients())
47004
+ await c.leaveGroup(groupName);
47005
+ return text(`Left @${groupName}`);
47006
+ }
46952
47007
  default:
46953
47008
  return text(`Unknown tool: ${name}`, true);
46954
47009
  }
@@ -47582,6 +47637,8 @@ import { createInterface } from "node:readline";
47582
47637
  function parseArgs(argv) {
47583
47638
  const result = {
47584
47639
  name: null,
47640
+ role: null,
47641
+ groups: null,
47585
47642
  joinLink: null,
47586
47643
  meshSlug: null,
47587
47644
  quiet: false,
@@ -47595,6 +47652,14 @@ function parseArgs(argv) {
47595
47652
  result.name = argv[++i];
47596
47653
  } else if (arg.startsWith("--name=")) {
47597
47654
  result.name = arg.slice("--name=".length);
47655
+ } else if (arg === "--role" && i + 1 < argv.length) {
47656
+ result.role = argv[++i];
47657
+ } else if (arg.startsWith("--role=")) {
47658
+ result.role = arg.slice("--role=".length);
47659
+ } else if (arg === "--groups" && i + 1 < argv.length) {
47660
+ result.groups = argv[++i];
47661
+ } else if (arg.startsWith("--groups=")) {
47662
+ result.groups = arg.slice("--groups=".length);
47598
47663
  } else if (arg === "--join" && i + 1 < argv.length) {
47599
47664
  result.joinLink = argv[++i];
47600
47665
  } else if (arg.startsWith("--join=")) {
@@ -47640,6 +47705,23 @@ async function pickMesh(meshes) {
47640
47705
  });
47641
47706
  });
47642
47707
  }
47708
+ function parseGroupsString(raw) {
47709
+ return raw.split(",").map((s) => s.trim()).filter(Boolean).map((token) => {
47710
+ const idx = token.indexOf(":");
47711
+ if (idx === -1)
47712
+ return { name: token };
47713
+ return { name: token.slice(0, idx), role: token.slice(idx + 1) };
47714
+ });
47715
+ }
47716
+ function askLine(prompt) {
47717
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
47718
+ return new Promise((resolve2) => {
47719
+ rl.question(prompt, (answer) => {
47720
+ rl.close();
47721
+ resolve2(answer.trim());
47722
+ });
47723
+ });
47724
+ }
47643
47725
  async function confirmPermissions() {
47644
47726
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
47645
47727
  const bold = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
@@ -47671,12 +47753,14 @@ async function confirmPermissions() {
47671
47753
  });
47672
47754
  });
47673
47755
  }
47674
- function printBanner(name, meshSlug) {
47756
+ function printBanner(name, meshSlug, role, groups) {
47675
47757
  const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
47676
47758
  const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
47677
47759
  const bold = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
47760
+ const roleSuffix = role ? ` (${role})` : "";
47761
+ const groupTags = groups.length ? " [" + groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
47678
47762
  const rule = "─".repeat(60);
47679
- console.log(bold(`claudemesh launch`) + dim(` — as ${name} on ${meshSlug}`));
47763
+ console.log(bold(`claudemesh launch`) + dim(` — as ${name}${roleSuffix} on ${meshSlug}${groupTags}`));
47680
47764
  console.log(rule);
47681
47765
  console.log("Peer messages arrive as <channel> reminders in real-time.");
47682
47766
  console.log("Peers send text only — they cannot call tools or read files.");
@@ -47731,6 +47815,22 @@ async function runLaunch(extraArgs) {
47731
47815
  mesh = await pickMesh(config2.meshes);
47732
47816
  }
47733
47817
  const displayName = args.name ?? `${hostname2()}-${process.pid}`;
47818
+ let role = args.role;
47819
+ let parsedGroups = args.groups ? parseGroupsString(args.groups) : [];
47820
+ if (!args.quiet) {
47821
+ if (role === null) {
47822
+ const answer = await askLine(" Role (optional): ");
47823
+ if (answer)
47824
+ role = answer;
47825
+ }
47826
+ if (parsedGroups.length === 0 && args.groups === null) {
47827
+ const answer = await askLine(" Groups (comma-separated, optional): ");
47828
+ if (answer)
47829
+ parsedGroups = parseGroupsString(answer);
47830
+ }
47831
+ if (role || parsedGroups.length)
47832
+ console.log("");
47833
+ }
47734
47834
  const tmpBase = tmpdir();
47735
47835
  try {
47736
47836
  for (const entry of readdirSync(tmpBase)) {
@@ -47746,12 +47846,13 @@ async function runLaunch(extraArgs) {
47746
47846
  const sessionConfig = {
47747
47847
  version: 1,
47748
47848
  meshes: [mesh],
47749
- displayName
47849
+ displayName,
47850
+ ...parsedGroups.length > 0 ? { groups: parsedGroups } : {}
47750
47851
  };
47751
47852
  writeFileSync4(join4(tmpDir, "config.json"), JSON.stringify(sessionConfig, null, 2) + `
47752
47853
  `, "utf-8");
47753
47854
  if (!args.quiet) {
47754
- printBanner(displayName, mesh.slug);
47855
+ printBanner(displayName, mesh.slug, role, parsedGroups);
47755
47856
  if (!args.skipPermConfirm) {
47756
47857
  await confirmPermissions();
47757
47858
  }
@@ -47819,7 +47920,7 @@ init_config();
47819
47920
  // package.json
47820
47921
  var package_default = {
47821
47922
  name: "claudemesh-cli",
47822
- version: "0.1.16",
47923
+ version: "0.2.0",
47823
47924
  description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
47824
47925
  keywords: [
47825
47926
  "claude-code",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemesh-cli",
3
- "version": "0.1.16",
3
+ "version": "0.2.0",
4
4
  "description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
5
5
  "keywords": [
6
6
  "claude-code",