claudemesh-cli 0.1.1 → 0.1.3

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 (3) hide show
  1. package/README.md +25 -1
  2. package/dist/index.js +434 -5
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -28,6 +28,28 @@ Run the printed command, then restart Claude Code.
28
28
  claudemesh join https://claudemesh.com/join/<token>
29
29
  ```
30
30
 
31
+ ## Launch Claude Code
32
+
33
+ For real-time **push messages** from peers (messages injected mid-turn
34
+ as `<channel source="claudemesh">` system reminders), launch with:
35
+
36
+ ```sh
37
+ claudemesh launch
38
+ # or pass through any claude flags:
39
+ claudemesh launch --model opus
40
+ claudemesh launch --resume
41
+ ```
42
+
43
+ Under the hood this runs:
44
+
45
+ ```sh
46
+ claude --dangerously-load-development-channels server:claudemesh
47
+ ```
48
+
49
+ Plain `claude` still works — the MCP tools are available — but incoming
50
+ messages are **pull-only** via the `check_messages` tool instead of
51
+ being pushed to Claude immediately.
52
+
31
53
  The invite link is generated by whoever runs the mesh. It bundles the
32
54
  mesh id, expiry, signing key, and role. Your CLI verifies it,
33
55
  generates a fresh keypair, enrolls you with the broker, and persists
@@ -36,7 +58,9 @@ the result to `~/.claudemesh/config.json`.
36
58
  ## Commands
37
59
 
38
60
  ```sh
39
- claudemesh install # print MCP registration command
61
+ claudemesh install # register MCP + status hooks
62
+ claudemesh uninstall # remove MCP + status hooks
63
+ claudemesh launch [args] # launch Claude Code with push messages enabled
40
64
  claudemesh join <url> # join a mesh via invite URL
41
65
  claudemesh list # show joined meshes + identities
42
66
  claudemesh leave <slug> # leave a mesh
