/** * Platform CLI verbs — vector / graph / context / stream / sql / skill / * vault / watch / webhook / task / clock. These wrap broker methods that * previously were only callable via MCP tools. * * All verbs run cold-path (open own WS via `withMesh`). Bridge expansion * for high-frequency reads (vector_search, graph_query, sql_query) lands * in 1.3.1. * * Spec: .artifacts/specs/2026-05-02-architecture-north-star.md */ import { withMesh } from "./connect.js"; import { render } from "~/ui/render.js"; import { bold, clay, dim } from "~/ui/styles.js"; import { EXIT } from "~/constants/exit-codes.js"; type Flags = { mesh?: string; json?: boolean }; function emitJson(data: unknown): void { console.log(JSON.stringify(data, null, 2)); } // ════════════════════════════════════════════════════════════════════════ // vector — embedding store + similarity search // ════════════════════════════════════════════════════════════════════════ export async function runVectorStore( collection: string, text: string, opts: Flags & { metadata?: string }, ): Promise { if (!collection || !text) { render.err("Usage: claudemesh vector store [--metadata ]"); return EXIT.INVALID_ARGS; } let metadata: Record | undefined; if (opts.metadata) { try { metadata = JSON.parse(opts.metadata) as Record; } catch { render.err("--metadata must be JSON"); return EXIT.INVALID_ARGS; } } return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const id = await client.vectorStore(collection, text, metadata); if (!id) { render.err("store failed"); return EXIT.INTERNAL_ERROR; } if (opts.json) emitJson({ id, collection }); else render.ok(`stored in ${clay(collection)}`, dim(id)); return EXIT.SUCCESS; }); } export async function runVectorSearch( collection: string, query: string, opts: Flags & { limit?: string }, ): Promise { if (!collection || !query) { render.err("Usage: claudemesh vector search [--limit N]"); return EXIT.INVALID_ARGS; } const limit = opts.limit ? parseInt(opts.limit, 10) : undefined; return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const hits = await client.vectorSearch(collection, query, limit); if (opts.json) { emitJson(hits); return EXIT.SUCCESS; } if (hits.length === 0) { render.info(dim("(no matches)")); return EXIT.SUCCESS; } render.section(`${hits.length} match${hits.length === 1 ? "" : "es"} in ${clay(collection)}`); for (const h of hits) { process.stdout.write(` ${bold(h.score.toFixed(3))} ${dim(h.id.slice(0, 8))} ${h.text}\n`); } return EXIT.SUCCESS; }); } export async function runVectorDelete( collection: string, id: string, opts: Flags, ): Promise { if (!collection || !id) { render.err("Usage: claudemesh vector delete "); return EXIT.INVALID_ARGS; } return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { await client.vectorDelete(collection, id); if (opts.json) emitJson({ id, deleted: true }); else render.ok(`deleted ${dim(id.slice(0, 8))}`); return EXIT.SUCCESS; }); } export async function runVectorCollections(opts: Flags): Promise { return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const cols = await client.listCollections(); if (opts.json) { emitJson(cols); return EXIT.SUCCESS; } if (cols.length === 0) { render.info(dim("(no collections)")); return EXIT.SUCCESS; } render.section(`vector collections (${cols.length})`); for (const c of cols) process.stdout.write(` ${clay(c)}\n`); return EXIT.SUCCESS; }); } // ════════════════════════════════════════════════════════════════════════ // graph — Cypher query / execute // ════════════════════════════════════════════════════════════════════════ export async function runGraphQuery(cypher: string, opts: Flags): Promise { if (!cypher) { render.err("Usage: claudemesh graph query \"\""); return EXIT.INVALID_ARGS; } return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const rows = await client.graphQuery(cypher); if (opts.json) { emitJson(rows); return EXIT.SUCCESS; } if (rows.length === 0) { render.info(dim("(no rows)")); return EXIT.SUCCESS; } render.section(`${rows.length} row${rows.length === 1 ? "" : "s"}`); for (const r of rows) process.stdout.write(` ${JSON.stringify(r)}\n`); return EXIT.SUCCESS; }); } export async function runGraphExecute(cypher: string, opts: Flags): Promise { if (!cypher) { render.err("Usage: claudemesh graph execute \"\""); return EXIT.INVALID_ARGS; } return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const rows = await client.graphExecute(cypher); if (opts.json) { emitJson(rows); return EXIT.SUCCESS; } render.ok("executed", `${rows.length} row${rows.length === 1 ? "" : "s"} affected`); return EXIT.SUCCESS; }); } // ════════════════════════════════════════════════════════════════════════ // context — share work-context summaries // ════════════════════════════════════════════════════════════════════════ export async function runContextShare( summary: string, opts: Flags & { files?: string; findings?: string; tags?: string }, ): Promise { if (!summary) { render.err("Usage: claudemesh context share \"\" [--files a,b] [--findings x,y] [--tags t1,t2]"); return EXIT.INVALID_ARGS; } const files = opts.files?.split(",").map((s) => s.trim()).filter(Boolean); const findings = opts.findings?.split(",").map((s) => s.trim()).filter(Boolean); const tags = opts.tags?.split(",").map((s) => s.trim()).filter(Boolean); return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { await client.shareContext(summary, files, findings, tags); if (opts.json) emitJson({ shared: true, summary }); else render.ok("context shared"); return EXIT.SUCCESS; }); } export async function runContextGet(query: string, opts: Flags): Promise { if (!query) { render.err("Usage: claudemesh context get \"\""); return EXIT.INVALID_ARGS; } return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const ctxs = await client.getContext(query); if (opts.json) { emitJson(ctxs); return EXIT.SUCCESS; } if (ctxs.length === 0) { render.info(dim("(no matches)")); return EXIT.SUCCESS; } render.section(`${ctxs.length} context${ctxs.length === 1 ? "" : "s"}`); for (const c of ctxs) { process.stdout.write(` ${bold(c.peerName)} ${dim("·")} ${c.updatedAt}\n`); process.stdout.write(` ${c.summary}\n`); if (c.tags.length) process.stdout.write(` ${dim("tags: " + c.tags.join(", "))}\n`); } return EXIT.SUCCESS; }); } export async function runContextList(opts: Flags): Promise { return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const ctxs = await client.listContexts(); if (opts.json) { emitJson(ctxs); return EXIT.SUCCESS; } if (ctxs.length === 0) { render.info(dim("(no contexts)")); return EXIT.SUCCESS; } render.section(`shared contexts (${ctxs.length})`); for (const c of ctxs) { process.stdout.write(` ${bold(c.peerName)} ${dim("·")} ${c.updatedAt}\n`); process.stdout.write(` ${c.summary}\n`); } return EXIT.SUCCESS; }); } // ════════════════════════════════════════════════════════════════════════ // stream — pub/sub event bus per mesh // ════════════════════════════════════════════════════════════════════════ export async function runStreamCreate(name: string, opts: Flags): Promise { if (!name) { render.err("Usage: claudemesh stream create "); return EXIT.INVALID_ARGS; } return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const id = await client.createStream(name); if (!id) { render.err("create failed"); return EXIT.INTERNAL_ERROR; } if (opts.json) emitJson({ id, name }); else render.ok(`created ${clay(name)}`, dim(id)); return EXIT.SUCCESS; }); } export async function runStreamPublish(name: string, dataRaw: string, opts: Flags): Promise { if (!name || dataRaw === undefined) { render.err("Usage: claudemesh stream publish "); return EXIT.INVALID_ARGS; } let data: unknown; try { data = JSON.parse(dataRaw); } catch { data = dataRaw; } return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { await client.publish(name, data); if (opts.json) emitJson({ published: true, name }); else render.ok(`published to ${clay(name)}`); return EXIT.SUCCESS; }); } export async function runStreamList(opts: Flags): Promise { return await withMesh({ meshSlug: opts.mesh ?? null }, async (client) => { const streams = await client.listStreams(); if (opts.json) { emitJson(streams); return EXIT.SUCCESS; } if (streams.length === 0) { render.info(dim("(no streams)")); return EXIT.SUCCESS; } render.section(`streams (${streams.length})`); for (const s of streams) { process.stdout.write(` ${clay(s.name)} ${dim(`· ${s.subscriberCount} subscriber${s.subscriberCount === 1 ? "" : "s"} · by ${s.createdBy}`)}\n`); } return EXIT.SUCCESS; }); } // ════════════════════════════════════════════════════════════════════════ // sql — typed query against per-mesh tables // ════════════════════════════════════════════════════════════════════════ export async function runSqlQuery(sql: string, opts: Flags): Promise { if (!sql) { render.err("Usage: claudemesh sql query \"