feat(cli): 1.5.0 — CLI-first architecture, tool-less MCP, policy engine
CLI becomes the API; MCP becomes a tool-less push-pipe. Bundle -42% (250 KB → 146 KB) after stripping ~1700 lines of dead tool handlers. - Tool-less MCP: tools/list returns []. Inbound peer messages still arrive as experimental.claude/channel notifications mid-turn. - Resource-noun-verb CLI: peer list, message send, memory recall, etc. Legacy flat verbs (peers, send, remember) remain as aliases. - Bundled claudemesh skill auto-installed by `claudemesh install` — sole CLI-discoverability surface for Claude. - Unix-socket bridge: CLI invocations dial the push-pipe's warm WS (~220 ms warm vs ~600 ms cold). - --mesh <slug> flag: connect a session to multiple meshes. - Policy engine: every broker-touching verb runs through a YAML gate at ~/.claudemesh/policy.yaml (auto-created). Destructive verbs prompt; non-TTY auto-denies. Audit log at ~/.claudemesh/audit.log. - --approval-mode plan|read-only|write|yolo + --policy <path>. Spec: .artifacts/specs/2026-05-02-architecture-north-star.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { create as createMesh } from "~/services/mesh/facade.js";
|
||||
import { getStoredToken } from "~/services/auth/facade.js";
|
||||
import { green, dim, icons } from "~/ui/styles.js";
|
||||
import { render } from "~/ui/render.js";
|
||||
import { bold, clay, dim } from "~/ui/styles.js";
|
||||
import { EXIT } from "~/constants/exit-codes.js";
|
||||
|
||||
export async function newMesh(
|
||||
@@ -8,16 +9,17 @@ export async function newMesh(
|
||||
opts: { template?: string; description?: string; json?: boolean },
|
||||
): Promise<number> {
|
||||
if (!name) {
|
||||
console.error(" Usage: claudemesh mesh create <name>");
|
||||
render.err("Usage: claudemesh create <name>");
|
||||
return EXIT.INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (!getStoredToken()) {
|
||||
console.log(dim(" Not signed in — starting login…\n"));
|
||||
render.info(dim("not signed in — starting login…"));
|
||||
render.blank();
|
||||
const { login } = await import("./login.js");
|
||||
const loginResult = await login();
|
||||
if (loginResult !== EXIT.SUCCESS) return loginResult;
|
||||
console.log("");
|
||||
render.blank();
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -28,20 +30,26 @@ export async function newMesh(
|
||||
|
||||
if (opts.json) {
|
||||
console.log(JSON.stringify({ schema_version: "1.0", ...result }, null, 2));
|
||||
} else {
|
||||
console.log(`\n ${green(icons.check)} Created "${result.slug}" (id: ${result.id})`);
|
||||
console.log(` ${green(icons.check)} You're the owner`);
|
||||
console.log(` ${green(icons.check)} Joined locally`);
|
||||
console.log(`\n Share with: claudemesh mesh share\n`);
|
||||
return EXIT.SUCCESS;
|
||||
}
|
||||
|
||||
render.section(`created ${bold(result.slug)}`);
|
||||
render.kv([
|
||||
["id", dim(result.id)],
|
||||
["role", clay("owner")],
|
||||
["local", "joined"],
|
||||
]);
|
||||
render.blank();
|
||||
render.hint(`share with: ${bold("claudemesh share")}`);
|
||||
render.blank();
|
||||
|
||||
return EXIT.SUCCESS;
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
if (msg.includes("409") || msg.includes("already exists")) {
|
||||
console.error(` ${icons.cross} A mesh with this name already exists. Try a different name.`);
|
||||
render.err("A mesh with this name already exists.", "Try a different name.");
|
||||
} else {
|
||||
console.error(` ${icons.cross} Failed: ${msg}`);
|
||||
render.err(`Failed: ${msg}`);
|
||||
}
|
||||
return EXIT.INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user