feat(cli): vault set / watch add / webhook create + prune dead MCP stubs
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

Closes the last functional gaps where the MCP tool registry exposed
write verbs the CLI didn't:

- vault set <k> <v> [--type env|file --mount <path> --description ...]
  Client-side crypto_secretbox_easy with a fresh symmetric key sealed
  to the member's own pubkey via crypto_box_seal — same pattern used
  for file shares. Pairs with the existing vault list/delete.
- watch add <url> [--label --interval --mode --extract --notify-on]
  Pairs with watch list/remove.
- webhook create <name> — pairs with webhook list/delete.

Cleanup: deletes 22 stub files under apps/cli/src/mcp/tools/* plus
router.ts, middleware/, handlers/ (~120 LoC). These were FAMILY/TOOLS
metadata-only re-exports left over from before the 1.5.0 tool-less
push-pipe flip; nothing imports them. The legitimate MCP surfaces
stay: the inbound <channel> push pipe, mesh skills as prompts and
skill:// resources, and the mesh-service proxy mode.

Released as 1.23.0 on npm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-05-03 20:53:25 +01:00
parent 4eff4f5a20
commit c56910bfcf
31 changed files with 160 additions and 120 deletions

View File

@@ -156,9 +156,9 @@ Platform
claudemesh stream create|publish|list pub/sub event bus
claudemesh sql query|execute|schema per-mesh SQL
claudemesh skill list|get|remove mesh-published skills
claudemesh vault list|delete encrypted secrets
claudemesh watch list|remove URL change watchers
claudemesh webhook list|delete outbound HTTP triggers
claudemesh vault set|list|delete encrypted secrets (set: --type env|file --mount /p)
claudemesh watch add|list|remove URL change watchers (add: --label --interval --extract)
claudemesh webhook create|list|delete outbound HTTP triggers
claudemesh file share <path> [--to peer] upload (or local-host fast path if --to matches)
claudemesh file get <id> [--out path] download by id
claudemesh file list|status|delete shared mesh files
@@ -591,7 +591,16 @@ async function main(): Promise<void> {
const f = { mesh: flags.mesh as string, json: !!flags.json };
if (sub === "list") { const { runVaultList } = await import("~/commands/platform-actions.js"); process.exit(await runVaultList(f)); }
else if (sub === "delete") { const { runVaultDelete } = await import("~/commands/platform-actions.js"); process.exit(await runVaultDelete(positionals[1] ?? "", f)); }
else { console.error("Usage: claudemesh vault <list|delete> (set/get currently via MCP — needs crypto)"); process.exit(EXIT.INVALID_ARGS); }
else if (sub === "set") {
const { runVaultSet } = await import("~/commands/platform-actions.js");
process.exit(await runVaultSet(positionals[1] ?? "", positionals[2] ?? "", {
...f,
entryType: (flags.type as "env" | "file" | undefined),
mountPath: flags.mount as string | undefined,
description: flags.description as string | undefined,
}));
}
else { console.error("Usage: claudemesh vault <list|set|delete>"); process.exit(EXIT.INVALID_ARGS); }
break;
}
case "watch": {
@@ -599,7 +608,18 @@ async function main(): Promise<void> {
const f = { mesh: flags.mesh as string, json: !!flags.json };
if (sub === "list") { const { runWatchList } = await import("~/commands/platform-actions.js"); process.exit(await runWatchList(f)); }
else if (sub === "remove") { const { runUnwatch } = await import("~/commands/platform-actions.js"); process.exit(await runUnwatch(positionals[1] ?? "", f)); }
else { console.error("Usage: claudemesh watch <list|remove>"); process.exit(EXIT.INVALID_ARGS); }
else if (sub === "add") {
const { runWatchAdd } = await import("~/commands/platform-actions.js");
process.exit(await runWatchAdd(positionals[1] ?? "", {
...f,
label: flags.label as string | undefined,
interval: flags.interval ? Number(flags.interval) : undefined,
mode: flags.mode as string | undefined,
extract: flags.extract as string | undefined,
notifyOn: flags["notify-on"] as string | undefined,
}));
}
else { console.error("Usage: claudemesh watch <list|add|remove>"); process.exit(EXIT.INVALID_ARGS); }
break;
}
case "webhook": {
@@ -607,7 +627,8 @@ async function main(): Promise<void> {
const f = { mesh: flags.mesh as string, json: !!flags.json };
if (sub === "list") { const { runWebhookList } = await import("~/commands/platform-actions.js"); process.exit(await runWebhookList(f)); }
else if (sub === "delete") { const { runWebhookDelete } = await import("~/commands/platform-actions.js"); process.exit(await runWebhookDelete(positionals[1] ?? "", f)); }
else { console.error("Usage: claudemesh webhook <list|delete>"); process.exit(EXIT.INVALID_ARGS); }
else if (sub === "create") { const { runWebhookCreate } = await import("~/commands/platform-actions.js"); process.exit(await runWebhookCreate(positionals[1] ?? "", f)); }
else { console.error("Usage: claudemesh webhook <list|create|delete>"); process.exit(EXIT.INVALID_ARGS); }
break;
}
case "file": {