claudemesh-cli 0.6.8 → 0.6.9

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 +314 -93
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -47376,13 +47376,14 @@ var TOOLS = [
47376
47376
  },
47377
47377
  {
47378
47378
  name: "schedule_reminder",
47379
- description: "Schedule a message for future delivery. Without `to`, it fires back to yourself (a self-reminder). With `to`, it delivers to a peer, @group, or * broadcast. The broker holds it and delivers when the time arrives. Receivers see `subtype: reminder` in the push envelope.",
47379
+ description: "Schedule a one-shot or recurring message. Without `to`, it fires back to yourself (a self-reminder). With `to`, it delivers to a peer, @group, or * broadcast. For one-shot, provide `deliver_at` or `in_seconds`. For recurring, provide `cron` (standard 5-field expression). The broker persists schedules to the database they survive restarts. Receivers see `subtype: reminder` in the push envelope.",
47380
47380
  inputSchema: {
47381
47381
  type: "object",
47382
47382
  properties: {
47383
47383
  message: { type: "string", description: "Message or reminder text" },
47384
- deliver_at: { type: "number", description: "Unix timestamp (ms) when to deliver" },
47385
- in_seconds: { type: "number", description: "Alternative to deliver_at: fire after N seconds" },
47384
+ deliver_at: { type: "number", description: "Unix timestamp (ms) when to deliver (one-shot)" },
47385
+ in_seconds: { type: "number", description: "Alternative to deliver_at: fire after N seconds (one-shot)" },
47386
+ cron: { type: "string", description: "Cron expression for recurring reminders (e.g. '0 */2 * * *' for every 2 hours, '30 9 * * 1-5' for 9:30 weekdays)" },
47386
47387
  to: {
47387
47388
  type: "string",
47388
47389
  description: "Recipient: display name, pubkey hex, @group, or * (omit for self-reminder)"
@@ -47565,6 +47566,9 @@ class BrokerClient {
47565
47566
  sessionId: `${process.pid}-${Date.now()}`,
47566
47567
  pid: process.pid,
47567
47568
  cwd: process.cwd(),
47569
+ peerType: "ai",
47570
+ channel: "claude-code",
47571
+ model: process.env.CLAUDE_MODEL || undefined,
47568
47572
  timestamp,
47569
47573
  signature
47570
47574
  }));
@@ -47773,7 +47777,7 @@ class BrokerClient {
47773
47777
  return;
47774
47778
  this.ws.send(JSON.stringify({ type: "forget", memoryId }));
47775
47779
  }
47776
- async scheduleMessage(to, message, deliverAt, isReminder = false) {
47780
+ async scheduleMessage(to, message, deliverAt, isReminder = false, cron) {
47777
47781
  if (!this.ws || this.ws.readyState !== this.ws.OPEN)
47778
47782
  return null;
47779
47783
  return new Promise((resolve) => {
@@ -47788,6 +47792,7 @@ class BrokerClient {
47788
47792
  message,
47789
47793
  deliverAt,
47790
47794
  ...isReminder ? { subtype: "reminder" } : {},
47795
+ ...cron ? { cron, recurring: true } : {},
47791
47796
  _reqId: reqId
47792
47797
  }));
47793
47798
  });
@@ -48234,7 +48239,9 @@ class BrokerClient {
48234
48239
  receivedAt: new Date().toISOString(),
48235
48240
  plaintext,
48236
48241
  kind,
48237
- ...msg.subtype ? { subtype: msg.subtype } : {}
48242
+ ...msg.subtype ? { subtype: msg.subtype } : {},
48243
+ ...msg.event ? { event: String(msg.event) } : {},
48244
+ ...msg.eventData ? { eventData: msg.eventData } : {}
48238
48245
  };
48239
48246
  this.pushBuffer.push(push);
48240
48247
  if (this.pushBuffer.length > 500)
@@ -48402,7 +48409,8 @@ class BrokerClient {
48402
48409
  if (msg.type === "scheduled_ack") {
48403
48410
  this.resolveFromMap(this.scheduledAckResolvers, msgReqId, {
48404
48411
  scheduledId: String(msg.scheduledId ?? ""),
48405
- deliverAt: Number(msg.deliverAt ?? 0)
48412
+ deliverAt: Number(msg.deliverAt ?? 0),
48413
+ ...msg.cron ? { cron: String(msg.cron) } : {}
48406
48414
  });
48407
48415
  return;
48408
48416
  }
@@ -48805,7 +48813,16 @@ No peers connected.`);
48805
48813
  const peerLines = peers.map((p) => {
48806
48814
  const summary = p.summary ? ` — "${p.summary}"` : "";
48807
48815
  const groupsStr = p.groups?.length ? ` [${p.groups.map((g) => `@${g.name}${g.role ? ":" + g.role : ""}`).join(", ")}]` : "";
48808
- return `- **${p.displayName}** [${p.status}]${groupsStr} (${p.pubkey.slice(0, 12)}…)${summary}`;
48816
+ const meta2 = [];
48817
+ if (p.peerType)
48818
+ meta2.push(`type:${p.peerType}`);
48819
+ if (p.channel)
48820
+ meta2.push(`channel:${p.channel}`);
48821
+ if (p.model)
48822
+ meta2.push(`model:${p.model}`);
48823
+ const metaStr = meta2.length ? ` {${meta2.join(", ")}}` : "";
48824
+ const cwdStr = p.cwd ? ` cwd:${p.cwd}` : "";
48825
+ return `- **${p.displayName}** [${p.status}]${groupsStr}${metaStr} (${p.pubkey.slice(0, 12)}…)${cwdStr}${summary}`;
48809
48826
  });
48810
48827
  sections.push(`${header}
48811
48828
  ${peerLines.join(`
@@ -48958,13 +48975,16 @@ ${lines.join(`
48958
48975
  const sArgs = args ?? {};
48959
48976
  if (!sArgs.message)
48960
48977
  return text("schedule_reminder: `message` required", true);
48978
+ const isCron = !!sArgs.cron;
48961
48979
  let deliverAt;
48962
- if (sArgs.deliver_at) {
48980
+ if (isCron) {
48981
+ deliverAt = 0;
48982
+ } else if (sArgs.deliver_at) {
48963
48983
  deliverAt = Number(sArgs.deliver_at);
48964
48984
  } else if (sArgs.in_seconds) {
48965
48985
  deliverAt = Date.now() + Number(sArgs.in_seconds) * 1000;
48966
48986
  } else {
48967
- return text("schedule_reminder: provide `deliver_at` (ms timestamp) or `in_seconds`", true);
48987
+ return text("schedule_reminder: provide `deliver_at` (ms timestamp), `in_seconds`, or `cron` expression", true);
48968
48988
  }
48969
48989
  const isSelf = !sArgs.to;
48970
48990
  let targetSpec;
@@ -48984,9 +49004,13 @@ ${lines.join(`
48984
49004
  targetSpec = to;
48985
49005
  }
48986
49006
  }
48987
- const result = await client.scheduleMessage(targetSpec, sArgs.message, deliverAt, true);
49007
+ const result = await client.scheduleMessage(targetSpec, sArgs.message, deliverAt, true, sArgs.cron);
48988
49008
  if (!result)
48989
49009
  return text("schedule_reminder: broker did not acknowledge — check connection", true);
49010
+ if (isCron) {
49011
+ const nextFire = new Date(result.deliverAt).toISOString();
49012
+ return text(isSelf ? `Recurring self-reminder scheduled (${result.scheduledId.slice(0, 8)}): "${sArgs.message.slice(0, 60)}" — cron: ${sArgs.cron}, next fire: ${nextFire}` : `Recurring reminder to "${sArgs.to}" scheduled (${result.scheduledId.slice(0, 8)}) — cron: ${sArgs.cron}, next fire: ${nextFire}`);
49013
+ }
48990
49014
  const when = new Date(result.deliverAt).toISOString();
48991
49015
  return text(isSelf ? `Self-reminder scheduled (${result.scheduledId.slice(0, 8)}): "${sArgs.message.slice(0, 60)}" at ${when}` : `Reminder to "${sArgs.to}" scheduled (${result.scheduledId.slice(0, 8)}) for ${when}`);
48992
49016
  }
@@ -49502,6 +49526,39 @@ ${rows.join(`
49502
49526
  client2.onPush(async (msg) => {
49503
49527
  if (messageMode === "off")
49504
49528
  return;
49529
+ if (msg.subtype === "system" && msg.event) {
49530
+ const eventName = msg.event;
49531
+ const data = msg.eventData ?? {};
49532
+ let content2;
49533
+ if (eventName === "peer_joined") {
49534
+ content2 = `[system] Peer "${data.name ?? "unknown"}" joined the mesh`;
49535
+ } else if (eventName === "peer_left") {
49536
+ content2 = `[system] Peer "${data.name ?? "unknown"}" left the mesh`;
49537
+ } else {
49538
+ content2 = `[system] ${eventName}: ${JSON.stringify(data)}`;
49539
+ }
49540
+ try {
49541
+ await server.notification({
49542
+ method: "notifications/claude/channel",
49543
+ params: {
49544
+ content: content2,
49545
+ meta: {
49546
+ kind: "system",
49547
+ event: eventName,
49548
+ mesh_slug: client2.meshSlug,
49549
+ mesh_id: client2.meshId,
49550
+ ...Object.keys(data).length > 0 ? { eventData: data } : {}
49551
+ }
49552
+ }
49553
+ });
49554
+ process.stderr.write(`[claudemesh] system: ${content2}
49555
+ `);
49556
+ } catch (pushErr) {
49557
+ process.stderr.write(`[claudemesh] system push FAILED: ${pushErr}
49558
+ `);
49559
+ }
49560
+ return;
49561
+ }
49505
49562
  const fromPubkey = msg.senderPubkey || "";
49506
49563
  const fromName = fromPubkey ? await resolvePeerName(client2, fromPubkey) : "unknown";
49507
49564
  if (messageMode === "inbox") {
@@ -49725,47 +49782,51 @@ function writeClaudeSettings(obj) {
49725
49782
  `, "utf-8");
49726
49783
  }
49727
49784
  var CLAUDEMESH_TOOLS = [
49728
- "mcp__claudemesh__send_message",
49729
- "mcp__claudemesh__list_peers",
49785
+ "mcp__claudemesh__cancel_scheduled",
49730
49786
  "mcp__claudemesh__check_messages",
49731
- "mcp__claudemesh__set_summary",
49732
- "mcp__claudemesh__set_status",
49733
- "mcp__claudemesh__join_group",
49734
- "mcp__claudemesh__leave_group",
49735
- "mcp__claudemesh__get_state",
49736
- "mcp__claudemesh__set_state",
49737
- "mcp__claudemesh__list_state",
49738
- "mcp__claudemesh__remember",
49739
- "mcp__claudemesh__recall",
49787
+ "mcp__claudemesh__claim_task",
49788
+ "mcp__claudemesh__complete_task",
49789
+ "mcp__claudemesh__create_stream",
49790
+ "mcp__claudemesh__create_task",
49791
+ "mcp__claudemesh__delete_file",
49792
+ "mcp__claudemesh__file_status",
49740
49793
  "mcp__claudemesh__forget",
49741
- "mcp__claudemesh__share_file",
49794
+ "mcp__claudemesh__get_context",
49742
49795
  "mcp__claudemesh__get_file",
49743
- "mcp__claudemesh__list_files",
49744
- "mcp__claudemesh__file_status",
49745
- "mcp__claudemesh__delete_file",
49746
- "mcp__claudemesh__vector_store",
49747
- "mcp__claudemesh__vector_search",
49748
- "mcp__claudemesh__vector_delete",
49749
- "mcp__claudemesh__list_collections",
49750
- "mcp__claudemesh__graph_query",
49796
+ "mcp__claudemesh__get_state",
49797
+ "mcp__claudemesh__grant_file_access",
49751
49798
  "mcp__claudemesh__graph_execute",
49752
- "mcp__claudemesh__mesh_info",
49753
- "mcp__claudemesh__ping_mesh",
49754
- "mcp__claudemesh__message_status",
49755
- "mcp__claudemesh__share_context",
49756
- "mcp__claudemesh__get_context",
49799
+ "mcp__claudemesh__graph_query",
49800
+ "mcp__claudemesh__join_group",
49801
+ "mcp__claudemesh__leave_group",
49802
+ "mcp__claudemesh__list_collections",
49757
49803
  "mcp__claudemesh__list_contexts",
49758
- "mcp__claudemesh__create_task",
49759
- "mcp__claudemesh__claim_task",
49760
- "mcp__claudemesh__complete_task",
49761
- "mcp__claudemesh__list_tasks",
49762
- "mcp__claudemesh__create_stream",
49763
- "mcp__claudemesh__publish",
49764
- "mcp__claudemesh__subscribe",
49804
+ "mcp__claudemesh__list_files",
49805
+ "mcp__claudemesh__list_peers",
49806
+ "mcp__claudemesh__list_scheduled",
49807
+ "mcp__claudemesh__list_state",
49765
49808
  "mcp__claudemesh__list_streams",
49809
+ "mcp__claudemesh__list_tasks",
49766
49810
  "mcp__claudemesh__mesh_execute",
49811
+ "mcp__claudemesh__mesh_info",
49767
49812
  "mcp__claudemesh__mesh_query",
49768
- "mcp__claudemesh__mesh_schema"
49813
+ "mcp__claudemesh__mesh_schema",
49814
+ "mcp__claudemesh__message_status",
49815
+ "mcp__claudemesh__ping_mesh",
49816
+ "mcp__claudemesh__publish",
49817
+ "mcp__claudemesh__recall",
49818
+ "mcp__claudemesh__remember",
49819
+ "mcp__claudemesh__schedule_reminder",
49820
+ "mcp__claudemesh__send_message",
49821
+ "mcp__claudemesh__set_state",
49822
+ "mcp__claudemesh__set_status",
49823
+ "mcp__claudemesh__set_summary",
49824
+ "mcp__claudemesh__share_context",
49825
+ "mcp__claudemesh__share_file",
49826
+ "mcp__claudemesh__subscribe",
49827
+ "mcp__claudemesh__vector_delete",
49828
+ "mcp__claudemesh__vector_search",
49829
+ "mcp__claudemesh__vector_store"
49769
49830
  ];
49770
49831
  function installAllowedTools() {
49771
49832
  const settings = readClaudeSettings();
@@ -50559,7 +50620,7 @@ init_config();
50559
50620
  // package.json
50560
50621
  var package_default = {
50561
50622
  name: "claudemesh-cli",
50562
- version: "0.6.8",
50623
+ version: "0.6.9",
50563
50624
  description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
50564
50625
  keywords: [
50565
50626
  "claude-code",
@@ -51025,8 +51086,19 @@ async function runPeers(flags) {
51025
51086
  const groups = p.groups.length ? " [" + p.groups.map((g) => `@${g.name}${g.role ? `:${g.role}` : ""}`).join(", ") + "]" : "";
51026
51087
  const statusIcon = p.status === "working" ? yellow("●") : green("●");
51027
51088
  const name = bold2(p.displayName);
51089
+ const meta2 = [];
51090
+ if (p.peerType)
51091
+ meta2.push(p.peerType);
51092
+ if (p.channel)
51093
+ meta2.push(p.channel);
51094
+ if (p.model)
51095
+ meta2.push(p.model);
51096
+ const metaStr = meta2.length ? dim(` (${meta2.join(", ")})`) : "";
51097
+ const cwdStr = p.cwd ? dim(` cwd: ${p.cwd}`) : "";
51028
51098
  const summary = p.summary ? dim(` ${p.summary}`) : "";
51029
- console.log(` ${statusIcon} ${name}${groups}${summary}`);
51099
+ console.log(` ${statusIcon} ${name}${groups}${metaStr}${summary}`);
51100
+ if (cwdStr)
51101
+ console.log(` ${cwdStr}`);
51030
51102
  }
51031
51103
  console.log("");
51032
51104
  });
@@ -51313,13 +51385,15 @@ async function runRemind(flags, positional) {
51313
51385
  if (!message) {
51314
51386
  console.error("Usage: claudemesh remind <message> --in <duration>");
51315
51387
  console.error(" claudemesh remind <message> --at <time>");
51388
+ console.error(' claudemesh remind <message> --cron "0 */2 * * *"');
51316
51389
  console.error(" claudemesh remind list");
51317
51390
  console.error(" claudemesh remind cancel <id>");
51318
51391
  process.exit(1);
51319
51392
  }
51320
- const deliverAt = parseDeliverAt(flags);
51321
- if (deliverAt === null) {
51322
- console.error('Specify when: --in <duration> (e.g. "2h", "30m") or --at <time> (e.g. "15:00")');
51393
+ const isCron = !!flags.cron;
51394
+ const deliverAt = isCron ? 0 : parseDeliverAt(flags);
51395
+ if (!isCron && deliverAt === null) {
51396
+ console.error('Specify when: --in <duration> (e.g. "2h", "30m"), --at <time> (e.g. "15:00"), or --cron <expression>');
51323
51397
  process.exit(1);
51324
51398
  }
51325
51399
  await withMesh({ meshSlug: flags.mesh ?? null }, async (client2) => {
@@ -51339,7 +51413,7 @@ async function runRemind(flags, positional) {
51339
51413
  } else {
51340
51414
  targetSpec = client2.getSessionPubkey() ?? "*";
51341
51415
  }
51342
- const result = await client2.scheduleMessage(targetSpec, message, deliverAt);
51416
+ const result = await client2.scheduleMessage(targetSpec, message, deliverAt ?? 0, false, flags.cron);
51343
51417
  if (!result) {
51344
51418
  console.error("✗ Broker did not acknowledge — check connection");
51345
51419
  process.exit(1);
@@ -51348,34 +51422,170 @@ async function runRemind(flags, positional) {
51348
51422
  console.log(JSON.stringify(result));
51349
51423
  return;
51350
51424
  }
51351
- const when = new Date(result.deliverAt).toLocaleString();
51352
51425
  const toLabel = !flags.to || flags.to === "self" ? "yourself" : flags.to;
51353
- console.log(`✓ Reminder set (${result.scheduledId.slice(0, 8)}): "${message}" → ${toLabel} at ${when}`);
51426
+ if (isCron) {
51427
+ const nextFire = new Date(result.deliverAt).toLocaleString();
51428
+ console.log(`✓ Recurring reminder set (${result.scheduledId.slice(0, 8)}): "${message}" → ${toLabel} — cron: ${flags.cron}, next fire: ${nextFire}`);
51429
+ } else {
51430
+ const when = new Date(result.deliverAt).toLocaleString();
51431
+ console.log(`✓ Reminder set (${result.scheduledId.slice(0, 8)}): "${message}" → ${toLabel} at ${when}`);
51432
+ }
51354
51433
  });
51355
51434
  }
51435
+ // src/templates/dev-team.json
51436
+ var dev_team_default = {
51437
+ name: "dev-team",
51438
+ description: "Software development team with frontend, backend, and devops groups",
51439
+ groups: [
51440
+ { name: "frontend", roles: ["lead", "member"] },
51441
+ { name: "backend", roles: ["lead", "member"] },
51442
+ { name: "devops", roles: ["lead", "member"] },
51443
+ { name: "qa", roles: ["lead", "member"] }
51444
+ ],
51445
+ stateKeys: {
51446
+ sprint: "current",
51447
+ "deploy-frozen": "false",
51448
+ "pr-queue": "[]"
51449
+ },
51450
+ suggestedRoles: ["lead", "member", "reviewer"],
51451
+ systemPromptHint: "You are part of a dev team. Coordinate with @frontend, @backend, @devops groups. Check state keys for sprint status and deploy freezes before making changes."
51452
+ };
51453
+ // src/templates/research.json
51454
+ var research_default = {
51455
+ name: "research",
51456
+ description: "Research and analysis team focused on deep investigation and knowledge sharing",
51457
+ groups: [
51458
+ { name: "analysis", roles: ["lead", "analyst"] },
51459
+ { name: "writing", roles: ["lead", "writer", "reviewer"] },
51460
+ { name: "data", roles: ["engineer", "analyst"] }
51461
+ ],
51462
+ stateKeys: {
51463
+ "research-topic": "",
51464
+ phase: "exploration",
51465
+ "findings-count": "0"
51466
+ },
51467
+ suggestedRoles: ["lead", "analyst", "writer", "reviewer"],
51468
+ systemPromptHint: "You are part of a research team. Share findings via remember(), use recall() before starting new analysis. Coordinate phases through state keys."
51469
+ };
51470
+ // src/templates/ops-incident.json
51471
+ var ops_incident_default = {
51472
+ name: "ops-incident",
51473
+ description: "Incident response team with oncall, comms, and engineering groups",
51474
+ groups: [
51475
+ { name: "oncall", roles: ["primary", "secondary"] },
51476
+ { name: "comms", roles: ["lead", "scribe"] },
51477
+ { name: "engineering", roles: ["lead", "responder"] }
51478
+ ],
51479
+ stateKeys: {
51480
+ "incident-status": "investigating",
51481
+ severity: "unknown",
51482
+ commander: "",
51483
+ timeline: "[]"
51484
+ },
51485
+ suggestedRoles: ["commander", "primary-oncall", "scribe", "responder"],
51486
+ systemPromptHint: "INCIDENT MODE. Priority: now for all messages. Update incident-status state. Commander coordinates. Scribe maintains timeline. Engineering fixes."
51487
+ };
51488
+ // src/templates/simulation.json
51489
+ var simulation_default = {
51490
+ name: "simulation",
51491
+ description: "Load testing simulation with configurable time multiplier and user personas",
51492
+ groups: [
51493
+ { name: "personas", roles: ["admin", "user", "customer"] },
51494
+ { name: "observers", roles: ["monitor", "analyst"] },
51495
+ { name: "control", roles: ["orchestrator"] }
51496
+ ],
51497
+ stateKeys: {
51498
+ "clock-speed": "x1",
51499
+ "sim-status": "paused",
51500
+ "tick-count": "0",
51501
+ scenario: ""
51502
+ },
51503
+ suggestedRoles: ["orchestrator", "persona", "monitor"],
51504
+ systemPromptHint: "SIMULATION MODE. Follow the clock-speed state for time multiplier. Act according to your persona role and the simulated time. Report actions to @observers."
51505
+ };
51506
+ // src/templates/personal.json
51507
+ var personal_default = {
51508
+ name: "personal",
51509
+ description: "Private mesh for a single user — all sessions auto-join",
51510
+ groups: [],
51511
+ stateKeys: {
51512
+ focus: "",
51513
+ todos: "[]"
51514
+ },
51515
+ suggestedRoles: [],
51516
+ systemPromptHint: "Personal workspace. All your Claude Code sessions share this mesh. Use state keys to track focus and todos across sessions."
51517
+ };
51518
+
51519
+ // src/templates/index.ts
51520
+ var TEMPLATES = {
51521
+ "dev-team": dev_team_default,
51522
+ research: research_default,
51523
+ "ops-incident": ops_incident_default,
51524
+ simulation: simulation_default,
51525
+ personal: personal_default
51526
+ };
51527
+ function listTemplates() {
51528
+ return Object.values(TEMPLATES);
51529
+ }
51530
+ function getTemplate(name) {
51531
+ return TEMPLATES[name];
51532
+ }
51533
+
51534
+ // src/commands/create.ts
51535
+ function runCreate(args) {
51536
+ if (args["list-templates"]) {
51537
+ console.log(`Available mesh templates:
51538
+ `);
51539
+ for (const t of listTemplates()) {
51540
+ console.log(` ${t.name}`);
51541
+ console.log(` ${t.description}`);
51542
+ console.log(` Groups: ${t.groups.map((g) => g.name).join(", ") || "(none)"}`);
51543
+ console.log(` State keys: ${Object.keys(t.stateKeys).join(", ") || "(none)"}`);
51544
+ console.log();
51545
+ }
51546
+ return;
51547
+ }
51548
+ const templateName = args.template;
51549
+ if (templateName) {
51550
+ const template = getTemplate(templateName);
51551
+ if (!template) {
51552
+ console.error(`Unknown template "${templateName}". Use --list-templates to see available options.`);
51553
+ process.exit(1);
51554
+ }
51555
+ console.log(`Template "${template.name}" loaded:`);
51556
+ console.log(` Groups: ${template.groups.map((g) => `@${g.name}`).join(", ")}`);
51557
+ console.log(` State keys: ${Object.keys(template.stateKeys).join(", ")}`);
51558
+ console.log(` Hint: ${template.systemPromptHint.slice(0, 80)}...`);
51559
+ console.log();
51560
+ console.log("Template applied. Use `claudemesh launch` with --groups to join the predefined groups.");
51561
+ return;
51562
+ }
51563
+ console.log("Usage: claudemesh create --template <name>");
51564
+ console.log(" claudemesh create --list-templates");
51565
+ }
51356
51566
 
51357
51567
  // src/index.ts
51358
51568
  var launch = defineCommand({
51359
51569
  meta: {
51360
51570
  name: "launch",
51361
- description: "Launch Claude Code connected to a mesh with real-time peer messaging"
51571
+ description: "Spawn a Claude Code session with mesh connectivity and MCP tools"
51362
51572
  },
51363
51573
  args: {
51364
51574
  name: {
51365
51575
  type: "string",
51366
- description: "Display name for this session"
51576
+ description: "Display name visible to other peers"
51367
51577
  },
51368
51578
  role: {
51369
51579
  type: "string",
51370
- description: "Role tag (dev, lead, analyst — free-form)"
51580
+ description: "Free-form role tag: `dev`, `lead`, `analyst`, etc"
51371
51581
  },
51372
51582
  groups: {
51373
51583
  type: "string",
51374
- description: 'Groups to join: "group:role,group2"colon sets role. Hierarchy via slash: "eng/frontend:lead"'
51584
+ description: 'Groups to join as `group:role,...`e.g. `"eng/frontend:lead,qa:member"`'
51375
51585
  },
51376
51586
  mesh: {
51377
51587
  type: "string",
51378
- description: "Select mesh by slug (interactive picker if omitted and >1 joined)"
51588
+ description: "Mesh slug (interactive picker if omitted and >1 joined)"
51379
51589
  },
51380
51590
  join: {
51381
51591
  type: "string",
@@ -51383,21 +51593,21 @@ var launch = defineCommand({
51383
51593
  },
51384
51594
  "message-mode": {
51385
51595
  type: "string",
51386
- description: "push (default) | inbox | off — controls how peer messages are delivered"
51596
+ description: '`"push"` (default) | `"inbox"` | `"off"` — how peer messages arrive'
51387
51597
  },
51388
51598
  "system-prompt": {
51389
51599
  type: "string",
51390
- description: "Set Claude's system prompt for this session"
51600
+ description: "Custom system prompt for this Claude session"
51391
51601
  },
51392
51602
  yes: {
51393
51603
  type: "boolean",
51394
51604
  alias: "y",
51395
- description: "Skip permission confirmation",
51605
+ description: "Skip the --dangerously-skip-permissions confirmation",
51396
51606
  default: false
51397
51607
  },
51398
51608
  quiet: {
51399
51609
  type: "boolean",
51400
- description: "Skip banner and all interactive prompts",
51610
+ description: "Suppress banner and interactive prompts",
51401
51611
  default: false
51402
51612
  }
51403
51613
  },
@@ -51408,7 +51618,7 @@ var launch = defineCommand({
51408
51618
  var install = defineCommand({
51409
51619
  meta: {
51410
51620
  name: "install",
51411
- description: "Register MCP server + status hooks with Claude Code"
51621
+ description: "Register MCP server and status hooks with Claude Code"
51412
51622
  },
51413
51623
  args: {
51414
51624
  "no-hooks": {
@@ -51424,12 +51634,12 @@ var install = defineCommand({
51424
51634
  var join7 = defineCommand({
51425
51635
  meta: {
51426
51636
  name: "join",
51427
- description: "Join a mesh via invite URL"
51637
+ description: "Join a mesh via invite URL or token"
51428
51638
  },
51429
51639
  args: {
51430
51640
  url: {
51431
51641
  type: "positional",
51432
- description: "Invite URL (https://claudemesh.com/join/...)",
51642
+ description: "Invite URL (`https://claudemesh.com/join/...`) or token",
51433
51643
  required: true
51434
51644
  }
51435
51645
  },
@@ -51440,12 +51650,12 @@ var join7 = defineCommand({
51440
51650
  var leave = defineCommand({
51441
51651
  meta: {
51442
51652
  name: "leave",
51443
- description: "Leave a joined mesh"
51653
+ description: "Leave a joined mesh and remove its local keypair"
51444
51654
  },
51445
51655
  args: {
51446
51656
  slug: {
51447
51657
  type: "positional",
51448
- description: "Mesh slug to leave",
51658
+ description: "Mesh slug to leave (see `claudemesh list`)",
51449
51659
  required: true
51450
51660
  }
51451
51661
  },
@@ -51461,23 +51671,33 @@ var main = defineCommand({
51461
51671
  },
51462
51672
  subCommands: {
51463
51673
  launch,
51674
+ create: defineCommand({
51675
+ meta: { name: "create", description: "Create a new mesh from a template" },
51676
+ args: {
51677
+ template: { type: "string", description: "Template name: `dev-team`, `research`, `ops-incident`, `simulation`, `personal`" },
51678
+ "list-templates": { type: "boolean", description: "List available templates and exit", default: false }
51679
+ },
51680
+ run({ args }) {
51681
+ runCreate(args);
51682
+ }
51683
+ }),
51464
51684
  install,
51465
51685
  uninstall: defineCommand({
51466
- meta: { name: "uninstall", description: "Remove MCP server and hooks" },
51686
+ meta: { name: "uninstall", description: "Remove MCP server and hooks from Claude Code config" },
51467
51687
  run() {
51468
51688
  runUninstall();
51469
51689
  }
51470
51690
  }),
51471
51691
  join: join7,
51472
51692
  list: defineCommand({
51473
- meta: { name: "list", description: "Show joined meshes and identities" },
51693
+ meta: { name: "list", description: "Show joined meshes, slugs, and local identities" },
51474
51694
  run() {
51475
51695
  runList();
51476
51696
  }
51477
51697
  }),
51478
51698
  leave,
51479
51699
  peers: defineCommand({
51480
- meta: { name: "peers", description: "List connected peers in the mesh" },
51700
+ meta: { name: "peers", description: "List online peers with status, summary, and groups" },
51481
51701
  args: {
51482
51702
  mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
51483
51703
  json: { type: "boolean", description: "Output as JSON", default: false }
@@ -51487,34 +51707,34 @@ var main = defineCommand({
51487
51707
  }
51488
51708
  }),
51489
51709
  send: defineCommand({
51490
- meta: { name: "send", description: "Send a message to a peer, group, or broadcast" },
51710
+ meta: { name: "send", description: "Send a message to a peer, group, or all peers" },
51491
51711
  args: {
51492
- to: { type: "positional", description: "Recipient: display name, @group, pubkey, or *", required: true },
51712
+ to: { type: "positional", description: "Recipient: display name, `@group`, `*` (broadcast), or pubkey hex", required: true },
51493
51713
  message: { type: "positional", description: "Message text", required: true },
51494
51714
  mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
51495
- priority: { type: "string", description: "now | next (default) | low" }
51715
+ priority: { type: "string", description: '`"now"` | `"next"` (default) | `"low"`' }
51496
51716
  },
51497
51717
  async run({ args }) {
51498
51718
  await runSend(args, args.to, args.message);
51499
51719
  }
51500
51720
  }),
51501
51721
  inbox: defineCommand({
51502
- meta: { name: "inbox", description: "Read pending peer messages" },
51722
+ meta: { name: "inbox", description: "Drain pending inbound messages" },
51503
51723
  args: {
51504
51724
  mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
51505
51725
  json: { type: "boolean", description: "Output as JSON", default: false },
51506
- wait: { type: "string", description: "Seconds to wait for broker delivery (default: 1)" }
51726
+ wait: { type: "string", description: "Seconds to wait for broker delivery (default: `1`)" }
51507
51727
  },
51508
51728
  async run({ args }) {
51509
51729
  await runInbox({ ...args, wait: args.wait ? parseInt(args.wait, 10) : undefined });
51510
51730
  }
51511
51731
  }),
51512
51732
  state: defineCommand({
51513
- meta: { name: "state", description: "Read or write shared mesh state" },
51733
+ meta: { name: "state", description: "Get, set, or list shared key-value state in the mesh" },
51514
51734
  args: {
51515
- action: { type: "positional", description: "get | set | list", required: true },
51516
- key: { type: "positional", description: "State key (required for get/set)" },
51517
- value: { type: "positional", description: "Value to set (required for set)" },
51735
+ action: { type: "positional", description: "`get <key>` | `set <key> <value>` | `list`", required: true },
51736
+ key: { type: "positional", description: "State key (required for `get` and `set`)" },
51737
+ value: { type: "positional", description: "Value to store (required for `set`)" },
51518
51738
  mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
51519
51739
  json: { type: "boolean", description: "Output as JSON", default: false }
51520
51740
  },
@@ -51550,11 +51770,11 @@ var main = defineCommand({
51550
51770
  }
51551
51771
  }),
51552
51772
  remember: defineCommand({
51553
- meta: { name: "remember", description: "Store a memory in the mesh (accessible to all peers)" },
51773
+ meta: { name: "remember", description: "Store a persistent memory visible to all peers" },
51554
51774
  args: {
51555
- content: { type: "positional", description: "Text to remember", required: true },
51775
+ content: { type: "positional", description: "Text to store", required: true },
51556
51776
  mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
51557
- tags: { type: "string", description: "Comma-separated tags (e.g. task,context)" },
51777
+ tags: { type: "string", description: "Comma-separated tags, e.g. `task,context`" },
51558
51778
  json: { type: "boolean", description: "Output as JSON", default: false }
51559
51779
  },
51560
51780
  async run({ args }) {
@@ -51562,9 +51782,9 @@ var main = defineCommand({
51562
51782
  }
51563
51783
  }),
51564
51784
  recall: defineCommand({
51565
- meta: { name: "recall", description: "Search mesh memory by keyword or phrase" },
51785
+ meta: { name: "recall", description: "Search mesh memories by keyword or phrase" },
51566
51786
  args: {
51567
- query: { type: "positional", description: "Search query", required: true },
51787
+ query: { type: "positional", description: "Full-text search query", required: true },
51568
51788
  mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
51569
51789
  json: { type: "boolean", description: "Output as JSON", default: false }
51570
51790
  },
@@ -51573,13 +51793,14 @@ var main = defineCommand({
51573
51793
  }
51574
51794
  }),
51575
51795
  remind: defineCommand({
51576
- meta: { name: "remind", description: "Schedule a reminder or delayed message via the broker" },
51796
+ meta: { name: "remind", description: "Schedule a delayed message. Also: `remind list`, `remind cancel <id>`" },
51577
51797
  args: {
51578
- message: { type: "positional", description: "Message text, or: list | cancel <id>", required: false },
51579
- extra: { type: "positional", description: "Additional positional args", required: false },
51580
- in: { type: "string", description: 'Deliver after duration: "2h", "30m", "90s"' },
51581
- at: { type: "string", description: 'Deliver at time: "15:00" or ISO timestamp' },
51582
- to: { type: "string", description: "Recipient (default: self). Name, @group, pubkey, or *" },
51798
+ message: { type: "positional", description: "Message text or `list` / `cancel <id>` to manage reminders", required: false },
51799
+ extra: { type: "positional", description: "Reminder ID for `cancel`", required: false },
51800
+ in: { type: "string", description: 'Deliver after duration: `"2h"`, `"30m"`, `"90s"`' },
51801
+ at: { type: "string", description: 'Deliver at time: `"15:00"` or ISO timestamp' },
51802
+ cron: { type: "string", description: 'Recurring cron expression: `"0 */2 * * *"` (every 2h), `"30 9 * * 1-5"` (9:30 weekdays)' },
51803
+ to: { type: "string", description: "Recipient (default: self). Name, `@group`, `*`, or pubkey" },
51583
51804
  mesh: { type: "string", description: "Mesh slug (auto-selected if only one joined)" },
51584
51805
  json: { type: "boolean", description: "Output as JSON", default: false }
51585
51806
  },
@@ -51589,31 +51810,31 @@ var main = defineCommand({
51589
51810
  }
51590
51811
  }),
51591
51812
  status: defineCommand({
51592
- meta: { name: "status", description: "Check broker reachability for each joined mesh" },
51813
+ meta: { name: "status", description: "Check broker connectivity for each joined mesh" },
51593
51814
  async run() {
51594
51815
  await runStatus();
51595
51816
  }
51596
51817
  }),
51597
51818
  doctor: defineCommand({
51598
- meta: { name: "doctor", description: "Diagnose install, config, keypairs, and PATH" },
51819
+ meta: { name: "doctor", description: "Diagnose install, config, keypairs, and PATH issues" },
51599
51820
  async run() {
51600
51821
  await runDoctor();
51601
51822
  }
51602
51823
  }),
51603
51824
  mcp: defineCommand({
51604
- meta: { name: "mcp", description: "Start MCP server (stdio invoked by Claude Code, not users)" },
51825
+ meta: { name: "mcp", description: "Start MCP server on stdio (called by Claude Code, not users)" },
51605
51826
  async run() {
51606
51827
  await startMcpServer();
51607
51828
  }
51608
51829
  }),
51609
51830
  "seed-test-mesh": defineCommand({
51610
- meta: { name: "seed-test-mesh", description: "Dev only: inject a mesh into config (skips invite flow)" },
51831
+ meta: { name: "seed-test-mesh", description: "Dev: inject a mesh into local config, skip invite flow" },
51611
51832
  run({ rawArgs }) {
51612
51833
  runSeedTestMesh(rawArgs);
51613
51834
  }
51614
51835
  }),
51615
51836
  hook: defineCommand({
51616
- meta: { name: "hook", description: "Internal hook handler (invoked by Claude Code hooks)" },
51837
+ meta: { name: "hook", description: "Internal: handle Claude Code hook events" },
51617
51838
  async run({ rawArgs }) {
51618
51839
  await runHook(rawArgs);
51619
51840
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemesh-cli",
3
- "version": "0.6.8",
3
+ "version": "0.6.9",
4
4
  "description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -48,10 +48,10 @@
48
48
  "prettier": "3.6.2",
49
49
  "typescript": "5.9.3",
50
50
  "vitest": "4.0.14",
51
- "@turbostarter/prettier-config": "0.1.0",
52
51
  "@turbostarter/eslint-config": "0.1.0",
53
- "@turbostarter/vitest-config": "0.1.0",
54
- "@turbostarter/tsconfig": "0.1.0"
52
+ "@turbostarter/prettier-config": "0.1.0",
53
+ "@turbostarter/tsconfig": "0.1.0",
54
+ "@turbostarter/vitest-config": "0.1.0"
55
55
  },
56
56
  "scripts": {
57
57
  "build": "bun build src/index.ts --target=node --outfile dist/index.js --banner \"#!/usr/bin/env node\" && chmod +x dist/index.js",