The user-facing tool. Two invocation modes:
- `claudemesh mcp` → MCP server (stdio), consumed by Claude Code
- `claudemesh <subcommand>` → human CLI
Layout:
apps/cli/
├── package.json bin: { claudemesh: ./src/index.ts }
├── README.md install + usage
└── src/
├── index.ts dispatcher (mcp | install | join | list | leave | --help)
├── env.ts CLAUDEMESH_BROKER_URL, CONFIG_DIR, DEBUG
├── mcp/
│ ├── server.ts MCP stdio server with 5 tools
│ ├── tools.ts tool schemas (send_message, list_peers,
│ │ check_messages, set_summary, set_status)
│ └── types.ts
├── ws/client.ts broker connection (stub for 15b)
├── state/config.ts ~/.claudemesh/config.json (joined meshes + keys)
└── commands/
├── install.ts print `claude mcp add ...` instruction
├── join.ts parse ic://join/... (stub, Step 17)
├── list.ts show joined meshes
└── leave.ts remove mesh from local config
Tool stubs return "not connected, run `claudemesh join <invite-link>`"
errors until 15b wires the WS client.
Verified:
- `bun src/index.ts --help` → prints usage
- `bun src/index.ts install` → prints MCP add command with resolved path
- `bun src/index.ts list` → "No meshes joined yet"
- `bun src/index.ts mcp` (via stdin) → returns tools/list with all 5 tools
Deps: @modelcontextprotocol/sdk, ws, libsodium-wrappers, zod.
Lockfile regenerated in the same commit per claudemesh-3's flag —
avoids breaking Coolify's --frozen-lockfile deploys.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
26 lines
789 B
TypeScript
26 lines
789 B
TypeScript
/**
|
|
* `claudemesh leave <slug>` — remove a mesh from local config.
|
|
*
|
|
* Does NOT (yet) notify the broker. In 15b+ this will send a
|
|
* best-effort revoke request before removing the entry.
|
|
*/
|
|
|
|
import { loadConfig, saveConfig } from "../state/config";
|
|
|
|
export function runLeave(args: string[]): void {
|
|
const slug = args[0];
|
|
if (!slug) {
|
|
console.error("Usage: claudemesh leave <slug>");
|
|
process.exit(1);
|
|
}
|
|
const config = loadConfig();
|
|
const before = config.meshes.length;
|
|
config.meshes = config.meshes.filter((m) => m.slug !== slug);
|
|
if (config.meshes.length === before) {
|
|
console.error(`claudemesh: no joined mesh with slug "${slug}"`);
|
|
process.exit(1);
|
|
}
|
|
saveConfig(config);
|
|
console.log(`Left mesh "${slug}". Remaining: ${config.meshes.length}`);
|
|
}
|