claudemesh-cli 0.1.1 → 0.1.2

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 +86 -4
  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.2" }, {
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,6 +56013,74 @@ 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
+
56008
56084
  // src/index.ts
56009
56085
  var HELP = `claudemesh — peer mesh for Claude Code sessions
56010
56086
 
@@ -56015,6 +56091,9 @@ Commands:
56015
56091
  install Register MCP + Stop/UserPromptSubmit status hooks
56016
56092
  (add --no-hooks for bare MCP registration)
56017
56093
  uninstall Remove MCP server + hooks
56094
+ launch [args] Launch Claude Code with real-time push messages enabled
56095
+ (add --quiet to skip the info banner; passes through
56096
+ extra flags, e.g. --model, --resume)
56018
56097
  join <url> Join a mesh via https://claudemesh.com/join/... URL
56019
56098
  list Show all joined meshes
56020
56099
  leave <slug> Leave a joined mesh
@@ -56043,6 +56122,9 @@ async function main() {
56043
56122
  case "hook":
56044
56123
  await runHook(args);
56045
56124
  return;
56125
+ case "launch":
56126
+ runLaunch(args);
56127
+ return;
56046
56128
  case "join":
56047
56129
  await runJoin(args);
56048
56130
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudemesh-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Claude Code MCP client for claudemesh — peer mesh messaging between Claude sessions.",
5
5
  "keywords": [
6
6
  "claude-code",