claudemesh-cli 1.17.0 → 1.19.0
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
CHANGED
|
@@ -88,7 +88,7 @@ __export(exports_urls, {
|
|
|
88
88
|
VERSION: () => VERSION,
|
|
89
89
|
URLS: () => URLS
|
|
90
90
|
});
|
|
91
|
-
var URLS, VERSION = "1.
|
|
91
|
+
var URLS, VERSION = "1.19.0", env;
|
|
92
92
|
var init_urls = __esm(() => {
|
|
93
93
|
URLS = {
|
|
94
94
|
BROKER: process.env.CLAUDEMESH_BROKER_URL ?? "wss://ic.claudemesh.com/ws",
|
|
@@ -5135,6 +5135,14 @@ __export(exports_rename, {
|
|
|
5135
5135
|
rename: () => rename
|
|
5136
5136
|
});
|
|
5137
5137
|
async function rename(slug, newName) {
|
|
5138
|
+
const auth = getStoredToken();
|
|
5139
|
+
if (!auth) {
|
|
5140
|
+
console.error(` ${icons.cross} Renaming a mesh requires a claudemesh.com account session.`);
|
|
5141
|
+
console.error(` ${dim("Joining via invite signs you in to the mesh, not to a web account.")}`);
|
|
5142
|
+
console.error(` ${dim("Run")} ${bold("claudemesh login")} ${dim("first, then retry, or rename from the dashboard:")}`);
|
|
5143
|
+
console.error(` https://claudemesh.com/dashboard`);
|
|
5144
|
+
return EXIT.AUTH_FAILED;
|
|
5145
|
+
}
|
|
5138
5146
|
try {
|
|
5139
5147
|
await renameMesh2(slug, newName);
|
|
5140
5148
|
console.log(` ${green(icons.check)} Renamed "${slug}" to "${newName}"`);
|
|
@@ -5146,6 +5154,7 @@ async function rename(slug, newName) {
|
|
|
5146
5154
|
}
|
|
5147
5155
|
var init_rename2 = __esm(() => {
|
|
5148
5156
|
init_facade10();
|
|
5157
|
+
init_facade6();
|
|
5149
5158
|
init_styles();
|
|
5150
5159
|
init_exit_codes();
|
|
5151
5160
|
});
|
|
@@ -11124,6 +11133,752 @@ var init_platform_actions = __esm(() => {
|
|
|
11124
11133
|
init_exit_codes();
|
|
11125
11134
|
});
|
|
11126
11135
|
|
|
11136
|
+
// skills/claudemesh/SKILL.md
|
|
11137
|
+
var SKILL_default = `---
|
|
11138
|
+
name: claudemesh
|
|
11139
|
+
description: Use when the user asks to send a message to a peer Claude session, list mesh peers, share state across meshes, schedule cross-session reminders, or otherwise interact with claudemesh — a peer mesh runtime for Claude Code sessions. Provides the canonical reference for every \`claudemesh\` CLI verb, its flags, JSON output shape, and common patterns.
|
|
11140
|
+
---
|
|
11141
|
+
|
|
11142
|
+
# claudemesh skill
|
|
11143
|
+
|
|
11144
|
+
\`claudemesh\` is the peer mesh runtime for Claude Code sessions. Each session in a mesh has a name, identity (ed25519 keypair), and shared resources: peers, messages, state, memory, files, vectors, scheduled jobs, skills.
|
|
11145
|
+
|
|
11146
|
+
**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.
|
|
11147
|
+
|
|
11148
|
+
## When you receive a \`<channel source="claudemesh">\` message
|
|
11149
|
+
|
|
11150
|
+
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.
|
|
11151
|
+
|
|
11152
|
+
### Channel attributes (everything you need to reply is in the push)
|
|
11153
|
+
|
|
11154
|
+
The \`<channel>\` interrupt carries these attributes — no lookup needed:
|
|
11155
|
+
|
|
11156
|
+
| Attribute | What it is |
|
|
11157
|
+
|---|---|
|
|
11158
|
+
| \`from_name\` | Sender's display name. **Use as \`to\` in your reply** for DMs. |
|
|
11159
|
+
| \`from_pubkey\` | Sender's session pubkey (hex). Stable per-session. |
|
|
11160
|
+
| \`from_member_id\` | Sender's stable mesh.member id. Survives display-name changes — the canonical id. |
|
|
11161
|
+
| \`mesh_slug\` | Mesh the message arrived on. Pass via \`--mesh <slug>\` if the parent isn't on the same mesh. |
|
|
11162
|
+
| \`priority\` | \`now\` / \`next\` / \`low\`. |
|
|
11163
|
+
| \`message_id\` | Server-side id of THIS message. **Pass to \`--reply-to <id>\` to thread your reply** in topic posts. |
|
|
11164
|
+
| \`topic\` | Set when the source is a topic post. Reply via \`topic post <topic> --reply-to <message_id>\`. |
|
|
11165
|
+
| \`reply_to_id\` | Set when the message itself is a reply to a previous one — render thread context. |
|
|
11166
|
+
|
|
11167
|
+
**Reply patterns:**
|
|
11168
|
+
|
|
11169
|
+
\`\`\`bash
|
|
11170
|
+
# DM → use from_name as the target
|
|
11171
|
+
claudemesh send "<from_name>" "ack — looking now"
|
|
11172
|
+
|
|
11173
|
+
# Topic reply → thread it onto the message you got
|
|
11174
|
+
claudemesh topic post "<topic>" "yep, looks good" --reply-to <message_id>
|
|
11175
|
+
|
|
11176
|
+
# When the sender is on a different mesh you've joined
|
|
11177
|
+
claudemesh send "<from_name>" "..." --mesh "<mesh_slug>"
|
|
11178
|
+
\`\`\`
|
|
11179
|
+
|
|
11180
|
+
## Performance model (warm vs cold path)
|
|
11181
|
+
|
|
11182
|
+
If the parent Claude session was launched via \`claudemesh launch\`, an MCP push-pipe is running and holds the per-mesh WS connection. CLI invocations dial \`~/.claudemesh/sockets/<mesh-slug>.sock\` and reuse that warm connection (~200ms total round-trip including Node.js startup). If no push-pipe is running (cron, scripts, hooks fired outside a session), the CLI opens its own WS, which takes ~500-700ms cold. **You don't manage this** — every verb auto-detects and falls through.
|
|
11183
|
+
|
|
11184
|
+
## Spawning new sessions (no wizard)
|
|
11185
|
+
|
|
11186
|
+
\`claudemesh launch\` is the canonical way to start a new Claude Code session connected to claudemesh. Pass every required flag up front so no interactive prompt fires — that's what makes the verb scriptable from tmux send-keys, AppleScript/iTerm spawn helpers, hooks, cron, and the \`claudemesh launch\` you call from inside another session. **Always use this verb, never \`claude\` directly with hand-rolled flags** — it sets up the per-session ed25519 keypair, exports \`CLAUDEMESH_DISPLAY_NAME\`, isolates the mesh config in a tmpdir, and passes the \`--dangerously-load-development-channels server:claudemesh\` plumbing that the MCP push-pipe needs.
|
|
11187
|
+
|
|
11188
|
+
### Full flag surface
|
|
11189
|
+
|
|
11190
|
+
| Flag | What it skips | Notes |
|
|
11191
|
+
|---|---|---|
|
|
11192
|
+
| \`--name <display-name>\` | the "What's your name?" prompt | required when spawning unattended; persists as the session's display name and \`from_name\` in inbound channels |
|
|
11193
|
+
| \`--mesh <slug>\` | the multi-mesh picker | required when the user has joined >1 mesh; otherwise the single mesh is auto-selected |
|
|
11194
|
+
| \`--join <invite-url>\` | the "join a mesh first" branch | run join + launch in one step; pair with \`-y\` for fully non-interactive |
|
|
11195
|
+
| \`--groups "name:role,name2:role2,all"\` | the group selection prompt | comma-separated \`<groupname>:<role>\` entries; the literal \`all\` joins \`@all\` |
|
|
11196
|
+
| \`--role <lead\\|member\\|observer>\` | the role prompt | applied to all groups in \`--groups\` that didn't specify their own |
|
|
11197
|
+
| \`--message-mode <push\\|inbox>\` | the message-mode prompt | \`push\` (default) emits \`<channel>\` notifications mid-turn; \`inbox\` only buffers — quieter for headless agents |
|
|
11198
|
+
| \`--system-prompt <path>\` | nothing — pure pass-through | forwarded to \`claude --append-system-prompt\` |
|
|
11199
|
+
| \`--resume <session-id>\` | nothing — pure pass-through | forwarded to \`claude --resume\` to continue a prior Claude Code session |
|
|
11200
|
+
| \`--continue\` | nothing — pure pass-through | forwarded to \`claude --continue\` |
|
|
11201
|
+
| \`-y\` / \`--yes\` | every confirmation prompt | including the "you'll skip ALL permission prompts" gate. **Use for autonomous agents; omit for shared/multi-person meshes.** |
|
|
11202
|
+
| \`-q\` / \`--quiet\` | the welcome banner | useful when the spawning script wants clean stdout |
|
|
11203
|
+
| \`--\` | (separator) | everything after \`--\` is forwarded verbatim to \`claude\`. Example: \`claudemesh launch --name X -y -- --resume abc123 --model opus\` |
|
|
11204
|
+
|
|
11205
|
+
### Wizard-free spawn templates
|
|
11206
|
+
|
|
11207
|
+
\`\`\`bash
|
|
11208
|
+
# Minimal — single joined mesh, fresh agent, autonomous:
|
|
11209
|
+
claudemesh launch --name "Lug Nut" -y
|
|
11210
|
+
|
|
11211
|
+
# Multi-mesh user — pick mesh explicitly:
|
|
11212
|
+
claudemesh launch --name "Mou" --mesh openclaw -y
|
|
11213
|
+
|
|
11214
|
+
# Cold-start a peer who hasn't joined the mesh yet:
|
|
11215
|
+
claudemesh launch \\
|
|
11216
|
+
--name "Lug Nut" \\
|
|
11217
|
+
--join "https://claudemesh.com/i/abc123" \\
|
|
11218
|
+
--groups "frontend:member,reviewers:observer,all" \\
|
|
11219
|
+
--message-mode push \\
|
|
11220
|
+
-y
|
|
11221
|
+
|
|
11222
|
+
# Resume a specific Claude session inside claudemesh:
|
|
11223
|
+
claudemesh launch --name "Mou" --mesh openclaw -y -- --resume abc123-...
|
|
11224
|
+
|
|
11225
|
+
# Quiet, headless, system-prompt loaded — for cron / hooks:
|
|
11226
|
+
claudemesh launch --name "ci-bot" --mesh openclaw \\
|
|
11227
|
+
--system-prompt /path/to/ci-bot.md \\
|
|
11228
|
+
--message-mode inbox \\
|
|
11229
|
+
-q -y
|
|
11230
|
+
\`\`\`
|
|
11231
|
+
|
|
11232
|
+
If any required flag is missing AND stdin is a TTY, \`launch\` falls back to its prompt for that single field. **In a non-TTY context (Bash tool, cron, AppleScript pipe), missing flags cause the verb to fail-closed — never silently use a default that affects identity.**
|
|
11233
|
+
|
|
11234
|
+
### Spawning into new terminal panes/windows
|
|
11235
|
+
|
|
11236
|
+
The launch verb itself is just a shell command — wrap it in whatever pane-creation primitive the host platform uses. The patterns that work today:
|
|
11237
|
+
|
|
11238
|
+
\`\`\`bash
|
|
11239
|
+
# tmux — send into a pane you control. NEVER send-keys into a pane
|
|
11240
|
+
# you didn't create; you risk typing into another live TUI.
|
|
11241
|
+
tmux new-window -t "$SESSION" -n claudemesh-lugnut
|
|
11242
|
+
tmux send-keys -t "$SESSION:claudemesh-lugnut" \\
|
|
11243
|
+
'claudemesh launch --name "Lug Nut" --mesh openclaw -y' Enter
|
|
11244
|
+
|
|
11245
|
+
# macOS iTerm2 (split current window into a vertical pane):
|
|
11246
|
+
osascript <<'OSA'
|
|
11247
|
+
tell application "iTerm2"
|
|
11248
|
+
tell current window
|
|
11249
|
+
create tab with default profile
|
|
11250
|
+
tell current session of current tab
|
|
11251
|
+
write text "claudemesh launch --name \\"Lug Nut\\" --mesh openclaw -y"
|
|
11252
|
+
end tell
|
|
11253
|
+
end tell
|
|
11254
|
+
end tell
|
|
11255
|
+
OSA
|
|
11256
|
+
|
|
11257
|
+
# macOS Terminal.app (new window):
|
|
11258
|
+
osascript -e 'tell application "Terminal" to do script "claudemesh launch --name \\"Lug Nut\\" --mesh openclaw -y"'
|
|
11259
|
+
|
|
11260
|
+
# GNOME Terminal / generic Linux:
|
|
11261
|
+
gnome-terminal -- bash -lc 'claudemesh launch --name "Lug Nut" --mesh openclaw -y'
|
|
11262
|
+
|
|
11263
|
+
# screen detached:
|
|
11264
|
+
screen -dmS lugnut bash -lc 'claudemesh launch --name "Lug Nut" --mesh openclaw -y'
|
|
11265
|
+
|
|
11266
|
+
# Windows Terminal (wt.exe) — open a new tab:
|
|
11267
|
+
wt.exe new-tab --title claudemesh-lugnut powershell -NoExit -Command "claudemesh launch --name 'Lug Nut' --mesh openclaw -y"
|
|
11268
|
+
|
|
11269
|
+
# Windows Terminal — split the current pane vertically instead:
|
|
11270
|
+
wt.exe split-pane -V powershell -NoExit -Command "claudemesh launch --name 'Lug Nut' --mesh openclaw -y"
|
|
11271
|
+
|
|
11272
|
+
# PowerShell — spawn a detached window of the user's default shell:
|
|
11273
|
+
Start-Process powershell -ArgumentList '-NoExit','-Command','claudemesh launch --name "Lug Nut" --mesh openclaw -y'
|
|
11274
|
+
|
|
11275
|
+
# cmd.exe — start a new console window:
|
|
11276
|
+
start "claudemesh-lugnut" cmd /k "claudemesh launch --name ""Lug Nut"" --mesh openclaw -y"
|
|
11277
|
+
|
|
11278
|
+
# WSL from a Windows host — same launch verb, just route through wsl.exe:
|
|
11279
|
+
wsl.exe -- bash -lc 'claudemesh launch --name "Lug Nut" --mesh openclaw -y'
|
|
11280
|
+
\`\`\`
|
|
11281
|
+
|
|
11282
|
+
Windows-specific gotchas:
|
|
11283
|
+
- **Single quotes don't nest in cmd.exe.** Use \`""\` to escape inner double quotes (see the \`cmd /k\` example) or move to PowerShell where single quotes work normally.
|
|
11284
|
+
- **\`-NoExit\`** is the PowerShell equivalent of bash's \`exec\` + interactive shell — keeps the window open after \`claudemesh launch\` returns control to its child \`claude\` process. Without it, the window closes when the launch script exits.
|
|
11285
|
+
- **WSL paths.** If you spawn from a Windows-side script into WSL, the \`claudemesh\` CLI in WSL writes to \`~/.claudemesh/\` on the Linux side, *not* \`%USERPROFILE%\\.claudemesh\\\`. The two installs are independent — match the spawn host to the install host.
|
|
11286
|
+
- **Windows Terminal profile names.** Replace \`powershell\` with \`pwsh\` for PowerShell 7+, or use \`--profile "<name>"\` to target a configured profile (e.g. one preconfigured with WSL Ubuntu + a starting directory).
|
|
11287
|
+
|
|
11288
|
+
The user's environment may also have these pre-built helpers (CLAUDE.md will tell you):
|
|
11289
|
+
|
|
11290
|
+
- \`~/tools/scripts/spawn-iterm-panes.sh\` and \`spawn-iterm-window.sh\` — safer iTerm spawners that only write into sessions they themselves created.
|
|
11291
|
+
- \`~/tools/scripts/claude-peers.sh\` — tmux wrapper that opens a split running \`claudemesh launch\` with sensible defaults.
|
|
11292
|
+
|
|
11293
|
+
Prefer those when available — they handle pane ownership / cleanup correctly.
|
|
11294
|
+
|
|
11295
|
+
### Sanity rules for unattended spawns
|
|
11296
|
+
|
|
11297
|
+
1. **Always pass \`--name\`.** A nameless session falls back to \`<hostname>-<pid>\`, which makes peer attribution opaque in \`peer list\` and inbound channels.
|
|
11298
|
+
2. **Always pass \`--mesh\` when the user has multiple meshes joined.** Otherwise the picker fires and the spawn hangs waiting for stdin.
|
|
11299
|
+
3. **Pass \`-y\` only when you understand the consent it grants.** It skips every permission gate — fine for an autonomous agent on a private mesh, dangerous on a shared mesh where peers can drive your file system.
|
|
11300
|
+
4. **For long-running daemonised peers, use \`--message-mode inbox\`** so they don't fire \`<channel>\` interrupts on every received DM. They poll \`claudemesh inbox\` on their own cadence.
|
|
11301
|
+
5. **Confirm the spawn worked** by waiting a few seconds and running \`claudemesh peer list\` — the new peer's \`displayName\` should appear with \`status: "idle"\`.
|
|
11302
|
+
|
|
11303
|
+
## Universal flags
|
|
11304
|
+
|
|
11305
|
+
| Flag | Behavior |
|
|
11306
|
+
|---|---|
|
|
11307
|
+
| \`--mesh <slug>\` | Target a specific mesh. Required when the user has multiple meshes joined. Default: first/only joined mesh, or interactive picker. |
|
|
11308
|
+
| \`--json\` | Emit JSON instead of human-readable text. Use this when you need to parse the output. |
|
|
11309
|
+
| \`--json field1,field2\` | Project specific fields (modeled on \`gh --json\`). Friendly aliases like \`name\` → \`displayName\` are resolved automatically. |
|
|
11310
|
+
| \`--approval-mode <mode>\` | \`plan\` / \`read-only\` deny all writes; \`write\` (default) prompts on destructive verbs from the policy file; \`yolo\` bypasses every prompt. |
|
|
11311
|
+
| \`--policy <path>\` | Override the policy file (default \`~/.claudemesh/policy.yaml\`, auto-created on first run). |
|
|
11312
|
+
| \`-y\` / \`--yes\` | Auto-approve any policy prompt. Equivalent to \`--approval-mode yolo\` for the current invocation. |
|
|
11313
|
+
|
|
11314
|
+
## Policy & confirmation
|
|
11315
|
+
|
|
11316
|
+
Every broker-touching verb runs through a policy gate before dispatch. The default policy allows reads and prompts on destructive writes (\`peer kick/ban/disconnect\`, \`file delete\`, \`vector/vault delete\`, \`memory forget\`, \`skill remove\`, \`webhook delete\`, \`watch remove\`, \`sql/graph execute\`, \`mesh delete\`). When you call \`claudemesh\` from a non-interactive context (cron, scripts, Claude's Bash tool), prompts auto-deny — pass \`-y\` or \`--approval-mode yolo\` for verbs you've vetted, or edit \`~/.claudemesh/policy.yaml\` to mark them \`decision: allow\`. Every gate decision is appended to \`~/.claudemesh/audit.log\` (newline-JSON).
|
|
11317
|
+
|
|
11318
|
+
## Resources and verbs
|
|
11319
|
+
|
|
11320
|
+
**Convention:** every operation is \`claudemesh <resource> <verb>\`. Legacy short forms (\`send\`, \`peers\`, \`kick\`, \`remember\`, ...) are aliases that keep working forever; prefer the resource form for new code.
|
|
11321
|
+
|
|
11322
|
+
### \`topic\` — conversation scope within a mesh (v0.2.0)
|
|
11323
|
+
|
|
11324
|
+
A topic is a named conversation inside a mesh. Mesh = trust boundary. Group = identity tag. **Topic = what you're talking about.** Subscribers receive topic-tagged messages; non-subscribers don't. Topics also persist message history so humans (and opting-in agents) can fetch back-scroll on reconnect.
|
|
11325
|
+
|
|
11326
|
+
\`\`\`bash
|
|
11327
|
+
claudemesh topic create deploys --description "deploy + on-call"
|
|
11328
|
+
claudemesh topic create incident-2026-05-02 --visibility private
|
|
11329
|
+
claudemesh topic list # all topics in mesh
|
|
11330
|
+
claudemesh topic join deploys # subscribe (by name or id)
|
|
11331
|
+
claudemesh topic join deploys --role lead # join as lead
|
|
11332
|
+
claudemesh topic leave deploys
|
|
11333
|
+
claudemesh topic members deploys # list subscribers
|
|
11334
|
+
claudemesh topic history deploys --limit 50 # fetch back-scroll
|
|
11335
|
+
claudemesh topic history deploys --before <msg-id> # paginate older
|
|
11336
|
+
claudemesh topic read deploys # mark all as read
|
|
11337
|
+
|
|
11338
|
+
# Send to a topic — same \`send\` verb, target starts with # (WS, v1 plaintext)
|
|
11339
|
+
claudemesh send "#deploys" "rolling out 1.5.1 to staging"
|
|
11340
|
+
|
|
11341
|
+
# v1.7.0+: live tail in the terminal — backfill last N + then SSE forward.
|
|
11342
|
+
# Decrypts v2 messages on render. Runs a 30s re-seal loop while held.
|
|
11343
|
+
claudemesh topic tail deploys --limit 50
|
|
11344
|
+
|
|
11345
|
+
# v1.8.0+: encrypted REST send (body_version 2). Falls back to v1
|
|
11346
|
+
# automatically for legacy unencrypted topics. --plaintext forces v1.
|
|
11347
|
+
claudemesh topic post deploys "rolling out, cc @Alexis stay around"
|
|
11348
|
+
|
|
11349
|
+
# v1.9.0+: thread a reply onto a previous topic message. Accepts the
|
|
11350
|
+
# full id or an 8+ char prefix; resolved against recent history.
|
|
11351
|
+
claudemesh topic post deploys "yes — same here" --reply-to 7XtIeF7o
|
|
11352
|
+
\`\`\`
|
|
11353
|
+
|
|
11354
|
+
In \`topic tail\` output, replies render with a \`↳ in reply to <name>: "<snippet>"\` line above the message and every row shows a short id tag (\`#xxxxxxxx\`) so you can copy-paste into \`--reply-to\`.
|
|
11355
|
+
|
|
11356
|
+
When to use topics vs groups vs DM:
|
|
11357
|
+
- **DM** (\`send <peer>\`) — 1:1, ephemeral.
|
|
11358
|
+
- **Group** (\`send "@frontend"\`) — addresses everyone in a group; ephemeral; for coordinating teams.
|
|
11359
|
+
- **Topic** (\`send "#deploys"\`) — durable conversation room; for ongoing work threads, incident channels, build-status feeds.
|
|
11360
|
+
|
|
11361
|
+
### \`member\` — mesh roster + online state (v1.7.0)
|
|
11362
|
+
|
|
11363
|
+
Distinct from \`peer list\`: members shows the static roster (every joined member of a mesh, online or not), peers shows the live WS-connected sessions plus REST-active humans.
|
|
11364
|
+
|
|
11365
|
+
\`\`\`bash
|
|
11366
|
+
claudemesh member list # everyone, with status dots
|
|
11367
|
+
claudemesh member list --online # only online
|
|
11368
|
+
claudemesh member list --mesh deploys --json
|
|
11369
|
+
\`\`\`
|
|
11370
|
+
|
|
11371
|
+
Status glyphs: \`●\` emerald = idle, \`●\` clay = working, \`●\` red = dnd, \`○\` dim = offline. \`bot\` tag appears on non-human members.
|
|
11372
|
+
|
|
11373
|
+
### \`notification\` — recent @-mentions (v1.7.0)
|
|
11374
|
+
|
|
11375
|
+
Server-side write-time fan-out from \`mesh.notification\` — one row per recipient per matching \`@-mention\`. Works for both v1 plaintext and v2 ciphertext (clients send the mention list explicitly on v2).
|
|
11376
|
+
|
|
11377
|
+
\`\`\`bash
|
|
11378
|
+
claudemesh notification list # last 24h, all mentions of you
|
|
11379
|
+
claudemesh notification list --since 2026-05-01T00:00Z # incremental for polling
|
|
11380
|
+
claudemesh notification list --json # parseable
|
|
11381
|
+
\`\`\`
|
|
11382
|
+
|
|
11383
|
+
### Per-topic encryption (v0.3.0 / CLI 1.8.0)
|
|
11384
|
+
|
|
11385
|
+
Topics created on or after CLI 1.8.0 generate a 32-byte XSalsa20-Poly1305 symmetric key sealed for each member via \`crypto_box\`. The broker holds ciphertext only. \`topic post\` encrypts; \`topic tail\` decrypts. The \`🔒 v2\` glyph in tail output marks ciphertext rounds. v1 plaintext topics keep working unchanged.
|
|
11386
|
+
|
|
11387
|
+
When a new member joins an encrypted topic, they get a 404 from \`GET /v1/topics/:name/key\` until any holder re-seals for them. \`topic tail\` runs a 30s background loop that does the re-seal automatically while the tail is open. Otherwise the joiner waits for someone with the key to log in.
|
|
11388
|
+
|
|
11389
|
+
### \`peer\` — read connected peers + admin (kick / ban / verify)
|
|
11390
|
+
|
|
11391
|
+
\`\`\`bash
|
|
11392
|
+
claudemesh peer list # human-readable (alias: peers)
|
|
11393
|
+
claudemesh peer list --json # full record
|
|
11394
|
+
claudemesh peer list --json name,status # field projection
|
|
11395
|
+
claudemesh peer list --mesh openclaw --json # specific mesh
|
|
11396
|
+
|
|
11397
|
+
claudemesh peer kick <peer> # end session, manual rejoin
|
|
11398
|
+
claudemesh peer disconnect <peer> # soft, peer auto-reconnects
|
|
11399
|
+
claudemesh peer ban <peer> # kick + revoke membership
|
|
11400
|
+
claudemesh peer unban <peer>
|
|
11401
|
+
claudemesh peer bans # list banned members
|
|
11402
|
+
claudemesh peer verify [peer] # 6×5-digit safety numbers
|
|
11403
|
+
\`\`\`
|
|
11404
|
+
|
|
11405
|
+
JSON shape (per peer):
|
|
11406
|
+
\`\`\`json
|
|
11407
|
+
{
|
|
11408
|
+
"displayName": "Mou",
|
|
11409
|
+
"pubkey": "abc123...",
|
|
11410
|
+
"status": "idle | working | dnd",
|
|
11411
|
+
"summary": "string or null",
|
|
11412
|
+
"groups": [{ "name": "reviewers", "role": "lead" }],
|
|
11413
|
+
"peerType": "claude | telegram | ...",
|
|
11414
|
+
"channel": "claude-code | api | ...",
|
|
11415
|
+
"model": "claude-opus-4-7 | ...",
|
|
11416
|
+
"cwd": "/path/to/working/dir or null",
|
|
11417
|
+
"stats": { "messagesIn": 0, "messagesOut": 0, "toolCalls": 0, "errors": 0, "uptime": 1200 }
|
|
11418
|
+
}
|
|
11419
|
+
\`\`\`
|
|
11420
|
+
|
|
11421
|
+
### \`message\` — send and inspect messages
|
|
11422
|
+
|
|
11423
|
+
\`\`\`bash
|
|
11424
|
+
# send (alias: claudemesh send <to> <msg>)
|
|
11425
|
+
claudemesh message send <peer-name|@group|*|pubkey> "message text"
|
|
11426
|
+
claudemesh message send Mou "hi" # by display name
|
|
11427
|
+
claudemesh message send "@reviewers" "ready for review"
|
|
11428
|
+
claudemesh message send "*" "broadcast"
|
|
11429
|
+
claudemesh message send <p> "..." --priority now # bypass busy gates
|
|
11430
|
+
claudemesh message send <p> "..." --priority next # default
|
|
11431
|
+
claudemesh message send <p> "..." --priority low # pull-only
|
|
11432
|
+
|
|
11433
|
+
# inbox (alias: claudemesh inbox)
|
|
11434
|
+
claudemesh message inbox
|
|
11435
|
+
claudemesh message inbox --json
|
|
11436
|
+
|
|
11437
|
+
# delivery status (alias: claudemesh msg-status <id>)
|
|
11438
|
+
claudemesh message status <message-id>
|
|
11439
|
+
claudemesh message status <message-id> --json
|
|
11440
|
+
\`\`\`
|
|
11441
|
+
|
|
11442
|
+
\`send\` JSON output: \`{"ok": true, "messageId": "...", "target": "..."}\`. Errors: \`{"ok": false, "error": "..."}\`.
|
|
11443
|
+
|
|
11444
|
+
### \`state\` — shared per-mesh key-value store
|
|
11445
|
+
|
|
11446
|
+
\`\`\`bash
|
|
11447
|
+
claudemesh state set <key> <value> # value can be JSON or string
|
|
11448
|
+
claudemesh state get <key>
|
|
11449
|
+
claudemesh state get <key> --json # includes updatedBy, updatedAt
|
|
11450
|
+
claudemesh state list
|
|
11451
|
+
claudemesh state list --json
|
|
11452
|
+
\`\`\`
|
|
11453
|
+
|
|
11454
|
+
State is broadcast to all peers when changed. Use it for shared scratch space: status flags, current focus, agreed-on values.
|
|
11455
|
+
|
|
11456
|
+
### \`memory\` — recall-able knowledge per mesh
|
|
11457
|
+
|
|
11458
|
+
\`\`\`bash
|
|
11459
|
+
claudemesh memory remember "fact text" --tags tag1,tag2 # alias: remember
|
|
11460
|
+
claudemesh memory recall "search query" # alias: recall
|
|
11461
|
+
claudemesh memory recall "search query" --json
|
|
11462
|
+
claudemesh memory forget <memory-id> # alias: forget
|
|
11463
|
+
\`\`\`
|
|
11464
|
+
|
|
11465
|
+
Memories are searchable across the mesh. Use for shared documentation, decisions, lessons learned.
|
|
11466
|
+
|
|
11467
|
+
### \`task\` — typed work-units claim/complete
|
|
11468
|
+
|
|
11469
|
+
\`\`\`bash
|
|
11470
|
+
claudemesh task create "<title>" --assignee <peer> --priority <p> --tags a,b
|
|
11471
|
+
claudemesh task list [--status open|claimed|done] [--assignee <peer>] [--json]
|
|
11472
|
+
claudemesh task claim <task-id>
|
|
11473
|
+
claudemesh task complete <task-id> [result text]
|
|
11474
|
+
\`\`\`
|
|
11475
|
+
|
|
11476
|
+
Tasks are exact-once: claiming is atomic at broker. Use for work coordination across peers.
|
|
11477
|
+
|
|
11478
|
+
### \`schedule\` — time-based delivery
|
|
11479
|
+
|
|
11480
|
+
\`\`\`bash
|
|
11481
|
+
# one-shot or recurring (alias: claudemesh remind ...)
|
|
11482
|
+
claudemesh schedule msg "ping" --in 30m # fires in 30 min
|
|
11483
|
+
claudemesh schedule msg "ping" --at 15:00 # next 15:00
|
|
11484
|
+
claudemesh schedule msg "ping" --cron "0 9 * * *" # 9am daily
|
|
11485
|
+
claudemesh schedule msg "to peer" --to <peer-name>
|
|
11486
|
+
claudemesh schedule list --json
|
|
11487
|
+
claudemesh schedule cancel <reminder-id>
|
|
11488
|
+
|
|
11489
|
+
# webhook + tool schedules arrive in a later release (broker work pending).
|
|
11490
|
+
\`\`\`
|
|
11491
|
+
|
|
11492
|
+
### \`profile / group\` — peer presence
|
|
11493
|
+
|
|
11494
|
+
\`\`\`bash
|
|
11495
|
+
claudemesh profile # view/edit your profile
|
|
11496
|
+
claudemesh profile summary "what you're working on" # broadcast (alias: summary)
|
|
11497
|
+
claudemesh profile status set idle|working|dnd # alias: status set
|
|
11498
|
+
claudemesh profile visible true|false # alias: visible
|
|
11499
|
+
claudemesh group join @reviewers --role lead
|
|
11500
|
+
claudemesh group leave @reviewers
|
|
11501
|
+
\`\`\`
|
|
11502
|
+
|
|
11503
|
+
### \`vector\` — embedding store + similarity search
|
|
11504
|
+
|
|
11505
|
+
\`\`\`bash
|
|
11506
|
+
claudemesh vector store <collection> "<text>" [--metadata '<json>']
|
|
11507
|
+
claudemesh vector search <collection> "<query>" [--limit N] [--json]
|
|
11508
|
+
claudemesh vector delete <collection> <id>
|
|
11509
|
+
claudemesh vector collections # list collection names
|
|
11510
|
+
\`\`\`
|
|
11511
|
+
|
|
11512
|
+
Search returns \`[{id, text, score, metadata}]\` ranked by cosine similarity.
|
|
11513
|
+
|
|
11514
|
+
### \`graph\` — Cypher queries against per-mesh graph
|
|
11515
|
+
|
|
11516
|
+
\`\`\`bash
|
|
11517
|
+
claudemesh graph query "MATCH (n) RETURN n LIMIT 10" # read
|
|
11518
|
+
claudemesh graph execute "CREATE (n:Foo {x: 1})" # write
|
|
11519
|
+
\`\`\`
|
|
11520
|
+
|
|
11521
|
+
Returns rows as \`[{...}, ...]\`. Queries that return no rows render "(no rows)".
|
|
11522
|
+
|
|
11523
|
+
### \`context\` — share work-context summaries between peers
|
|
11524
|
+
|
|
11525
|
+
\`\`\`bash
|
|
11526
|
+
claudemesh context share "summary text" --files a.ts,b.ts --findings "x,y" --tags spec,review
|
|
11527
|
+
claudemesh context get "search query"
|
|
11528
|
+
claudemesh context list
|
|
11529
|
+
\`\`\`
|
|
11530
|
+
|
|
11531
|
+
Use to broadcast "what I just did and what I learned" so peers don't duplicate effort.
|
|
11532
|
+
|
|
11533
|
+
### \`stream\` — pub/sub event bus
|
|
11534
|
+
|
|
11535
|
+
\`\`\`bash
|
|
11536
|
+
claudemesh stream create <name>
|
|
11537
|
+
claudemesh stream publish <name> '<json-or-text>'
|
|
11538
|
+
claudemesh stream list
|
|
11539
|
+
\`\`\`
|
|
11540
|
+
|
|
11541
|
+
For event broadcasting (build-events, deploy-notifications, sensor data). Subscribers receive via push.
|
|
11542
|
+
|
|
11543
|
+
### \`sql\` — typed SQL against per-mesh tables
|
|
11544
|
+
|
|
11545
|
+
\`\`\`bash
|
|
11546
|
+
claudemesh sql query "SELECT * FROM <table>" # SELECT only
|
|
11547
|
+
claudemesh sql execute "INSERT INTO ..." # writes
|
|
11548
|
+
claudemesh sql schema # list tables + columns
|
|
11549
|
+
\`\`\`
|
|
11550
|
+
|
|
11551
|
+
Returns \`{columns, rows, rowCount}\` for queries. Each mesh has its own SQL namespace.
|
|
11552
|
+
|
|
11553
|
+
### \`skill\` — discover + manage mesh-published Claude skills
|
|
11554
|
+
|
|
11555
|
+
\`\`\`bash
|
|
11556
|
+
claudemesh skill list [search-query]
|
|
11557
|
+
claudemesh skill get <skill-name>
|
|
11558
|
+
claudemesh skill remove <skill-name>
|
|
11559
|
+
\`\`\`
|
|
11560
|
+
|
|
11561
|
+
Published skills appear as \`/claudemesh:<name>\` slash commands across all connected sessions.
|
|
11562
|
+
|
|
11563
|
+
### \`vault\` — encrypted per-mesh secrets
|
|
11564
|
+
|
|
11565
|
+
\`\`\`bash
|
|
11566
|
+
claudemesh vault list # list keys (values stay encrypted on disk)
|
|
11567
|
+
claudemesh vault delete <key>
|
|
11568
|
+
# claudemesh vault set/get currently goes through MCP — needs E2E crypto round-trip
|
|
11569
|
+
\`\`\`
|
|
11570
|
+
|
|
11571
|
+
### \`watch\` — URL change watchers
|
|
11572
|
+
|
|
11573
|
+
\`\`\`bash
|
|
11574
|
+
claudemesh watch list # list active watches
|
|
11575
|
+
claudemesh watch remove <watch-id>
|
|
11576
|
+
# Watch creation currently via MCP \`mesh_watch\` — config-heavy
|
|
11577
|
+
\`\`\`
|
|
11578
|
+
|
|
11579
|
+
### \`webhook\` — outbound HTTP triggers
|
|
11580
|
+
|
|
11581
|
+
\`\`\`bash
|
|
11582
|
+
claudemesh webhook list # list configured webhooks
|
|
11583
|
+
claudemesh webhook delete <name>
|
|
11584
|
+
# Webhook creation currently via MCP \`create_webhook\`
|
|
11585
|
+
\`\`\`
|
|
11586
|
+
|
|
11587
|
+
### \`file\` — shared mesh files
|
|
11588
|
+
|
|
11589
|
+
\`\`\`bash
|
|
11590
|
+
claudemesh file share <path> # upload to mesh (visible to all members)
|
|
11591
|
+
claudemesh file share <path> --to <peer> # share with one peer (same-host fast path if co-located)
|
|
11592
|
+
claudemesh file share <path> --to <peer> --message "see line 42"
|
|
11593
|
+
claudemesh file share <path> --upload # force network upload, skip same-host fast path
|
|
11594
|
+
claudemesh file get <file-id> # download by id (saves to ./<name>)
|
|
11595
|
+
claudemesh file get <file-id> --out /tmp/foo.bin # download to explicit path
|
|
11596
|
+
claudemesh file list [search-query] # browse mesh files
|
|
11597
|
+
claudemesh file status <file-id> # who has accessed
|
|
11598
|
+
claudemesh file delete <file-id>
|
|
11599
|
+
\`\`\`
|
|
11600
|
+
|
|
11601
|
+
**Same-host fast path** (v0.6.0+): when \`--to <peer>\` resolves to a session
|
|
11602
|
+
running on the same hostname as you, \`claudemesh file share\` skips MinIO
|
|
11603
|
+
entirely and sends a DM with the absolute filepath. The receiver reads it
|
|
11604
|
+
directly off disk. No 50 MB cap, no upload latency, nothing in the bucket.
|
|
11605
|
+
Falls back to encrypted upload when the peer is remote, or always when
|
|
11606
|
+
\`--upload\` is set. Routes by session pubkey, so sibling sessions of the
|
|
11607
|
+
same member work without tripping the self-DM guard.
|
|
11608
|
+
|
|
11609
|
+
**Network upload cap**: 50 MB. Same-host fast path has no cap.
|
|
11610
|
+
|
|
11611
|
+
**\`--to\` accepts**: display name, member pubkey, session pubkey, or any
|
|
11612
|
+
≥8-char prefix of a pubkey. Prefer pubkey when multiple peers share a name.
|
|
11613
|
+
|
|
11614
|
+
### \`mesh-mcp\` — call MCP servers other peers deployed to the mesh
|
|
11615
|
+
|
|
11616
|
+
\`\`\`bash
|
|
11617
|
+
claudemesh mesh-mcp list # which servers are deployed
|
|
11618
|
+
claudemesh mesh-mcp call <server> <tool> '<json-args>'
|
|
11619
|
+
claudemesh mesh-mcp catalog # full catalog with schemas
|
|
11620
|
+
\`\`\`
|
|
11621
|
+
|
|
11622
|
+
Mesh-deployed MCPs let peer X call a tool that peer Y maintains, without local install.
|
|
11623
|
+
|
|
11624
|
+
### \`clock\` — mesh logical clock
|
|
11625
|
+
|
|
11626
|
+
\`\`\`bash
|
|
11627
|
+
claudemesh clock # current state
|
|
11628
|
+
claudemesh clock set <speed> # speed: 0=paused, 1=realtime, 60=60× faster
|
|
11629
|
+
claudemesh clock pause
|
|
11630
|
+
claudemesh clock resume
|
|
11631
|
+
\`\`\`
|
|
11632
|
+
|
|
11633
|
+
Used for simulations / tests that need a controlled time axis shared across peers.
|
|
11634
|
+
|
|
11635
|
+
### \`mesh\` — mesh-level introspection
|
|
11636
|
+
|
|
11637
|
+
\`\`\`bash
|
|
11638
|
+
claudemesh info --json # mesh overview: peers, groups, state keys, ...
|
|
11639
|
+
claudemesh stats --json # per-peer activity counters
|
|
11640
|
+
claudemesh clock --json # mesh logical clock (speed/tick/sim_time)
|
|
11641
|
+
claudemesh ping --json # diagnostic — ws status, peer count, push buffer
|
|
11642
|
+
claudemesh peers --mesh X # peers on a specific mesh
|
|
11643
|
+
\`\`\`
|
|
11644
|
+
|
|
11645
|
+
### \`mesh management\` — admin ops
|
|
11646
|
+
|
|
11647
|
+
\`\`\`bash
|
|
11648
|
+
claudemesh list # all your meshes
|
|
11649
|
+
claudemesh create <name> # create a new mesh
|
|
11650
|
+
claudemesh share [email] # generate invite link
|
|
11651
|
+
claudemesh disconnect <peer> # soft disconnect (auto-reconnects)
|
|
11652
|
+
claudemesh kick <peer> # kick (must rejoin manually)
|
|
11653
|
+
claudemesh ban <peer> # ban (revoked, can't rejoin)
|
|
11654
|
+
claudemesh unban <peer>
|
|
11655
|
+
claudemesh bans # list banned members
|
|
11656
|
+
claudemesh delete <slug> # delete a mesh
|
|
11657
|
+
claudemesh rename <slug> <name>
|
|
11658
|
+
\`\`\`
|
|
11659
|
+
|
|
11660
|
+
### \`verify\` — safety numbers (Signal-style MITM detection)
|
|
11661
|
+
|
|
11662
|
+
\`\`\`bash
|
|
11663
|
+
claudemesh verify <peer> # show 6×5-digit fingerprint
|
|
11664
|
+
claudemesh verify <peer> --json
|
|
11665
|
+
\`\`\`
|
|
11666
|
+
|
|
11667
|
+
Compare digits with the peer out-of-band (call, in person — not chat). If they match, the channel is not being intercepted.
|
|
11668
|
+
|
|
11669
|
+
### \`auth\` — sign-in
|
|
11670
|
+
|
|
11671
|
+
\`\`\`bash
|
|
11672
|
+
claudemesh login # browser or paste-token
|
|
11673
|
+
claudemesh whoami # current identity
|
|
11674
|
+
claudemesh logout
|
|
11675
|
+
\`\`\`
|
|
11676
|
+
|
|
11677
|
+
## Common workflows
|
|
11678
|
+
|
|
11679
|
+
### "Send a message to peer X with a confirmation"
|
|
11680
|
+
\`\`\`bash
|
|
11681
|
+
result=$(claudemesh send "X" "ping" --json)
|
|
11682
|
+
echo "$result" | jq -r '.messageId'
|
|
11683
|
+
\`\`\`
|
|
11684
|
+
|
|
11685
|
+
### "List peers who are currently working"
|
|
11686
|
+
\`\`\`bash
|
|
11687
|
+
claudemesh peers --json name,status | jq '[.[] | select(.status == "working")]'
|
|
11688
|
+
\`\`\`
|
|
11689
|
+
|
|
11690
|
+
### "Send to all reviewers"
|
|
11691
|
+
\`\`\`bash
|
|
11692
|
+
claudemesh send "@reviewers" "PR ready: <url>"
|
|
11693
|
+
\`\`\`
|
|
11694
|
+
|
|
11695
|
+
### "Set my summary so peers know what I'm doing"
|
|
11696
|
+
\`\`\`bash
|
|
11697
|
+
claudemesh summary "drafting the auth migration spec"
|
|
11698
|
+
\`\`\`
|
|
11699
|
+
|
|
11700
|
+
### "Schedule a daily ping at 9am"
|
|
11701
|
+
\`\`\`bash
|
|
11702
|
+
claudemesh remind "morning standup time" --cron "0 9 * * *"
|
|
11703
|
+
\`\`\`
|
|
11704
|
+
|
|
11705
|
+
### "Check who I'm verified with"
|
|
11706
|
+
\`\`\`bash
|
|
11707
|
+
claudemesh verify <peer-name>
|
|
11708
|
+
# Compare the 6×5-digit number with peer over voice or in person.
|
|
11709
|
+
\`\`\`
|
|
11710
|
+
|
|
11711
|
+
## Gotchas
|
|
11712
|
+
|
|
11713
|
+
- **\`<peer-name>\` resolution is case-insensitive but exact-match only.** Don't fuzzy-match. If a peer is named "Mou-2", use that exact string. Use \`claudemesh peers --json name\` to confirm.
|
|
11714
|
+
- **\`@group\` requires the leading \`@\`.** Without it, claudemesh treats the string as a peer name lookup.
|
|
11715
|
+
- **\`*\` means broadcast.** Use carefully — it goes to every peer on the mesh.
|
|
11716
|
+
- **\`--priority now\` bypasses busy gates** (peers in DND still receive). Use only for genuine interruptions.
|
|
11717
|
+
- **\`claudemesh launch\` writes a per-session config to a tmpdir.** Don't edit \`~/.claudemesh/config.json\` while a session is running — changes won't take effect until the next launch.
|
|
11718
|
+
- **The \`claudemesh mcp\` server registers ZERO tools.** Never search ToolSearch for \`mcp__claudemesh__*\` — there are none. All operations go through Bash + CLI.
|
|
11719
|
+
- **Soft-deprecated MCP tools (1.1.x).** If you previously called \`mcp__claudemesh__send_message\`, use \`claudemesh send\` via Bash instead. The deprecated tools still work in 1.x but print a stderr warning. They're removed in 2.0.
|
|
11720
|
+
- **Field aliases in \`--json\`.** \`name\` resolves to \`displayName\`. Other aliases may be added in future versions; check \`--json\` output to confirm field names.
|
|
11721
|
+
- **\`claudemesh send\` to a name that's not online** errors with the list of online peers. Use \`claudemesh peers --json\` first if uncertain.
|
|
11722
|
+
- **The \`--mesh <slug>\` flag is required when the user has multiple meshes joined.** Without it, the CLI either picks the first mesh deterministically or shows an interactive picker (depending on context).
|
|
11723
|
+
|
|
11724
|
+
## Behavioral conventions
|
|
11725
|
+
|
|
11726
|
+
- **Confirm before destructive ops** (\`kick\`, \`ban\`, \`delete\`, \`forget\`). Show the user what you're about to do.
|
|
11727
|
+
- **Preview peer-name matches before sending** when the name is ambiguous. \`claudemesh peers --json name,pubkey | jq\` is the right tool for disambiguation.
|
|
11728
|
+
- **Don't broadcast (\`*\`) for trivial messages.** It pings every peer mid-task. Prefer DM or \`@group\`.
|
|
11729
|
+
- **Don't poll \`inbox\`.** Messages are pushed via \`<channel source="claudemesh">\` automatically. Only call \`inbox --json\` if you suspect a buffered message is stuck.
|
|
11730
|
+
- **Echo the messageId in JSON contexts** so the caller can \`msg-status\` it later.
|
|
11731
|
+
|
|
11732
|
+
## Related
|
|
11733
|
+
|
|
11734
|
+
- Spec: \`.artifacts/specs/2026-05-02-architecture-north-star.md\` (architecture rationale)
|
|
11735
|
+
- Source: \`~/Desktop/claudemesh/apps/cli/\`
|
|
11736
|
+
- Broker: \`wss://ic.claudemesh.com/ws\`
|
|
11737
|
+
- Dashboard: \`https://claudemesh.com/dashboard\`
|
|
11738
|
+
`;
|
|
11739
|
+
var init_SKILL = () => {};
|
|
11740
|
+
|
|
11741
|
+
// src/commands/skill.ts
|
|
11742
|
+
var exports_skill = {};
|
|
11743
|
+
__export(exports_skill, {
|
|
11744
|
+
runSkill: () => runSkill
|
|
11745
|
+
});
|
|
11746
|
+
async function runSkill() {
|
|
11747
|
+
process.stdout.write(SKILL_default);
|
|
11748
|
+
if (!SKILL_default.endsWith(`
|
|
11749
|
+
`))
|
|
11750
|
+
process.stdout.write(`
|
|
11751
|
+
`);
|
|
11752
|
+
return EXIT.SUCCESS;
|
|
11753
|
+
}
|
|
11754
|
+
var init_skill = __esm(() => {
|
|
11755
|
+
init_SKILL();
|
|
11756
|
+
init_exit_codes();
|
|
11757
|
+
});
|
|
11758
|
+
|
|
11759
|
+
// src/commands/file.ts
|
|
11760
|
+
var exports_file = {};
|
|
11761
|
+
__export(exports_file, {
|
|
11762
|
+
runFileShare: () => runFileShare,
|
|
11763
|
+
runFileGet: () => runFileGet
|
|
11764
|
+
});
|
|
11765
|
+
import { hostname as osHostname } from "node:os";
|
|
11766
|
+
import { resolve as resolvePath, basename, dirname as dirname6 } from "node:path";
|
|
11767
|
+
import { statSync as statSync6, existsSync as existsSync20, writeFileSync as writeFileSync11, mkdirSync as mkdirSync7 } from "node:fs";
|
|
11768
|
+
function emitJson2(data) {
|
|
11769
|
+
console.log(JSON.stringify(data, null, 2));
|
|
11770
|
+
}
|
|
11771
|
+
function formatSize(bytes) {
|
|
11772
|
+
if (bytes < 1024)
|
|
11773
|
+
return `${bytes} B`;
|
|
11774
|
+
if (bytes < 1024 * 1024)
|
|
11775
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
11776
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
11777
|
+
}
|
|
11778
|
+
async function runFileShare(filePath, opts) {
|
|
11779
|
+
if (!filePath) {
|
|
11780
|
+
render.err('Usage: claudemesh file share <path> [--to <peer>] [--tags a,b] [--message "..."] [--upload]');
|
|
11781
|
+
return EXIT.INVALID_ARGS;
|
|
11782
|
+
}
|
|
11783
|
+
const absPath = resolvePath(filePath);
|
|
11784
|
+
if (!existsSync20(absPath)) {
|
|
11785
|
+
render.err(`File not found: ${absPath}`);
|
|
11786
|
+
return EXIT.INVALID_ARGS;
|
|
11787
|
+
}
|
|
11788
|
+
const stat = statSync6(absPath);
|
|
11789
|
+
if (!stat.isFile()) {
|
|
11790
|
+
render.err(`Not a regular file: ${absPath}`);
|
|
11791
|
+
return EXIT.INVALID_ARGS;
|
|
11792
|
+
}
|
|
11793
|
+
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
11794
|
+
return await withMesh({ meshSlug: opts.mesh ?? null }, async (client, mesh) => {
|
|
11795
|
+
if (opts.to && !opts.upload) {
|
|
11796
|
+
const peers = await client.listPeers();
|
|
11797
|
+
const myHost = osHostname();
|
|
11798
|
+
const target = peers.find((p) => {
|
|
11799
|
+
if (!p.hostname || p.hostname !== myHost)
|
|
11800
|
+
return false;
|
|
11801
|
+
return p.displayName === opts.to || p.memberPubkey === opts.to || p.pubkey === opts.to || typeof opts.to === "string" && opts.to.length >= 8 && p.pubkey.startsWith(opts.to);
|
|
11802
|
+
});
|
|
11803
|
+
if (target) {
|
|
11804
|
+
const note = opts.message ? `
|
|
11805
|
+
${opts.message}` : "";
|
|
11806
|
+
const body = `\uD83D\uDCCE file://${absPath} (${formatSize(stat.size)} · same host, no upload)${note}`;
|
|
11807
|
+
const result = await client.send(target.pubkey, body, "next");
|
|
11808
|
+
if (!result.ok) {
|
|
11809
|
+
render.err(`Send failed: ${result.error ?? "unknown"}`);
|
|
11810
|
+
return EXIT.NETWORK_ERROR;
|
|
11811
|
+
}
|
|
11812
|
+
if (opts.json) {
|
|
11813
|
+
emitJson2({ mode: "local", path: absPath, to: target.displayName, hostname: myHost, sizeBytes: stat.size });
|
|
11814
|
+
} else {
|
|
11815
|
+
render.ok(`shared ${bold(basename(absPath))} ${dim(`(${formatSize(stat.size)})`)} → ${green(target.displayName)} ${dim("[same host, no upload]")}`);
|
|
11816
|
+
}
|
|
11817
|
+
return EXIT.SUCCESS;
|
|
11818
|
+
}
|
|
11819
|
+
}
|
|
11820
|
+
const fileId = await client.uploadFile(absPath, mesh.meshId, mesh.memberId, {
|
|
11821
|
+
name: basename(absPath),
|
|
11822
|
+
tags,
|
|
11823
|
+
persistent: true,
|
|
11824
|
+
targetSpec: opts.to
|
|
11825
|
+
});
|
|
11826
|
+
if (opts.to) {
|
|
11827
|
+
const note = opts.message ? `
|
|
11828
|
+
${opts.message}` : "";
|
|
11829
|
+
const body = `\uD83D\uDCCE ${basename(absPath)} (${formatSize(stat.size)})
|
|
11830
|
+
claudemesh file get ${fileId}${note}`;
|
|
11831
|
+
await client.send(opts.to, body, "next");
|
|
11832
|
+
}
|
|
11833
|
+
if (opts.json) {
|
|
11834
|
+
emitJson2({ mode: "upload", fileId, name: basename(absPath), sizeBytes: stat.size, to: opts.to ?? null });
|
|
11835
|
+
} else {
|
|
11836
|
+
render.ok(`uploaded ${bold(basename(absPath))} ${dim(`(${formatSize(stat.size)})`)} ${dim("· id=" + fileId.slice(0, 12))}`);
|
|
11837
|
+
if (opts.to)
|
|
11838
|
+
render.info(dim(` notified ${opts.to}`));
|
|
11839
|
+
else
|
|
11840
|
+
render.info(dim(` retrieve: claudemesh file get ${fileId}`));
|
|
11841
|
+
}
|
|
11842
|
+
return EXIT.SUCCESS;
|
|
11843
|
+
});
|
|
11844
|
+
}
|
|
11845
|
+
async function runFileGet(fileId, opts) {
|
|
11846
|
+
if (!fileId) {
|
|
11847
|
+
render.err("Usage: claudemesh file get <file-id> [--out <path>]");
|
|
11848
|
+
return EXIT.INVALID_ARGS;
|
|
11849
|
+
}
|
|
11850
|
+
return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => {
|
|
11851
|
+
const meta = await client.getFile(fileId);
|
|
11852
|
+
if (!meta) {
|
|
11853
|
+
render.err(`File not found or not accessible: ${fileId}`);
|
|
11854
|
+
return EXIT.NOT_FOUND;
|
|
11855
|
+
}
|
|
11856
|
+
const res = await fetch(meta.url, { signal: AbortSignal.timeout(60000) });
|
|
11857
|
+
if (!res.ok) {
|
|
11858
|
+
render.err(`Download failed: HTTP ${res.status}`);
|
|
11859
|
+
return EXIT.NETWORK_ERROR;
|
|
11860
|
+
}
|
|
11861
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
11862
|
+
const outPath = opts.out ? resolvePath(opts.out) : resolvePath(process.cwd(), meta.name);
|
|
11863
|
+
mkdirSync7(dirname6(outPath), { recursive: true });
|
|
11864
|
+
writeFileSync11(outPath, buf);
|
|
11865
|
+
if (opts.json) {
|
|
11866
|
+
emitJson2({ fileId, name: meta.name, savedTo: outPath, sizeBytes: buf.length });
|
|
11867
|
+
} else {
|
|
11868
|
+
render.ok(`saved ${bold(meta.name)} ${dim(`(${formatSize(buf.length)})`)} → ${dim(outPath)}`);
|
|
11869
|
+
}
|
|
11870
|
+
return EXIT.SUCCESS;
|
|
11871
|
+
});
|
|
11872
|
+
}
|
|
11873
|
+
var MAX_FILE_BYTES;
|
|
11874
|
+
var init_file = __esm(() => {
|
|
11875
|
+
init_connect();
|
|
11876
|
+
init_render();
|
|
11877
|
+
init_styles();
|
|
11878
|
+
init_exit_codes();
|
|
11879
|
+
MAX_FILE_BYTES = 50 * 1024 * 1024;
|
|
11880
|
+
});
|
|
11881
|
+
|
|
11127
11882
|
// ../../packages/sdk/dist/crypto.js
|
|
11128
11883
|
var require_crypto = __commonJS((exports) => {
|
|
11129
11884
|
var __importDefault = exports && exports.__importDefault || function(mod) {
|
|
@@ -11716,7 +12471,7 @@ __export(exports_bridge, {
|
|
|
11716
12471
|
runBridge: () => runBridge,
|
|
11717
12472
|
bridgeConfigTemplate: () => bridgeConfigTemplate
|
|
11718
12473
|
});
|
|
11719
|
-
import { readFileSync as readFileSync14, existsSync as
|
|
12474
|
+
import { readFileSync as readFileSync14, existsSync as existsSync21 } from "node:fs";
|
|
11720
12475
|
function parseConfig(text) {
|
|
11721
12476
|
const trimmed = text.trim();
|
|
11722
12477
|
if (trimmed.startsWith("{"))
|
|
@@ -11760,7 +12515,7 @@ async function runBridge(configPath) {
|
|
|
11760
12515
|
render.err("Usage: claudemesh bridge run <config.yaml>");
|
|
11761
12516
|
return EXIT.INVALID_ARGS;
|
|
11762
12517
|
}
|
|
11763
|
-
if (!
|
|
12518
|
+
if (!existsSync21(configPath)) {
|
|
11764
12519
|
render.err(`config file not found: ${configPath}`);
|
|
11765
12520
|
return EXIT.NOT_FOUND;
|
|
11766
12521
|
}
|
|
@@ -12737,7 +13492,7 @@ var init_definitions = __esm(() => {
|
|
|
12737
13492
|
|
|
12738
13493
|
// src/services/bridge/server.ts
|
|
12739
13494
|
import { createServer as createServer2 } from "node:net";
|
|
12740
|
-
import { mkdirSync as
|
|
13495
|
+
import { mkdirSync as mkdirSync8, unlinkSync as unlinkSync2, existsSync as existsSync22, chmodSync as chmodSync5 } from "node:fs";
|
|
12741
13496
|
async function resolveTarget2(client, to) {
|
|
12742
13497
|
if (to.startsWith("@") || to === "*" || /^[0-9a-f]{64}$/i.test(to)) {
|
|
12743
13498
|
return { ok: true, spec: to };
|
|
@@ -12851,10 +13606,10 @@ function handleConnection(socket, client) {
|
|
|
12851
13606
|
function startBridgeServer(client) {
|
|
12852
13607
|
const path = socketPath(client.meshSlug);
|
|
12853
13608
|
const dir = socketDir();
|
|
12854
|
-
if (!
|
|
12855
|
-
|
|
13609
|
+
if (!existsSync22(dir)) {
|
|
13610
|
+
mkdirSync8(dir, { recursive: true, mode: 448 });
|
|
12856
13611
|
}
|
|
12857
|
-
if (
|
|
13612
|
+
if (existsSync22(path)) {
|
|
12858
13613
|
try {
|
|
12859
13614
|
unlinkSync2(path);
|
|
12860
13615
|
} catch {}
|
|
@@ -13005,11 +13760,11 @@ If the channel meta contains \`subtype: reminder\`, this is a scheduled reminder
|
|
|
13005
13760
|
| remember(content, tags?) | Store persistent knowledge with optional tags. |
|
|
13006
13761
|
| recall(query) | Full-text search over mesh memory. |
|
|
13007
13762
|
| forget(id) | Soft-delete a memory entry. |
|
|
13008
|
-
|
|
|
13009
|
-
|
|
|
13010
|
-
|
|
|
13011
|
-
|
|
|
13012
|
-
|
|
|
13763
|
+
| claudemesh file share <path> [--to peer] [--tags a,b] | Share a file with the mesh, or DM it to a specific peer. Same-host fast path: when --to matches a peer on this machine, sends an absolute filepath instead of uploading (no MinIO round-trip). |
|
|
13764
|
+
| claudemesh file get <id> [--out path] | Download a shared file by id. |
|
|
13765
|
+
| claudemesh file list [query] | Find files shared in the mesh. |
|
|
13766
|
+
| claudemesh file status <id> | Check who has accessed a file. |
|
|
13767
|
+
| claudemesh file delete <id> | Remove a shared file from the mesh. |
|
|
13013
13768
|
| vector_store(collection, text, metadata?) | Store embedding in per-mesh Qdrant collection. |
|
|
13014
13769
|
| vector_search(collection, query, limit?) | Semantic search over stored embeddings. |
|
|
13015
13770
|
| vector_delete(collection, id) | Remove an embedding. |
|
|
@@ -14320,6 +15075,7 @@ Topic (conversation scope, v0.2.0)
|
|
|
14320
15075
|
claudemesh topic tail <topic> live SSE tail [--limit --forward-only]
|
|
14321
15076
|
claudemesh topic post <t> <msg> encrypted REST post (v0.3.0 v2) [--reply-to <id>]
|
|
14322
15077
|
claudemesh send "#topic" "msg" send to a topic (WS path, v1 plaintext)
|
|
15078
|
+
claudemesh skill print the bundled SKILL.md to stdout
|
|
14323
15079
|
claudemesh me cross-mesh workspace overview (v0.4.0)
|
|
14324
15080
|
claudemesh me topics cross-mesh topic list [--unread]
|
|
14325
15081
|
claudemesh me notifications cross-mesh @-mentions [--all] [--since=ISO]
|
|
@@ -14355,6 +15111,8 @@ Platform
|
|
|
14355
15111
|
claudemesh vault list|delete encrypted secrets
|
|
14356
15112
|
claudemesh watch list|remove URL change watchers
|
|
14357
15113
|
claudemesh webhook list|delete outbound HTTP triggers
|
|
15114
|
+
claudemesh file share <path> [--to peer] upload (or local-host fast path if --to matches)
|
|
15115
|
+
claudemesh file get <id> [--out path] download by id
|
|
14358
15116
|
claudemesh file list|status|delete shared mesh files
|
|
14359
15117
|
claudemesh mesh-mcp list|call|catalog deployed mesh-MCP servers
|
|
14360
15118
|
claudemesh clock set|pause|resume mesh logical clock
|
|
@@ -14960,7 +15718,10 @@ async function main() {
|
|
|
14960
15718
|
case "skill": {
|
|
14961
15719
|
const sub = positionals[0];
|
|
14962
15720
|
const f = { mesh: flags.mesh, json: !!flags.json };
|
|
14963
|
-
if (sub
|
|
15721
|
+
if (!sub) {
|
|
15722
|
+
const { runSkill: runSkill2 } = await Promise.resolve().then(() => (init_skill(), exports_skill));
|
|
15723
|
+
process.exit(await runSkill2());
|
|
15724
|
+
} else if (sub === "list") {
|
|
14964
15725
|
const { runSkillList: runSkillList2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
|
|
14965
15726
|
process.exit(await runSkillList2({ ...f, query: positionals[1] }));
|
|
14966
15727
|
} else if (sub === "get") {
|
|
@@ -14970,7 +15731,8 @@ async function main() {
|
|
|
14970
15731
|
const { runSkillRemove: runSkillRemove2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
|
|
14971
15732
|
process.exit(await runSkillRemove2(positionals[1] ?? "", f));
|
|
14972
15733
|
} else {
|
|
14973
|
-
console.error(
|
|
15734
|
+
console.error(`Usage: claudemesh skill (print bundled SKILL.md)
|
|
15735
|
+
claudemesh skill <list|get|remove>`);
|
|
14974
15736
|
process.exit(EXIT.INVALID_ARGS);
|
|
14975
15737
|
}
|
|
14976
15738
|
break;
|
|
@@ -15023,7 +15785,19 @@ async function main() {
|
|
|
15023
15785
|
case "file": {
|
|
15024
15786
|
const sub = positionals[0];
|
|
15025
15787
|
const f = { mesh: flags.mesh, json: !!flags.json };
|
|
15026
|
-
if (sub === "
|
|
15788
|
+
if (sub === "share") {
|
|
15789
|
+
const { runFileShare: runFileShare2 } = await Promise.resolve().then(() => (init_file(), exports_file));
|
|
15790
|
+
process.exit(await runFileShare2(positionals[1] ?? "", {
|
|
15791
|
+
...f,
|
|
15792
|
+
to: flags.to,
|
|
15793
|
+
tags: flags.tags,
|
|
15794
|
+
message: flags.message,
|
|
15795
|
+
upload: !!flags.upload
|
|
15796
|
+
}));
|
|
15797
|
+
} else if (sub === "get") {
|
|
15798
|
+
const { runFileGet: runFileGet2 } = await Promise.resolve().then(() => (init_file(), exports_file));
|
|
15799
|
+
process.exit(await runFileGet2(positionals[1] ?? "", { ...f, out: flags.out }));
|
|
15800
|
+
} else if (sub === "list") {
|
|
15027
15801
|
const { runFileList: runFileList2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
|
|
15028
15802
|
process.exit(await runFileList2({ ...f, query: positionals[1] }));
|
|
15029
15803
|
} else if (sub === "status") {
|
|
@@ -15033,7 +15807,7 @@ async function main() {
|
|
|
15033
15807
|
const { runFileDelete: runFileDelete2 } = await Promise.resolve().then(() => (init_platform_actions(), exports_platform_actions));
|
|
15034
15808
|
process.exit(await runFileDelete2(positionals[1] ?? "", f));
|
|
15035
15809
|
} else {
|
|
15036
|
-
console.error("Usage: claudemesh file <list|status|delete>");
|
|
15810
|
+
console.error("Usage: claudemesh file <share|get|list|status|delete>");
|
|
15037
15811
|
process.exit(EXIT.INVALID_ARGS);
|
|
15038
15812
|
}
|
|
15039
15813
|
break;
|
|
@@ -15315,4 +16089,4 @@ main().catch((err) => {
|
|
|
15315
16089
|
process.exit(EXIT.INTERNAL_ERROR);
|
|
15316
16090
|
});
|
|
15317
16091
|
|
|
15318
|
-
//# debugId=
|
|
16092
|
+
//# debugId=4702C484C802D1AB64756E2164756E21
|