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.
- package/README.md +25 -1
- package/dist/index.js +86 -4
- 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 #
|
|
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 ??
|
|
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.
|
|
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 ??
|
|
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;
|