claudemesh-cli 1.34.2 → 1.34.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.
- package/dist/entrypoints/cli.js +113 -58
- package/dist/entrypoints/cli.js.map +4 -4
- package/dist/entrypoints/mcp.js +134 -54
- package/dist/entrypoints/mcp.js.map +5 -4
- package/package.json +1 -1
- package/skills/claudemesh/SKILL.md +18 -7
package/dist/entrypoints/cli.js
CHANGED
|
@@ -104,7 +104,7 @@ __export(exports_urls, {
|
|
|
104
104
|
VERSION: () => VERSION,
|
|
105
105
|
URLS: () => URLS
|
|
106
106
|
});
|
|
107
|
-
var URLS, VERSION = "1.34.
|
|
107
|
+
var URLS, VERSION = "1.34.3", env;
|
|
108
108
|
var init_urls = __esm(() => {
|
|
109
109
|
URLS = {
|
|
110
110
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -15721,9 +15721,13 @@ description: Use when the user asks to send a message to a peer Claude session,
|
|
|
15721
15721
|
|
|
15722
15722
|
**You invoke claudemesh exclusively through the \`claudemesh\` CLI via Bash.** There are no MCP tools to call — \`tools/list\` returns empty for the claudemesh MCP server. The MCP server exists only to deliver inbound peer messages as \`<channel source="claudemesh">\` interrupts mid-turn. Everything else is CLI.
|
|
15723
15723
|
|
|
15724
|
+
## Launch welcome (\`kind: "welcome"\`) — 1.34.2+
|
|
15725
|
+
|
|
15726
|
+
5 seconds after Claude Code attaches to claudemesh via \`claudemesh launch\`, the MCP server emits ONE \`<channel source="claudemesh">\` push with \`meta.kind: "welcome"\`. It carries identity (\`self_display_name\`, \`self_session_pubkey\`, \`self_role\`), the active \`mesh_slug\`, live \`peer_count\` + \`peer_names\`, recent \`unread_count\` + \`latest_message_ids\`, and a CLI hint line. Treat it as the "mesh is connected" handshake — read it once, internalize identity + peers + inbox state, and use it to decide whether to act on unread items right away. Do NOT reply to a welcome push the way you reply to a DM; it has no sender.
|
|
15727
|
+
|
|
15724
15728
|
## When you receive a \`<channel source="claudemesh">\` message
|
|
15725
15729
|
|
|
15726
|
-
Respond IMMEDIATELY. Pause your current task, reply via \`claudemesh send\`, then resume. Read \`from_name\`, \`mesh_slug\`, and \`priority\` from the channel attributes. Reply by setting \`<to>\` to the sender's \`from_name\`. Do not ignore low-priority messages — acknowledge them briefly even if you defer action. If the channel meta contains \`subtype: reminder\`, this is a scheduled reminder you set yourself — act on it.
|
|
15730
|
+
Respond IMMEDIATELY (unless \`meta.kind\` is \`"welcome"\` or \`"system"\` — those are informational, no reply needed). Pause your current task, reply via \`claudemesh send\`, then resume. Read \`from_name\`, \`mesh_slug\`, and \`priority\` from the channel attributes. Reply by setting \`<to>\` to the sender's \`from_name\`. Do not ignore low-priority messages — acknowledge them briefly even if you defer action. If the channel meta contains \`subtype: reminder\`, this is a scheduled reminder you set yourself — act on it.
|
|
15727
15731
|
|
|
15728
15732
|
### Channel attributes (everything you need to reply is in the push)
|
|
15729
15733
|
|
|
@@ -15731,14 +15735,17 @@ The \`<channel>\` interrupt carries these attributes — no lookup needed:
|
|
|
15731
15735
|
|
|
15732
15736
|
| Attribute | What it is |
|
|
15733
15737
|
|---|---|
|
|
15734
|
-
| \`from_name\` | Sender's display name. **Use as \`to\` in your reply** for DMs. |
|
|
15735
|
-
| \`from_pubkey\` | Sender's session pubkey (hex).
|
|
15736
|
-
| \`
|
|
15738
|
+
| \`from_name\` | Sender's display name. **Use as \`to\` in your reply** for DMs. Empty/absent on \`kind: "welcome"\` and \`kind: "system"\`. |
|
|
15739
|
+
| \`from_pubkey\` | Sender's **session pubkey** (hex, ephemeral per-launch). Since 1.34.0 this is the session pubkey of the launched session that originated the send, NOT the daemon's stable member pubkey — sibling sessions of the same human are correctly disambiguated. |
|
|
15740
|
+
| \`from_session_pubkey\` | Same as \`from_pubkey\` for session-originated DMs. Kept as a separate key so the model never confuses session vs member identity when a control-plane source is involved. |
|
|
15741
|
+
| \`from_member_id\` / \`from_member_pubkey\` | Sender's stable mesh.member id / pubkey. Survives display-name and session rotation. Use to recognize "the same human across multiple Claude Code windows". |
|
|
15737
15742
|
| \`mesh_slug\` | Mesh the message arrived on. Pass via \`--mesh <slug>\` if the parent isn't on the same mesh. |
|
|
15738
15743
|
| \`priority\` | \`now\` / \`next\` / \`low\`. |
|
|
15739
15744
|
| \`message_id\` | Server-side id of THIS message. **Pass to \`--reply-to <id>\` to thread your reply** in topic posts. |
|
|
15745
|
+
| \`client_message_id\` | Sender-stable idempotency id (UUID). Survives broker restarts; safe to log. |
|
|
15740
15746
|
| \`topic\` | Set when the source is a topic post. Reply via \`topic post <topic> --reply-to <message_id>\`. |
|
|
15741
15747
|
| \`reply_to_id\` | Set when the message itself is a reply to a previous one — render thread context. |
|
|
15748
|
+
| \`kind\` (welcome/system meta only) | \`"welcome"\` for the launch handshake, \`"system"\` for peer_join/peer_leave/etc. — neither needs a reply. |
|
|
15742
15749
|
|
|
15743
15750
|
**Reply patterns:**
|
|
15744
15751
|
|
|
@@ -16082,15 +16089,19 @@ claudemesh message send <p> "..." --priority now # bypass busy gates
|
|
|
16082
16089
|
claudemesh message send <p> "..." --priority next # default
|
|
16083
16090
|
claudemesh message send <p> "..." --priority low # pull-only
|
|
16084
16091
|
|
|
16085
|
-
# inbox (alias: claudemesh inbox)
|
|
16086
|
-
claudemesh
|
|
16087
|
-
claudemesh
|
|
16092
|
+
# inbox (alias: claudemesh inbox) — 1.34.0+ reads from inbox.db via daemon IPC
|
|
16093
|
+
claudemesh inbox # all attached meshes, last 100
|
|
16094
|
+
claudemesh inbox --mesh <slug> # scoped to one mesh
|
|
16095
|
+
claudemesh inbox --mesh <slug> --limit 20 # custom cap
|
|
16096
|
+
claudemesh inbox --json # full row (sender_pubkey, mesh, body, received_at, …)
|
|
16088
16097
|
|
|
16089
16098
|
# delivery status (alias: claudemesh msg-status <id>)
|
|
16090
16099
|
claudemesh message status <message-id>
|
|
16091
16100
|
claudemesh message status <message-id> --json
|
|
16092
16101
|
\`\`\`
|
|
16093
16102
|
|
|
16103
|
+
**Inbox source (1.34.0+):** \`claudemesh inbox\` queries the daemon's persistent \`~/.claudemesh/daemon/inbox.db\` over IPC — it is NOT a fresh broker-WS buffer drain. Rows survive daemon restarts. Sender attribution is the actual session pubkey of the launched session that originated the send (NOT the stable member pubkey of the sender's daemon), so two sibling sessions of the same human appear as distinct rows.
|
|
16104
|
+
|
|
16094
16105
|
\`send\` JSON output: \`{"ok": true, "messageId": "...", "target": "..."}\`. Errors: \`{"ok": false, "error": "..."}\`.
|
|
16095
16106
|
|
|
16096
16107
|
### \`state\` — shared per-mesh key-value store
|
|
@@ -18170,9 +18181,12 @@ function bailNoDaemon() {
|
|
|
18170
18181
|
`);
|
|
18171
18182
|
process.exit(1);
|
|
18172
18183
|
}
|
|
18173
|
-
function daemonGet(path2) {
|
|
18184
|
+
function daemonGet(path2, opts = {}) {
|
|
18174
18185
|
return new Promise((resolve3, reject) => {
|
|
18175
|
-
const
|
|
18186
|
+
const headers = {};
|
|
18187
|
+
if (opts.sessionToken)
|
|
18188
|
+
headers.Authorization = `ClaudeMesh-Session ${opts.sessionToken}`;
|
|
18189
|
+
const req = httpRequest2({ socketPath: DAEMON_PATHS.SOCK_FILE, path: path2, method: "GET", timeout: 5000, headers }, (res) => {
|
|
18176
18190
|
const chunks = [];
|
|
18177
18191
|
res.on("data", (c) => chunks.push(c));
|
|
18178
18192
|
res.on("end", () => {
|
|
@@ -18469,9 +18483,8 @@ ${mf.allowed_tools.map((t) => ` - ${t}`).join(`
|
|
|
18469
18483
|
const transport = new StdioServerTransport;
|
|
18470
18484
|
await server.connect(transport);
|
|
18471
18485
|
const WELCOME_DELAY_MS = 5000;
|
|
18472
|
-
const WELCOME_LOOKBACK_MS = 24 * 60 * 60 * 1000;
|
|
18473
18486
|
setTimeout(() => {
|
|
18474
|
-
|
|
18487
|
+
emitMeshWelcome(server, mcpLog);
|
|
18475
18488
|
}, WELCOME_DELAY_MS);
|
|
18476
18489
|
const keepalive = setInterval(() => {}, 1000);
|
|
18477
18490
|
const shutdown = () => {
|
|
@@ -18482,52 +18495,83 @@ ${mf.allowed_tools.map((t) => ` - ${t}`).join(`
|
|
|
18482
18495
|
process.on("SIGTERM", shutdown);
|
|
18483
18496
|
process.on("SIGINT", shutdown);
|
|
18484
18497
|
}
|
|
18485
|
-
async function
|
|
18486
|
-
const
|
|
18487
|
-
const
|
|
18488
|
-
let
|
|
18498
|
+
async function emitMeshWelcome(server, mcpLog) {
|
|
18499
|
+
const { readSessionTokenFromEnv: readSessionTokenFromEnv2 } = await Promise.resolve().then(() => (init_token(), exports_token));
|
|
18500
|
+
const sessionToken = readSessionTokenFromEnv2();
|
|
18501
|
+
let selfDisplayName;
|
|
18502
|
+
let selfSessionPubkey;
|
|
18503
|
+
let selfMeshSlug;
|
|
18504
|
+
let selfRole;
|
|
18505
|
+
if (sessionToken) {
|
|
18506
|
+
try {
|
|
18507
|
+
const { status, body } = await daemonGet("/v1/sessions/me", { sessionToken });
|
|
18508
|
+
if (status === 200 && body?.session) {
|
|
18509
|
+
selfDisplayName = body.session.displayName;
|
|
18510
|
+
selfMeshSlug = body.session.mesh;
|
|
18511
|
+
selfRole = body.session.role;
|
|
18512
|
+
selfSessionPubkey = body.session.presence?.sessionPubkey;
|
|
18513
|
+
}
|
|
18514
|
+
} catch (e) {
|
|
18515
|
+
mcpLog("welcome_self_lookup_failed", { err: String(e) });
|
|
18516
|
+
}
|
|
18517
|
+
}
|
|
18518
|
+
let peerCount = -1;
|
|
18519
|
+
let peerNames = [];
|
|
18489
18520
|
try {
|
|
18490
|
-
const
|
|
18491
|
-
|
|
18492
|
-
|
|
18493
|
-
|
|
18521
|
+
const path2 = selfMeshSlug ? `/v1/peers?mesh=${encodeURIComponent(selfMeshSlug)}` : "/v1/peers";
|
|
18522
|
+
const { status, body } = await daemonGet(path2, { sessionToken });
|
|
18523
|
+
if (status === 200 && Array.isArray(body?.peers)) {
|
|
18524
|
+
const peers = body.peers;
|
|
18525
|
+
const real = peers.filter((p) => p.peerRole !== "control-plane" && p.pubkey !== selfSessionPubkey);
|
|
18526
|
+
peerCount = real.length;
|
|
18527
|
+
peerNames = real.map((p) => String(p.displayName ?? "unknown")).filter((n, i, arr) => arr.indexOf(n) === i).slice(0, 5);
|
|
18494
18528
|
}
|
|
18495
|
-
body = res.body;
|
|
18496
18529
|
} catch (e) {
|
|
18497
|
-
mcpLog("
|
|
18498
|
-
return;
|
|
18530
|
+
mcpLog("welcome_peers_lookup_failed", { err: String(e) });
|
|
18499
18531
|
}
|
|
18500
|
-
const
|
|
18501
|
-
|
|
18502
|
-
|
|
18503
|
-
|
|
18532
|
+
const sinceIso = new Date(Date.now() - 86400000).toISOString();
|
|
18533
|
+
const inboxPath = selfMeshSlug ? `/v1/inbox?mesh=${encodeURIComponent(selfMeshSlug)}&since=${encodeURIComponent(sinceIso)}&limit=20` : `/v1/inbox?since=${encodeURIComponent(sinceIso)}&limit=20`;
|
|
18534
|
+
let inboxItems = [];
|
|
18535
|
+
try {
|
|
18536
|
+
const { status, body } = await daemonGet(inboxPath, { sessionToken });
|
|
18537
|
+
if (status === 200 && Array.isArray(body?.items)) {
|
|
18538
|
+
inboxItems = body.items;
|
|
18539
|
+
}
|
|
18540
|
+
} catch (e) {
|
|
18541
|
+
mcpLog("welcome_inbox_lookup_failed", { err: String(e) });
|
|
18542
|
+
}
|
|
18543
|
+
const lines = [];
|
|
18544
|
+
const idTag = selfDisplayName ? `${selfDisplayName}${selfSessionPubkey ? ` (${selfSessionPubkey.slice(0, 8)})` : ""}${selfRole ? ` [${selfRole}]` : ""}` : "session";
|
|
18545
|
+
const meshTag = selfMeshSlug ? ` on mesh \`${selfMeshSlug}\`` : "";
|
|
18546
|
+
lines.push(`\uD83C\uDF10 [welcome] claudemesh connected — you are **${idTag}**${meshTag}.`);
|
|
18547
|
+
if (peerCount === 0) {
|
|
18548
|
+
lines.push(`\uD83D\uDC65 No other peers online right now.`);
|
|
18549
|
+
} else if (peerCount > 0) {
|
|
18550
|
+
const namesPreview = peerNames.join(", ");
|
|
18551
|
+
const more = peerCount > peerNames.length ? ` …and ${peerCount - peerNames.length} more` : "";
|
|
18552
|
+
lines.push(`\uD83D\uDC65 ${peerCount} peer${peerCount === 1 ? "" : "s"} online: ${namesPreview}${more}`);
|
|
18553
|
+
} else {
|
|
18554
|
+
lines.push(`\uD83D\uDC65 Peer list unavailable (daemon query failed).`);
|
|
18504
18555
|
}
|
|
18505
|
-
|
|
18506
|
-
|
|
18507
|
-
|
|
18508
|
-
|
|
18509
|
-
|
|
18510
|
-
|
|
18511
|
-
|
|
18512
|
-
|
|
18513
|
-
|
|
18514
|
-
|
|
18515
|
-
|
|
18516
|
-
|
|
18517
|
-
|
|
18518
|
-
|
|
18519
|
-
|
|
18520
|
-
|
|
18521
|
-
|
|
18556
|
+
if (inboxItems.length === 0) {
|
|
18557
|
+
lines.push(`\uD83D\uDCE5 Inbox is empty (last 24h).`);
|
|
18558
|
+
} else {
|
|
18559
|
+
lines.push(`\uD83D\uDCE5 ${inboxItems.length} message${inboxItems.length === 1 ? "" : "s"} in inbox (last 24h):`);
|
|
18560
|
+
for (const it of inboxItems.slice(0, 3)) {
|
|
18561
|
+
const sender = String(it.sender_name ?? "unknown");
|
|
18562
|
+
const senderPub = String(it.sender_pubkey ?? "").slice(0, 8);
|
|
18563
|
+
const tag = sender !== senderPub ? `${sender} (${senderPub})` : senderPub;
|
|
18564
|
+
const bodyText = (typeof it.body === "string" ? it.body : "(encrypted)").slice(0, 60);
|
|
18565
|
+
const time = it.received_at ? new Date(String(it.received_at)).toLocaleTimeString() : "";
|
|
18566
|
+
lines.push(` ${tag} ${time}: ${bodyText}`);
|
|
18567
|
+
}
|
|
18568
|
+
if (inboxItems.length > 3)
|
|
18569
|
+
lines.push(` …and ${inboxItems.length - 3} more`);
|
|
18570
|
+
}
|
|
18571
|
+
lines.push(`\uD83D\uDCA1 Use: \`claudemesh peer list\` · \`claudemesh send <peer> <msg>\` · \`claudemesh inbox\``);
|
|
18572
|
+
lines.push(`\uD83D\uDCDA Read the \`claudemesh\` skill (SKILL.md) for full CLI / channel / inbox reference if not yet in context.`);
|
|
18573
|
+
const content = lines.join(`
|
|
18522
18574
|
`);
|
|
18523
|
-
const remainder = items.length > 3 ? `
|
|
18524
|
-
…and ${items.length - 3} more` : "";
|
|
18525
|
-
const meshList = [...byMesh.keys()].filter(Boolean).join(", ");
|
|
18526
|
-
const header = `\uD83D\uDCE5 [welcome] ${items.length} message${items.length === 1 ? "" : "s"} in inbox from the last 24h${meshList ? ` (${meshList})` : ""}`;
|
|
18527
|
-
const footer = `
|
|
18528
|
-
Run \`claudemesh inbox\` for full content.`;
|
|
18529
|
-
const content = `${header}
|
|
18530
|
-
${preview}${remainder}${footer}`;
|
|
18531
18575
|
try {
|
|
18532
18576
|
await server.notification({
|
|
18533
18577
|
method: "notifications/claude/channel",
|
|
@@ -18535,13 +18579,22 @@ ${preview}${remainder}${footer}`;
|
|
|
18535
18579
|
content,
|
|
18536
18580
|
meta: {
|
|
18537
18581
|
kind: "welcome",
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
|
|
18582
|
+
self_display_name: selfDisplayName ?? "",
|
|
18583
|
+
self_session_pubkey: selfSessionPubkey ?? "",
|
|
18584
|
+
self_role: selfRole ?? "",
|
|
18585
|
+
mesh_slug: selfMeshSlug ?? "",
|
|
18586
|
+
peer_count: peerCount >= 0 ? peerCount : null,
|
|
18587
|
+
peer_names: peerNames,
|
|
18588
|
+
unread_count: inboxItems.length,
|
|
18589
|
+
latest_message_ids: inboxItems.slice(0, 10).map((it) => String(it.id ?? ""))
|
|
18541
18590
|
}
|
|
18542
18591
|
}
|
|
18543
18592
|
});
|
|
18544
|
-
mcpLog("welcome_emitted", {
|
|
18593
|
+
mcpLog("welcome_emitted", {
|
|
18594
|
+
mesh: selfMeshSlug ?? "",
|
|
18595
|
+
peer_count: peerCount,
|
|
18596
|
+
unread_count: inboxItems.length
|
|
18597
|
+
});
|
|
18545
18598
|
} catch (err) {
|
|
18546
18599
|
mcpLog("welcome_emit_failed", { err: String(err) });
|
|
18547
18600
|
}
|
|
@@ -19416,7 +19469,9 @@ Message (resource form)
|
|
|
19416
19469
|
[--self] (allow targeting your own member/session pubkey;
|
|
19417
19470
|
fans out to every sibling session of your member)
|
|
19418
19471
|
[--json] (machine-readable result)
|
|
19419
|
-
claudemesh message inbox
|
|
19472
|
+
claudemesh message inbox read persisted inbox (alias: inbox)
|
|
19473
|
+
flags: [--mesh <slug>] [--limit N] [--json]
|
|
19474
|
+
reads ~/.claudemesh/daemon/inbox.db via daemon
|
|
19420
19475
|
claudemesh message status <id> delivery status (alias: msg-status)
|
|
19421
19476
|
|
|
19422
19477
|
Memory (resource form)
|
|
@@ -20582,4 +20637,4 @@ main().catch((err) => {
|
|
|
20582
20637
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
20583
20638
|
});
|
|
20584
20639
|
|
|
20585
|
-
//# debugId=
|
|
20640
|
+
//# debugId=1E35EC1C4AC8296064756E2164756E21
|