package/dist/index.js CHANGED
@@ -55187,7 +55187,7 @@ class BrokerClient {
55187
55187
  if (senderPubkey && nonce && ciphertext) {
55188
55188
  plaintext = await decryptDirect({ nonce, ciphertext }, senderPubkey, this.mesh.secretKey);
55189
55189
  }
55190
- if (plaintext === null && ciphertext) {
55190
+ if (plaintext === null && ciphertext && !senderPubkey) {
55191
55191
  try {
55192
55192
  plaintext = Buffer.from(ciphertext, "base64").toString("utf-8");
55193
55193
  } catch {
@@ -55333,14 +55333,18 @@ function resolveClient(to) {
55333
55333
  error: `multiple meshes joined; prefix target with "<mesh-slug>:" (joined: ${clients2.map((c) => c.meshSlug).join(", ")})`
55334
55334
  };
55335
55335
  }
55336
+ function decryptFailedWarning(senderPubkey) {
55337
+ const who = senderPubkey ? senderPubkey.slice(0, 12) + "…" : "unknown sender";
55338
+ return `⚠ message from ${who} failed to decrypt (tampered or wrong keypair)`;
55339
+ }
55336
55340
  function formatPush(p, meshSlug) {
55337
- const body = p.plaintext ?? "(decryption failed)";
55341
+ const body = p.plaintext ?? decryptFailedWarning(p.senderPubkey);
55338
55342
  return `[${meshSlug}] from ${p.senderPubkey.slice(0, 12)}… (${p.priority}, ${p.createdAt}):
55339
55343
  ${body}`;
55340
55344
  }
55341
55345
  async function startMcpServer() {
55342
55346
  const config2 = loadConfig();
55343
- const server = new Server({ name: "claudemesh", version: "0.1.1" }, {
55347
+ const server = new Server({ name: "claudemesh", version: "0.1.3" }, {
55344
55348
  capabilities: {
55345
55349
  experimental: { "claude/channel": {} },
55346
55350
  tools: {}
@@ -55441,7 +55445,7 @@ ${drained.join(`
55441
55445
  client.onPush(async (msg) => {
55442
55446
  const fromPubkey = msg.senderPubkey || "";
55443
55447
  const fromName = fromPubkey ? `peer-${fromPubkey.slice(0, 8)}` : "unknown";
55444
- const content = msg.plaintext ?? "(decryption failed)";
55448
+ const content = msg.plaintext ?? decryptFailedWarning(fromPubkey);
55445
55449
  try {
55446
55450
  await server.notification({
55447
55451
  method: "notifications/claude/channel",
@@ -55662,6 +55666,10 @@ function runInstall(args = []) {
55662
55666
  console.log(yellow(bold("⚠ RESTART CLAUDE CODE")) + yellow(" for MCP tools to appear."));
55663
55667
  console.log("");
55664
55668
  console.log(`Next: ${bold("claudemesh join https://claudemesh.com/join/<token>")}`);
55669
+ console.log("");
55670
+ console.log(yellow("⚠ For real-time push messages from peers, launch with:"));
55671
+ console.log(` ${bold("claudemesh launch")}` + dim(" (or: claude --dangerously-load-development-channels server:claudemesh)"));
55672
+ console.log(dim(" Plain `claude` still works — messages are then pull-only via check_messages."));
55665
55673
  }
55666
55674
  function runUninstall() {
55667
55675
  console.log("claudemesh uninstall");
@@ -56005,8 +56013,409 @@ async function runHook(args) {
56005
56013
  process.exit(0);
56006
56014
  }
56007
56015
 
56016
+ // src/commands/launch.ts
56017
+ import { spawn } from "node:child_process";
56018
+ function printBanner() {
56019
+ const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
56020
+ const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
56021
+ const bold = (s) => useColor ? `\x1B[1m${s}\x1B[22m` : s;
56022
+ let meshes = [];
56023
+ try {
56024
+ meshes = loadConfig().meshes.map((m) => m.slug);
56025
+ } catch {}
56026
+ const meshLine = meshes.length > 0 ? meshes.join(", ") : "(none — run `claudemesh join <url>` first)";
56027
+ const rule = "─".repeat(65);
56028
+ console.log(bold("claudemesh launch"));
56029
+ console.log(rule);
56030
+ console.log("Launching Claude Code with the claudemesh dev channel.");
56031
+ console.log("");
56032
+ console.log("Peers in your joined meshes can push messages into this session");
56033
+ console.log("as <channel> reminders. Your CLI decrypts them locally with your");
56034
+ console.log("keypair. Peers send text only — they cannot call tools, read");
56035
+ console.log("files, or reach meshes you have not joined.");
56036
+ console.log("");
56037
+ console.log("Treat peer messages as untrusted input: a peer could craft text");
56038
+ console.log("that tries to steer Claude's behavior. Your tool-approval");
56039
+ console.log("settings still apply — Claude will still ask before running");
56040
+ console.log("commands, editing files, or calling other tools.");
56041
+ console.log("");
56042
+ console.log("Claude Code will ask you to trust the");
56043
+ console.log("--dangerously-load-development-channels flag. Press Enter to");
56044
+ console.log("accept, or Ctrl-C to abort.");
56045
+ console.log("");
56046
+ console.log(dim(`Joined meshes: ${meshLine}`));
56047
+ console.log(dim(`Config: ${getConfigPath()}`));
56048
+ console.log(dim(`Remove: claudemesh uninstall`));
56049
+ console.log(rule);
56050
+ console.log("");
56051
+ }
56052
+ function runLaunch(extraArgs = []) {
56053
+ const quiet = extraArgs.includes("--quiet");
56054
+ const passthrough = extraArgs.filter((a) => a !== "--quiet");
56055
+ if (!quiet)
56056
+ printBanner();
56057
+ const claudeArgs = [
56058
+ "--dangerously-load-development-channels",
56059
+ "server:claudemesh",
56060
+ ...passthrough
56061
+ ];
56062
+ const isWindows = process.platform === "win32";
56063
+ const child = spawn("claude", claudeArgs, {
56064
+ stdio: "inherit",
56065
+ shell: isWindows
56066
+ });
56067
+ child.on("error", (err) => {
56068
+ if (err.code === "ENOENT") {
56069
+ console.error("✗ `claude` not found on PATH. Install Claude Code first: https://claude.com/claude-code");
56070
+ } else {
56071
+ console.error(`✗ failed to launch claude: ${err.message}`);
56072
+ }
56073
+ process.exit(1);
56074
+ });
56075
+ child.on("exit", (code, signal) => {
56076
+ if (signal) {
56077
+ process.kill(process.pid, signal);
56078
+ return;
56079
+ }
56080
+ process.exit(code ?? 0);
56081
+ });
56082
+ }
56083
+
56084
+ // src/commands/status.ts
56085
+ import { statSync, existsSync as existsSync3 } from "node:fs";
56086
+ // package.json
56087
+ var package_default = {
56088
+ name: "claudemesh-cli",
56089
+ version: "0.1.3",
56090
+ description: "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
56091
+ keywords: [
56092
+ "claude-code",
56093
+ "mcp",
56094
+ "model-context-protocol",
56095
+ "claudemesh",
56096
+ "peer-messaging",
56097
+ "multi-agent"
56098
+ ],
56099
+ author: "Alejandro Gutiérrez",
56100
+ license: "MIT",
56101
+ homepage: "https://claudemesh.com",
56102
+ repository: {
56103
+ type: "git",
56104
+ url: "https://github.com/alezmad/claudemesh.git",
56105
+ directory: "apps/cli"
56106
+ },
56107
+ type: "module",
56108
+ bin: {
56109
+ claudemesh: "./dist/index.js"
56110
+ },
56111
+ files: [
56112
+ "dist",
56113
+ "README.md",
56114
+ "LICENSE"
56115
+ ],
56116
+ publishConfig: {
56117
+ access: "public"
56118
+ },
56119
+ scripts: {
56120
+ build: 'bun build src/index.ts --target=node --outfile dist/index.js --banner "#!/usr/bin/env node" && chmod +x dist/index.js',
56121
+ clean: "git clean -xdf .cache .turbo dist node_modules",
56122
+ dev: "bun --hot src/index.ts",
56123
+ start: "bun src/index.ts",
56124
+ format: "prettier --check . --ignore-path ../../.gitignore",
56125
+ lint: "eslint",
56126
+ prepublishOnly: "bun run build",
56127
+ test: "vitest run",
56128
+ typecheck: "tsc --noEmit"
56129
+ },
56130
+ prettier: "@turbostarter/prettier-config",
56131
+ engines: {
56132
+ node: ">=20"
56133
+ },
56134
+ dependencies: {
56135
+ "@modelcontextprotocol/sdk": "1.27.1",
56136
+ "libsodium-wrappers": "0.7.15",
56137
+ ws: "8.20.0",
56138
+ zod: "4.1.13"
56139
+ },
56140
+ devDependencies: {
56141
+ "@turbostarter/eslint-config": "workspace:*",
56142
+ "@turbostarter/prettier-config": "workspace:*",
56143
+ "@turbostarter/tsconfig": "workspace:*",
56144
+ "@turbostarter/vitest-config": "workspace:*",
56145
+ "@types/libsodium-wrappers": "0.7.14",
56146
+ "@types/ws": "8.5.13",
56147
+ eslint: "catalog:",
56148
+ prettier: "catalog:",
56149
+ typescript: "catalog:",
56150
+ vitest: "catalog:"
56151
+ }
56152
+ };
56153
+
56154
+ // src/version.ts
56155
+ var VERSION = package_default.version;
56156
+
56157
+ // src/commands/status.ts
56158
+ async function probeBroker(url2, timeoutMs = 4000) {
56159
+ return new Promise((resolve2) => {
56160
+ const ws = new wrapper_default(url2);
56161
+ const timer = setTimeout(() => {
56162
+ try {
56163
+ ws.terminate();
56164
+ } catch {}
56165
+ resolve2({ ok: false, error: "timeout" });
56166
+ }, timeoutMs);
56167
+ ws.on("open", () => {
56168
+ clearTimeout(timer);
56169
+ try {
56170
+ ws.close();
56171
+ } catch {}
56172
+ resolve2({ ok: true });
56173
+ });
56174
+ ws.on("error", (err) => {
56175
+ clearTimeout(timer);
56176
+ resolve2({ ok: false, error: err.message });
56177
+ });
56178
+ });
56179
+ }
56180
+ async function runStatus() {
56181
+ const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
56182
+ const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
56183
+ const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
56184
+ const red = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
56185
+ console.log(`claudemesh status (v${VERSION})`);
56186
+ console.log("─".repeat(60));
56187
+ const configPath = getConfigPath();
56188
+ let configPerms = "missing";
56189
+ if (existsSync3(configPath)) {
56190
+ const st = statSync(configPath);
56191
+ const mode = (st.mode & 511).toString(8).padStart(4, "0");
56192
+ configPerms = mode === "0600" ? `${mode} ✓` : `${mode} ⚠ (expected 0600)`;
56193
+ }
56194
+ console.log(`Config: ${configPath} (${configPerms})`);
56195
+ const config2 = loadConfig();
56196
+ if (config2.meshes.length === 0) {
56197
+ console.log("");
56198
+ console.log(dim("No meshes joined. Run `claudemesh join <invite-url>` to get started."));
56199
+ process.exit(0);
56200
+ }
56201
+ console.log("");
56202
+ console.log(`Meshes (${config2.meshes.length}):`);
56203
+ const results = [];
56204
+ for (const m of config2.meshes) {
56205
+ process.stdout.write(` ${m.slug.padEnd(20)} probing ${m.brokerUrl}… `);
56206
+ const probe = await probeBroker(m.brokerUrl);
56207
+ results.push({
56208
+ slug: m.slug,
56209
+ brokerUrl: m.brokerUrl,
56210
+ pubkey: m.pubkey,
56211
+ reachable: probe.ok,
56212
+ error: probe.error
56213
+ });
56214
+ if (probe.ok) {
56215
+ console.log(green("reachable"));
56216
+ } else {
56217
+ console.log(red(`unreachable (${probe.error})`));
56218
+ }
56219
+ }
56220
+ console.log("");
56221
+ for (const r of results) {
56222
+ console.log(dim(` ${r.slug}: pubkey ${r.pubkey.slice(0, 16)}…`));
56223
+ }
56224
+ const allOk = results.every((r) => r.reachable);
56225
+ console.log("");
56226
+ if (allOk) {
56227
+ console.log(green("All meshes reachable."));
56228
+ process.exit(0);
56229
+ } else {
56230
+ const broken = results.filter((r) => !r.reachable).length;
56231
+ console.log(red(`${broken} of ${results.length} mesh(es) unreachable.`));
56232
+ process.exit(1);
56233
+ }
56234
+ }
56235
+
56236
+ // src/commands/doctor.ts
56237
+ import { existsSync as existsSync4, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
56238
+ import { homedir as homedir3, platform as platform2 } from "node:os";
56239
+ import { join as join3 } from "node:path";
56240
+ import { spawnSync as spawnSync2 } from "node:child_process";
56241
+ function checkNode() {
56242
+ const major = Number(process.versions.node.split(".")[0]);
56243
+ return {
56244
+ name: "Node.js >= 20",
56245
+ pass: major >= 20,
56246
+ detail: `v${process.versions.node}`,
56247
+ fix: "Install Node 20 or newer (https://nodejs.org)"
56248
+ };
56249
+ }
56250
+ function checkClaudeOnPath() {
56251
+ const res = platform2() === "win32" ? spawnSync2("where", ["claude"]) : spawnSync2("sh", ["-c", "command -v claude"]);
56252
+ const onPath = res.status === 0;
56253
+ const location = onPath ? res.stdout.toString().trim().split(`
56254
+ `)[0] : undefined;
56255
+ return {
56256
+ name: "claude binary on PATH",
56257
+ pass: onPath,
56258
+ detail: location,
56259
+ fix: "Install Claude Code (https://claude.com/claude-code)"
56260
+ };
56261
+ }
56262
+ function checkMcpRegistered() {
56263
+ const claudeConfig = join3(homedir3(), ".claude.json");
56264
+ if (!existsSync4(claudeConfig)) {
56265
+ return {
56266
+ name: "claudemesh MCP registered in ~/.claude.json",
56267
+ pass: false,
56268
+ fix: "Run `claudemesh install`"
56269
+ };
56270
+ }
56271
+ try {
56272
+ const cfg = JSON.parse(readFileSync3(claudeConfig, "utf-8"));
56273
+ const registered = Boolean(cfg.mcpServers?.["claudemesh"]);
56274
+ return {
56275
+ name: "claudemesh MCP registered in ~/.claude.json",
56276
+ pass: registered,
56277
+ fix: registered ? undefined : "Run `claudemesh install`"
56278
+ };
56279
+ } catch (e) {
56280
+ return {
56281
+ name: "claudemesh MCP registered in ~/.claude.json",
56282
+ pass: false,
56283
+ detail: e instanceof Error ? e.message : String(e),
56284
+ fix: "Check ~/.claude.json for JSON parse errors"
56285
+ };
56286
+ }
56287
+ }
56288
+ function checkHooksRegistered() {
56289
+ const settings = join3(homedir3(), ".claude", "settings.json");
56290
+ if (!existsSync4(settings)) {
56291
+ return {
56292
+ name: "Status hooks registered in ~/.claude/settings.json",
56293
+ pass: false,
56294
+ fix: "Run `claudemesh install` (remove --no-hooks)"
56295
+ };
56296
+ }
56297
+ try {
56298
+ const raw = readFileSync3(settings, "utf-8");
56299
+ const has = raw.includes("claudemesh hook ");
56300
+ return {
56301
+ name: "Status hooks registered in ~/.claude/settings.json",
56302
+ pass: has,
56303
+ fix: has ? undefined : "Run `claudemesh install` (remove --no-hooks)"
56304
+ };
56305
+ } catch (e) {
56306
+ return {
56307
+ name: "Status hooks registered in ~/.claude/settings.json",
56308
+ pass: false,
56309
+ detail: e instanceof Error ? e.message : String(e)
56310
+ };
56311
+ }
56312
+ }
56313
+ function checkConfigFile() {
56314
+ const path = getConfigPath();
56315
+ if (!existsSync4(path)) {
56316
+ return {
56317
+ name: "~/.claudemesh/config.json exists and parses",
56318
+ pass: true,
56319
+ detail: "not created yet (fine — no meshes joined)"
56320
+ };
56321
+ }
56322
+ try {
56323
+ loadConfig();
56324
+ const st = statSync2(path);
56325
+ const mode = (st.mode & 511).toString(8);
56326
+ const secure = platform2() === "win32" || mode === "600";
56327
+ return {
56328
+ name: "~/.claudemesh/config.json parses + chmod 0600",
56329
+ pass: secure,
56330
+ detail: platform2() === "win32" ? "chmod skipped on Windows" : `0${mode}`,
56331
+ fix: secure ? undefined : `chmod 600 ${path}`
56332
+ };
56333
+ } catch (e) {
56334
+ return {
56335
+ name: "~/.claudemesh/config.json exists and parses",
56336
+ pass: false,
56337
+ detail: e instanceof Error ? e.message : String(e),
56338
+ fix: "Inspect or delete ~/.claudemesh/config.json and re-join"
56339
+ };
56340
+ }
56341
+ }
56342
+ function checkKeypairs() {
56343
+ try {
56344
+ const cfg = loadConfig();
56345
+ if (cfg.meshes.length === 0) {
56346
+ return {
56347
+ name: "Mesh keypairs valid",
56348
+ pass: true,
56349
+ detail: "no meshes joined"
56350
+ };
56351
+ }
56352
+ for (const m of cfg.meshes) {
56353
+ if (m.pubkey.length !== 64 || !/^[0-9a-f]+$/.test(m.pubkey)) {
56354
+ return {
56355
+ name: "Mesh keypairs valid",
56356
+ pass: false,
56357
+ detail: `${m.slug}: pubkey malformed`,
56358
+ fix: `Leave + re-join the mesh: claudemesh leave ${m.slug}`
56359
+ };
56360
+ }
56361
+ if (m.secretKey.length !== 128 || !/^[0-9a-f]+$/.test(m.secretKey)) {
56362
+ return {
56363
+ name: "Mesh keypairs valid",
56364
+ pass: false,
56365
+ detail: `${m.slug}: secret key malformed`,
56366
+ fix: `Leave + re-join the mesh: claudemesh leave ${m.slug}`
56367
+ };
56368
+ }
56369
+ }
56370
+ return {
56371
+ name: "Mesh keypairs valid",
56372
+ pass: true,
56373
+ detail: `${cfg.meshes.length} mesh(es)`
56374
+ };
56375
+ } catch (e) {
56376
+ return {
56377
+ name: "Mesh keypairs valid",
56378
+ pass: false,
56379
+ detail: e instanceof Error ? e.message : String(e)
56380
+ };
56381
+ }
56382
+ }
56383
+ async function runDoctor() {
56384
+ const useColor = !process.env.NO_COLOR && process.env.TERM !== "dumb" && process.stdout.isTTY;
56385
+ const dim = (s) => useColor ? `\x1B[2m${s}\x1B[22m` : s;
56386
+ const green = (s) => useColor ? `\x1B[32m${s}\x1B[39m` : s;
56387
+ const red = (s) => useColor ? `\x1B[31m${s}\x1B[39m` : s;
56388
+ console.log(`claudemesh doctor (v${VERSION})`);
56389
+ console.log("─".repeat(60));
56390
+ const checks3 = [
56391
+ checkNode(),
56392
+ checkClaudeOnPath(),
56393
+ checkMcpRegistered(),
56394
+ checkHooksRegistered(),
56395
+ checkConfigFile(),
56396
+ checkKeypairs()
56397
+ ];
56398
+ for (const c of checks3) {
56399
+ const mark = c.pass ? green("✓") : red("✗");
56400
+ const detail = c.detail ? dim(` (${c.detail})`) : "";
56401
+ console.log(`${mark} ${c.name}${detail}`);
56402
+ if (!c.pass && c.fix) {
56403
+ console.log(dim(` → ${c.fix}`));
56404
+ }
56405
+ }
56406
+ const failing = checks3.filter((c) => !c.pass);
56407
+ console.log("");
56408
+ if (failing.length === 0) {
56409
+ console.log(green("All checks passed."));
56410
+ process.exit(0);
56411
+ } else {
56412
+ console.log(red(`${failing.length} check(s) failed.`));
56413
+ process.exit(1);
56414
+ }
56415
+ }
56416
+
56008
56417
  // src/index.ts
56009
- var HELP = `claudemesh — peer mesh for Claude Code sessions
56418
+ var HELP = `claudemesh v${VERSION} — peer mesh for Claude Code sessions
56010
56419
 
56011
56420
  Usage:
56012
56421
  claudemesh <command> [args]
@@ -56015,12 +56424,18 @@ Commands:
56015
56424
  install Register MCP + Stop/UserPromptSubmit status hooks
56016
56425
  (add --no-hooks for bare MCP registration)
56017
56426
  uninstall Remove MCP server + hooks
56427
+ launch [args] Launch Claude Code with real-time push messages enabled
56428
+ (add --quiet to skip the info banner; passes through
56429
+ extra flags, e.g. --model, --resume)
56018
56430
  join <url> Join a mesh via https://claudemesh.com/join/... URL
56019
56431
  list Show all joined meshes
56020
56432
  leave <slug> Leave a joined mesh
56433
+ status Health report: broker reachability per joined mesh
56434
+ doctor Diagnostic checks (install, config, keypairs, PATH)
56021
56435
  seed-test-mesh Dev-only: inject a mesh into config (skips invite flow)
56022
56436
  mcp Start MCP server (stdio) — invoked by Claude Code
56023
56437
  --help, -h Show this help
56438
+ --version, -v Show the CLI version
56024
56439
 
56025
56440
  Environment:
56026
56441
  CLAUDEMESH_BROKER_URL Override broker URL (default: wss://ic.claudemesh.com/ws)
@@ -56043,6 +56458,9 @@ async function main() {
56043
56458
  case "hook":
56044
56459
  await runHook(args);
56045
56460
  return;
56461
+ case "launch":
56462
+ runLaunch(args);
56463
+ return;
56046
56464
  case "join":
56047
56465
  await runJoin(args);
56048
56466
  return;
@@ -56052,9 +56470,20 @@ async function main() {
56052
56470
  case "leave":
56053
56471
  runLeave(args);
56054
56472
  return;
56473
+ case "status":
56474
+ await runStatus();
56475
+ return;
56476
+ case "doctor":
56477
+ await runDoctor();
56478
+ return;
56055
56479
  case "seed-test-mesh":
56056
56480
  runSeedTestMesh(args);
56057
56481
  return;
56482
+ case "--version":
56483
+ case "-v":
56484
+ case "version":
56485
+ console.log(VERSION);
56486
+ return;
56058
56487
  case "--help":
56059
56488
  case "-h":
56060
56489
  case "help":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemesh-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
5
5
  "keywords": [
6
6
  "claude-code",