feat(cli): wss push → mcp channel injection + status hooks in install
Some checks failed
CI / Lint (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Broker tests (Postgres) (push) Has been cancelled
CI / Docker build (linux/amd64) (push) Has been cancelled

Full parity with claude-peers:

1. Push-injection (the "tap on shoulder" UX)
   - MCP server now declares experimental.claude/channel capability
   - BrokerClient onPush handlers emit server.notification({
       method: "notifications/claude/channel",
       params: { content, meta: {from_id, from_name, mesh_slug,
                  mesh_id, priority, sent_at, delivered_at, kind}}
     })
   - Claude Code injects each push as <channel source="claudemesh">
     system reminder, so the receiver session sees inbound messages
     WITHOUT calling check_messages manually
   - Updated MCP instructions with the "RESPOND IMMEDIATELY" framing
     (adapted from claude-peers)

2. Status hooks in install (default-on, --no-hooks to opt out)
   - new apps/cli/src/commands/hook.ts: reads stdin JSON (Claude Code
     hook payload), extracts cwd+session_id, POSTs /hook/set-status
     to every joined mesh's broker in parallel with process.ppid +
     1s timeout per POST. Silent fail, fire-and-forget.
   - install.ts: writes to ~/.claude/settings.json registering
     `claudemesh hook idle` on Stop + `claudemesh hook working` on
     UserPromptSubmit. Idempotent, preserves other hook entries.
   - uninstall.ts: removes both hook entries + MCP entry; leaves
     unrelated hook/MCP entries alone.
   - dedupes by brokerUrl (multiple meshes on same broker → one POST)

3. CLI surface
   - new subcommand: `claudemesh hook <status>` (internal, but
     exposed so Claude Code can invoke it via the hook shell command)
   - `install --no-hooks` for users who want bare MCP registration
   - --help updated

Coexistence with claude-peers: both tools register Stop and
UserPromptSubmit hooks, each POSTs to its own broker. Claude Code
fires multiple hooks per event without conflict.

npm version 0.1.0 → 0.1.1 (patch).

Verified:
- install with hooks → 2 entries added to settings.json ✓
- install --no-hooks → "Hooks skipped" ✓
- uninstall → both MCP entry + 2 hook entries removed ✓
- `echo '{...}' | claudemesh hook idle` with no joined meshes →
  silent no-op ("no joined meshes, nothing to do") ✓
- MCP initialize response includes experimental.claude/channel ✓

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-04-05 19:17:33 +01:00
parent c3fa04dde8
commit b1f428c44b
5 changed files with 338 additions and 25 deletions

View File

@@ -14,6 +14,7 @@ import { runJoin } from "./commands/join";
import { runList } from "./commands/list";
import { runLeave } from "./commands/leave";
import { runSeedTestMesh } from "./commands/seed-test-mesh";
import { runHook } from "./commands/hook";
const HELP = `claudemesh — peer mesh for Claude Code sessions
@@ -21,8 +22,9 @@ Usage:
claudemesh <command> [args]
Commands:
install Register claudemesh as a Claude Code MCP server
uninstall Remove claudemesh MCP server registration
install Register MCP + Stop/UserPromptSubmit status hooks
(add --no-hooks for bare MCP registration)
uninstall Remove MCP server + hooks
join <url> Join a mesh via https://claudemesh.com/join/... URL
list Show all joined meshes
leave <slug> Leave a joined mesh
@@ -45,11 +47,14 @@ async function main(): Promise<void> {
await startMcpServer();
return;
case "install":
runInstall();
runInstall(args);
return;
case "uninstall":
runUninstall();
return;
case "hook":
await runHook(args);
return;
case "join":
await runJoin(args);
return;