From 8931296e82d6502936300be3cdc8ffb40e915d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:23:12 +0100 Subject: [PATCH] feat(cli): scaffold @claudemesh/cli MCP client package (stubs) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user-facing tool. Two invocation modes: - `claudemesh mcp` → MCP server (stdio), consumed by Claude Code - `claudemesh ` → 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 `" 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) --- apps/cli/README.md | 59 +++++ apps/cli/eslint.config.js | 3 + apps/cli/package.json | 37 +++ apps/cli/src/commands/install.ts | 36 +++ apps/cli/src/commands/join.ts | 30 +++ apps/cli/src/commands/leave.ts | 25 ++ apps/cli/src/commands/list.ts | 28 ++ apps/cli/src/env.ts | 27 ++ apps/cli/src/index.ts | 73 ++++++ apps/cli/src/mcp/server.ts | 86 +++++++ apps/cli/src/mcp/tools.ts | 81 ++++++ apps/cli/src/mcp/types.ts | 24 ++ apps/cli/src/state/config.ts | 58 +++++ apps/cli/src/ws/client.ts | 40 +++ apps/cli/tsconfig.json | 15 ++ pnpm-lock.yaml | 428 ++++++++++++++++++++++++++++++- 16 files changed, 1048 insertions(+), 2 deletions(-) create mode 100644 apps/cli/README.md create mode 100644 apps/cli/eslint.config.js create mode 100644 apps/cli/package.json create mode 100644 apps/cli/src/commands/install.ts create mode 100644 apps/cli/src/commands/join.ts create mode 100644 apps/cli/src/commands/leave.ts create mode 100644 apps/cli/src/commands/list.ts create mode 100644 apps/cli/src/env.ts create mode 100644 apps/cli/src/index.ts create mode 100644 apps/cli/src/mcp/server.ts create mode 100644 apps/cli/src/mcp/tools.ts create mode 100644 apps/cli/src/mcp/types.ts create mode 100644 apps/cli/src/state/config.ts create mode 100644 apps/cli/src/ws/client.ts create mode 100644 apps/cli/tsconfig.json diff --git a/apps/cli/README.md b/apps/cli/README.md new file mode 100644 index 0000000..9ce1112 --- /dev/null +++ b/apps/cli/README.md @@ -0,0 +1,59 @@ +# @claudemesh/cli + +Client tool for claudemesh — install once per machine, join one or more +meshes, and your Claude Code sessions can talk to peers on demand. + +## Install + +```sh +# From npm (once published) +npm install -g @claudemesh/cli + +# Or from the monorepo during dev +cd apps/cli && bun link +``` + +Then register the MCP server with Claude Code: + +```sh +claudemesh install +# prints: claude mcp add claudemesh --scope user -- claudemesh mcp +``` + +Run the printed command, then restart Claude Code. + +## Join a mesh + +```sh +claudemesh join ic://join/BASE64URL... +``` + +The invite link is generated by whoever runs the mesh. It bundles the +mesh id, expiry, signing key, and role. Your CLI verifies it, +generates a fresh keypair, enrolls you with the broker, and persists +the result to `~/.claudemesh/config.json`. + +## Commands + +```sh +claudemesh install # print MCP registration command +claudemesh join # join a mesh via invite link +claudemesh list # show joined meshes + identities +claudemesh leave # leave a mesh +claudemesh mcp # start MCP server (stdio — Claude Code only) +claudemesh --help # show usage +``` + +## Env overrides + +| Var | Default | Purpose | +| ----------------------- | ---------------------------- | ------------------------------ | +| `CLAUDEMESH_BROKER_URL` | `wss://ic.claudemesh.com/ws` | Point at a self-hosted broker | +| `CLAUDEMESH_CONFIG_DIR` | `~/.claudemesh/` | Override config location | +| `CLAUDEMESH_DEBUG` | `0` | Verbose logging | + +## Status + +v0.1.0 scaffold — CLI commands + MCP server shell in place. WS broker +connection, libsodium crypto, invite-link verification, and auto-install +of hooks land in subsequent steps. diff --git a/apps/cli/eslint.config.js b/apps/cli/eslint.config.js new file mode 100644 index 0000000..005be22 --- /dev/null +++ b/apps/cli/eslint.config.js @@ -0,0 +1,3 @@ +import baseConfig from "@turbostarter/eslint-config/base"; + +export default baseConfig; diff --git a/apps/cli/package.json b/apps/cli/package.json new file mode 100644 index 0000000..2e16993 --- /dev/null +++ b/apps/cli/package.json @@ -0,0 +1,37 @@ +{ + "name": "@claudemesh/cli", + "version": "0.1.0", + "private": true, + "type": "module", + "bin": { + "claudemesh": "./src/index.ts" + }, + "scripts": { + "clean": "git clean -xdf .cache .turbo dist node_modules", + "dev": "bun --hot src/index.ts", + "start": "bun src/index.ts", + "format": "prettier --check . --ignore-path ../../.gitignore", + "lint": "eslint", + "test": "vitest run", + "typecheck": "tsc --noEmit" + }, + "prettier": "@turbostarter/prettier-config", + "dependencies": { + "@modelcontextprotocol/sdk": "1.27.1", + "libsodium-wrappers": "0.7.15", + "ws": "8.20.0", + "zod": "catalog:" + }, + "devDependencies": { + "@turbostarter/eslint-config": "workspace:*", + "@turbostarter/prettier-config": "workspace:*", + "@turbostarter/tsconfig": "workspace:*", + "@turbostarter/vitest-config": "workspace:*", + "@types/libsodium-wrappers": "0.7.14", + "@types/ws": "8.5.13", + "eslint": "catalog:", + "prettier": "catalog:", + "typescript": "catalog:", + "vitest": "catalog:" + } +} diff --git a/apps/cli/src/commands/install.ts b/apps/cli/src/commands/install.ts new file mode 100644 index 0000000..83c3ad2 --- /dev/null +++ b/apps/cli/src/commands/install.ts @@ -0,0 +1,36 @@ +/** + * `claudemesh install` — print Claude Code MCP registration instructions. + * + * In the v1 flow, users copy-paste a `claude mcp add ...` command. + * Later we'll auto-write the MCP entry to ~/.claude.json and hooks + * to ~/.claude/settings.json (mirroring claude-intercom's installer). + */ + +import { fileURLToPath } from "node:url"; +import { dirname, resolve } from "node:path"; + +export function runInstall(): void { + // Resolve the path to this package's own index.ts so the generated + // command points at the right binary even when installed globally. + const here = fileURLToPath(import.meta.url); + const entry = resolve(dirname(here), "..", "index.ts"); + + console.log("claudemesh — MCP registration"); + console.log("------------------------------"); + console.log(""); + console.log("Register the MCP server with Claude Code:"); + console.log(""); + console.log(` claude mcp add claudemesh --scope user -- bun ${entry} mcp`); + console.log(""); + console.log("Or if installed globally:"); + console.log(""); + console.log(` claude mcp add claudemesh --scope user -- claudemesh mcp`); + console.log(""); + console.log( + "After registering, restart Claude Code. Then join a mesh with:", + ); + console.log(""); + console.log(" claudemesh join "); + console.log(""); + console.log("(Auto-install of hooks + MCP entry will ship in a later step.)"); +} diff --git a/apps/cli/src/commands/join.ts b/apps/cli/src/commands/join.ts new file mode 100644 index 0000000..49132c4 --- /dev/null +++ b/apps/cli/src/commands/join.ts @@ -0,0 +1,30 @@ +/** + * `claudemesh join ` — parse a mesh invite link and + * join the mesh. + * + * STUB: real invite-link parsing + keypair generation + broker + * enrollment lands in Step 17. For now this just validates the link + * shape and tells the user what's coming. + */ + +export function runJoin(args: string[]): void { + const link = args[0]; + if (!link) { + console.error("Usage: claudemesh join "); + console.error(""); + console.error("Example: claudemesh join ic://join/BASE64URL..."); + process.exit(1); + } + if (!link.startsWith("ic://join/")) { + console.error( + `claudemesh: invalid invite link. Expected ic://join/... got "${link}"`, + ); + process.exit(1); + } + console.log("claudemesh: join not yet implemented (Step 17)."); + console.log(` Invite link parsed: ${link.slice(0, 40)}...`); + console.log( + " Real flow will: verify sig, generate keypair, enroll member, persist to ~/.claudemesh/config.json", + ); + process.exit(0); +} diff --git a/apps/cli/src/commands/leave.ts b/apps/cli/src/commands/leave.ts new file mode 100644 index 0000000..d12e6ea --- /dev/null +++ b/apps/cli/src/commands/leave.ts @@ -0,0 +1,25 @@ +/** + * `claudemesh leave ` — 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 "); + 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}`); +} diff --git a/apps/cli/src/commands/list.ts b/apps/cli/src/commands/list.ts new file mode 100644 index 0000000..7d80ab5 --- /dev/null +++ b/apps/cli/src/commands/list.ts @@ -0,0 +1,28 @@ +/** + * `claudemesh list` — show all joined meshes + their status. + */ + +import { loadConfig, getConfigPath } from "../state/config"; + +export function runList(): void { + const config = loadConfig(); + if (config.meshes.length === 0) { + console.log("No meshes joined yet."); + console.log(""); + console.log("Join one with: claudemesh join "); + console.log(`Config file: ${getConfigPath()}`); + return; + } + console.log(`Joined meshes (${config.meshes.length}):`); + console.log(""); + for (const m of config.meshes) { + console.log(` ${m.name} (${m.slug})`); + console.log(` mesh id: ${m.meshId}`); + console.log(` member id: ${m.memberId}`); + console.log(` pubkey: ${m.pubkey.slice(0, 16)}…`); + console.log(` broker: ${m.brokerUrl}`); + console.log(` joined: ${m.joinedAt}`); + console.log(""); + } + console.log(`Config: ${getConfigPath()}`); +} diff --git a/apps/cli/src/env.ts b/apps/cli/src/env.ts new file mode 100644 index 0000000..9dddba4 --- /dev/null +++ b/apps/cli/src/env.ts @@ -0,0 +1,27 @@ +import { z } from "zod"; + +/** + * CLI environment config. + * + * Read once at startup. Overridable via env vars so users can point + * at a self-hosted broker or a staging instance without rebuilding. + */ +const envSchema = z.object({ + CLAUDEMESH_BROKER_URL: z.string().default("wss://ic.claudemesh.com/ws"), + CLAUDEMESH_CONFIG_DIR: z.string().optional(), + CLAUDEMESH_DEBUG: z.coerce.boolean().default(false), +}); + +export type CliEnv = z.infer; + +export function loadEnv(): CliEnv { + const parsed = envSchema.safeParse(process.env); + if (!parsed.success) { + console.error("[claudemesh] invalid environment:"); + console.error(z.treeifyError(parsed.error)); + process.exit(1); + } + return parsed.data; +} + +export const env = loadEnv(); diff --git a/apps/cli/src/index.ts b/apps/cli/src/index.ts new file mode 100644 index 0000000..992ede1 --- /dev/null +++ b/apps/cli/src/index.ts @@ -0,0 +1,73 @@ +#!/usr/bin/env bun +/** + * @claudemesh/cli entry point. + * + * Dispatches between two modes: + * - `claudemesh mcp` → MCP server (stdio transport) + * - `claudemesh ` → CLI subcommand + * + * Claude Code invokes the `mcp` mode via stdio. Humans use all others. + */ + +import { startMcpServer } from "./mcp/server"; +import { runInstall } from "./commands/install"; +import { runJoin } from "./commands/join"; +import { runList } from "./commands/list"; +import { runLeave } from "./commands/leave"; + +const HELP = `claudemesh — peer mesh for Claude Code sessions + +Usage: + claudemesh [args] + +Commands: + install Print Claude Code MCP registration instructions + join Join a mesh via invite link (ic://join/...) + list Show all joined meshes + leave Leave a joined mesh + mcp Start MCP server (stdio) — invoked by Claude Code + --help, -h Show this help + +Environment: + CLAUDEMESH_BROKER_URL Override broker URL (default: wss://ic.claudemesh.com/ws) + CLAUDEMESH_CONFIG_DIR Override config directory (default: ~/.claudemesh/) + CLAUDEMESH_DEBUG=1 Verbose logging +`; + +const cmd = process.argv[2]; +const args = process.argv.slice(3); + +async function main(): Promise { + switch (cmd) { + case "mcp": + await startMcpServer(); + return; + case "install": + runInstall(); + return; + case "join": + runJoin(args); + return; + case "list": + runList(); + return; + case "leave": + runLeave(args); + return; + case "--help": + case "-h": + case "help": + case undefined: + console.log(HELP); + return; + default: + console.error(`Unknown command: ${cmd}`); + console.error("Run `claudemesh --help` for usage."); + process.exit(1); + } +} + +main().catch((e) => { + console.error(`claudemesh: ${e instanceof Error ? e.message : String(e)}`); + process.exit(1); +}); diff --git a/apps/cli/src/mcp/server.ts b/apps/cli/src/mcp/server.ts new file mode 100644 index 0000000..2359344 --- /dev/null +++ b/apps/cli/src/mcp/server.ts @@ -0,0 +1,86 @@ +/** + * MCP server (stdio transport) for @claudemesh/cli. + * + * Invoked by Claude Code as a stdio subprocess. Exposes the 5 tools + * in tools.ts. In this 15a scaffold, all tools return a "not + * connected" response; 15b will wire them to a live WS broker + * connection. + */ + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + ListToolsRequestSchema, + CallToolRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import { TOOLS } from "./tools"; +import { loadConfig } from "../state/config"; + +const NOT_CONNECTED = { + content: [ + { + type: "text" as const, + text: "claudemesh: not yet connected to broker. Run `claudemesh join ` to join a mesh, then restart your Claude Code session. (Broker client wiring lands in Step 15b — scaffold only for now.)", + }, + ], + isError: true, +}; + +const INSTRUCTIONS = `You are connected to a claudemesh — a peer-to-peer network of other Claude Code sessions. + +Use these tools to coordinate with peers on demand. Each mesh is a trust boundary; messages are E2E-encrypted and routed through a shared broker. + +Available tools: +- send_message: send a direct or channel message +- list_peers: see who else is in your meshes and their status +- check_messages: pull undelivered messages (normally pushed automatically) +- set_summary: describe what you're working on (visible to peers) +- set_status: manually override your presence (idle/working/dnd) + +When you receive an inbound message (channel notification), respond promptly — like answering a knock on the door. The sender is waiting on you.`; + +export async function startMcpServer(): Promise { + // Load config so we know which meshes the user has joined. + const config = loadConfig(); + + const server = new Server( + { name: "claudemesh", version: "0.1.0" }, + { + capabilities: { tools: {} }, + instructions: INSTRUCTIONS, + }, + ); + + server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: TOOLS, + })); + + server.setRequestHandler(CallToolRequestSchema, async (req) => { + const { name } = req.params; + // Stubs: all tools return "not connected" until 15b. + if (config.meshes.length === 0) { + return { + content: [ + { + type: "text" as const, + text: `claudemesh: no meshes joined yet. Run \`claudemesh join \` to join one.`, + }, + ], + isError: true, + }; + } + switch (name) { + case "send_message": + case "list_peers": + case "check_messages": + case "set_summary": + case "set_status": + return NOT_CONNECTED; + default: + throw new Error(`Unknown tool: ${name}`); + } + }); + + const transport = new StdioServerTransport(); + await server.connect(transport); +} diff --git a/apps/cli/src/mcp/tools.ts b/apps/cli/src/mcp/tools.ts new file mode 100644 index 0000000..e4a5fa2 --- /dev/null +++ b/apps/cli/src/mcp/tools.ts @@ -0,0 +1,81 @@ +/** + * MCP tool definitions exposed to Claude Code. + * + * Mirror the claude-intercom tool surface: send_message, list_peers, + * check_messages, set_summary, set_status. Tools return "not + * connected" errors until 15b wires the WS client. + */ + +import type { Tool } from "@modelcontextprotocol/sdk/types.js"; + +export const TOOLS: Tool[] = [ + { + name: "send_message", + description: + "Send a message to a peer in one of your joined meshes. `to` is a peer display name, hex pubkey, or `#channel`. `priority` controls delivery: `now` bypasses busy gates, `next` waits for idle (default), `low` is pull-only.", + inputSchema: { + type: "object", + properties: { + to: { + type: "string", + description: "Peer name, pubkey, or #channel", + }, + message: { type: "string", description: "Message text" }, + priority: { + type: "string", + enum: ["now", "next", "low"], + description: "Delivery priority (default: next)", + }, + }, + required: ["to", "message"], + }, + }, + { + name: "list_peers", + description: + "List peers across all joined meshes. Shows name, mesh, status (idle/working/dnd), and current summary.", + inputSchema: { + type: "object", + properties: { + mesh_slug: { + type: "string", + description: "Only list peers in this mesh (optional)", + }, + }, + }, + }, + { + name: "check_messages", + description: + "Pull any undelivered messages from the broker. Normally messages arrive via push; use this to drain the queue after being offline.", + inputSchema: { type: "object", properties: {} }, + }, + { + name: "set_summary", + description: + "Set a 1–2 sentence summary of what you're working on. Visible to other peers.", + inputSchema: { + type: "object", + properties: { + summary: { type: "string", description: "1-2 sentence summary" }, + }, + required: ["summary"], + }, + }, + { + name: "set_status", + description: + "Manually override your status. `dnd` blocks everything except `now`-priority messages.", + inputSchema: { + type: "object", + properties: { + status: { + type: "string", + enum: ["idle", "working", "dnd"], + description: "Your status", + }, + }, + required: ["status"], + }, + }, +]; diff --git a/apps/cli/src/mcp/types.ts b/apps/cli/src/mcp/types.ts new file mode 100644 index 0000000..b4bc92d --- /dev/null +++ b/apps/cli/src/mcp/types.ts @@ -0,0 +1,24 @@ +/** + * MCP tool schemas + shared types for the CLI's MCP server. + */ + +export type Priority = "now" | "next" | "low"; +export type PeerStatus = "idle" | "working" | "dnd"; + +export interface SendMessageArgs { + to: string; // peer name, pubkey, or #channel + message: string; + priority?: Priority; +} + +export interface ListPeersArgs { + mesh_slug?: string; // filter to one joined mesh +} + +export interface SetSummaryArgs { + summary: string; +} + +export interface SetStatusArgs { + status: PeerStatus; +} diff --git a/apps/cli/src/state/config.ts b/apps/cli/src/state/config.ts new file mode 100644 index 0000000..8f34a82 --- /dev/null +++ b/apps/cli/src/state/config.ts @@ -0,0 +1,58 @@ +/** + * Local persistent config — ~/.claudemesh/config.json + * + * Stores: joined meshes, per-mesh identity keys (ed25519 keypairs), + * last-seen broker URL. Loaded on CLI start, on MCP server start, + * and on every join/leave. + */ + +import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs"; +import { homedir } from "node:os"; +import { join, dirname } from "node:path"; +import { z } from "zod"; +import { env } from "../env"; + +const joinedMeshSchema = z.object({ + meshId: z.string(), + memberId: z.string(), + slug: z.string(), + name: z.string(), + pubkey: z.string(), // ed25519 hex (32 bytes = 64 chars) + secretKey: z.string(), // ed25519 hex (64 bytes = 128 chars) + brokerUrl: z.string(), + joinedAt: z.string(), +}); + +const configSchema = z.object({ + version: z.literal(1).default(1), + meshes: z.array(joinedMeshSchema).default([]), +}); + +export type JoinedMesh = z.infer; +export type Config = z.infer; + +const CONFIG_DIR = env.CLAUDEMESH_CONFIG_DIR ?? join(homedir(), ".claudemesh"); +const CONFIG_PATH = join(CONFIG_DIR, "config.json"); + +export function loadConfig(): Config { + if (!existsSync(CONFIG_PATH)) { + return configSchema.parse({ version: 1, meshes: [] }); + } + try { + const raw = readFileSync(CONFIG_PATH, "utf-8"); + return configSchema.parse(JSON.parse(raw)); + } catch (e) { + throw new Error( + `Failed to load ${CONFIG_PATH}: ${e instanceof Error ? e.message : String(e)}`, + ); + } +} + +export function saveConfig(config: Config): void { + mkdirSync(dirname(CONFIG_PATH), { recursive: true }); + writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8"); +} + +export function getConfigPath(): string { + return CONFIG_PATH; +} diff --git a/apps/cli/src/ws/client.ts b/apps/cli/src/ws/client.ts new file mode 100644 index 0000000..b333896 --- /dev/null +++ b/apps/cli/src/ws/client.ts @@ -0,0 +1,40 @@ +/** + * WS client to the broker (STUB). + * + * Final implementation in Step 15b — connects to broker, sends hello + * (with signed nonce), pumps messages to/from the MCP server, handles + * reconnect. For now just a placeholder type surface so the MCP + * server can depend on it. + */ + +import type { JoinedMesh } from "../state/config"; + +export interface BrokerConnection { + meshId: string; + isConnected(): boolean; + sendMessage(args: { + targetSpec: string; + priority: "now" | "next" | "low"; + nonce: string; + ciphertext: string; + }): Promise<{ ok: boolean; messageId?: string; error?: string }>; + close(): void; +} + +/** + * Stub broker connection. Returns "not implemented" errors on every + * call. Real implementation in 15b will connect to env.CLAUDEMESH_BROKER_URL. + */ +export function connectBroker(_mesh: JoinedMesh): BrokerConnection { + return { + meshId: _mesh.meshId, + isConnected: () => false, + sendMessage: async () => ({ + ok: false, + error: "broker client not implemented (Step 15b)", + }), + close: () => { + /* noop */ + }, + }; +} diff --git a/apps/cli/tsconfig.json b/apps/cli/tsconfig.json new file mode 100644 index 0000000..379db76 --- /dev/null +++ b/apps/cli/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@turbostarter/tsconfig/base.json", + "compilerOptions": { + "lib": ["es2022"], + "module": "esnext", + "moduleResolution": "bundler", + "baseUrl": ".", + "paths": { + "~/*": ["./src/*"] + }, + "types": ["bun-types"] + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8444687..4881c0c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -161,6 +161,52 @@ importers: specifier: 'catalog:' version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.0.13)(@vitest/ui@4.0.14)(jiti@2.6.1)(jsdom@26.0.0)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.19.2)(yaml@2.8.0) + apps/cli: + dependencies: + '@modelcontextprotocol/sdk': + specifier: 1.27.1 + version: 1.27.1(zod@4.1.13) + libsodium-wrappers: + specifier: 0.7.15 + version: 0.7.15 + ws: + specifier: 8.20.0 + version: 8.20.0 + zod: + specifier: 'catalog:' + version: 4.1.13 + devDependencies: + '@turbostarter/eslint-config': + specifier: workspace:* + version: link:../../tooling/eslint + '@turbostarter/prettier-config': + specifier: workspace:* + version: link:../../tooling/prettier + '@turbostarter/tsconfig': + specifier: workspace:* + version: link:../../tooling/typescript + '@turbostarter/vitest-config': + specifier: workspace:* + version: link:../../tooling/vitest + '@types/libsodium-wrappers': + specifier: 0.7.14 + version: 0.7.14 + '@types/ws': + specifier: 8.5.13 + version: 8.5.13 + eslint: + specifier: 'catalog:' + version: 9.39.0(jiti@2.6.1) + prettier: + specifier: 'catalog:' + version: 3.6.2 + typescript: + specifier: 'catalog:' + version: 5.9.3 + vitest: + specifier: 'catalog:' + version: 4.0.14(@opentelemetry/api@1.9.0)(@types/node@24.0.13)(@vitest/ui@4.0.14)(jiti@2.6.1)(jsdom@26.0.0)(lightningcss@1.30.2)(terser@5.43.1)(tsx@4.19.2)(yaml@2.8.0) + apps/web: dependencies: '@ai-sdk/react': @@ -3461,6 +3507,12 @@ packages: '@hexagon/base64@1.1.28': resolution: {integrity: sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==} + '@hono/node-server@1.19.12': + resolution: {integrity: sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@hono/zod-validator@0.7.4': resolution: {integrity: sha512-biKGn3BRJVaftZlIPMyK+HCe/UHAjJ6sH0UyXe3+v0OcgVr9xfImDROTJFLtn9e3XEEAHGZIM9U6evu85abm8Q==} peerDependencies: @@ -3835,6 +3887,16 @@ packages: '@mixpanel/rrweb@2.0.0-alpha.18.2': resolution: {integrity: sha512-J3dVTEu6Z4p8di7y9KKvUooNuBjX97DdG6XGWoPEPi07A9512h9M8MEtvlY3mK0PGfuC0Mz5Pv/Ws6gjGYfKQg==} + '@modelcontextprotocol/sdk@1.27.1': + resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@napi-rs/canvas-android-arm64@0.1.88': resolution: {integrity: sha512-KEaClPnZuVxJ8smUWjV1wWFkByBO/D+vy4lN+Dm5DFH514oqwukxKGeck9xcKJhaWJGjfruGmYGiwRe//+/zQQ==} engines: {node: '>= 10'} @@ -7297,6 +7359,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -7354,6 +7420,14 @@ packages: ajv: optional: true + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-keywords@5.1.0: resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} peerDependencies: @@ -7686,6 +7760,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -7986,6 +8064,14 @@ packages: constant-case@2.0.0: resolution: {integrity: sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + conventional-changelog-angular@7.0.0: resolution: {integrity: sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ==} engines: {node: '>=16'} @@ -8005,6 +8091,10 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} @@ -8230,6 +8320,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize@1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} @@ -8844,6 +8943,10 @@ packages: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + exec-async@2.2.0: resolution: {integrity: sha512-87OpwcEiMia/DeiKFzaQNBNFeN3XkkpYIh9FyOqq5mS2oKv3CBE67PXoEKcr6nodWdXNogTiQ0jE2NGuoffXPw==} @@ -8988,6 +9091,16 @@ packages: exponential-backoff@3.1.2: resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + express-rate-limit@8.3.2: + resolution: {integrity: sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + exsolve@1.0.7: resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} @@ -9089,6 +9202,10 @@ packages: resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -9137,6 +9254,10 @@ packages: forwarded-parse@2.1.2: resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -9176,6 +9297,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fromentries@1.3.2: resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} @@ -9442,6 +9567,10 @@ packages: resolution: {integrity: sha512-YG/fo7zlU3KwrBL5vDpWKisLYiM+nVstBQqfr7gCPbSYURnNEP9BDxEMz8KfsDR9JX0lJWDRNc6nXX31v7ZEyg==} engines: {node: '>=16.9.0'} + hono@4.12.10: + resolution: {integrity: sha512-mx/p18PLy5og9ufies2GOSUqep98Td9q4i/EF6X7yJgAiIopxqdfIO3jbqsi3jRgTgw88jMDEzVKi+V2EF+27w==} + engines: {node: '>=16.9.0'} + hosted-git-info@7.0.2: resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} engines: {node: ^16.14.0 || >=18.0.0} @@ -9473,6 +9602,10 @@ packages: resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} engines: {node: '>= 0.8'} + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -9519,6 +9652,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -9607,10 +9744,18 @@ packages: invariant@2.2.4: resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + ip-address@9.0.5: resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} engines: {node: '>= 12'} + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} @@ -9744,6 +9889,9 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -9932,6 +10080,9 @@ packages: jose@6.1.0: resolution: {integrity: sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==} + jose@6.2.2: + resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -9987,6 +10138,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} @@ -10370,6 +10524,10 @@ packages: mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + memoize-one@5.2.1: resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} @@ -10380,6 +10538,10 @@ packages: resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==} engines: {node: '>=16.10'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-options@3.0.4: resolution: {integrity: sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==} engines: {node: '>=10'} @@ -10556,6 +10718,10 @@ packages: resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -11089,6 +11255,9 @@ packages: resolution: {integrity: sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==} engines: {node: 20 || >=22} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -11173,6 +11342,10 @@ packages: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} engines: {node: '>=8'} @@ -11446,6 +11619,10 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + proxy-agent@6.5.0: resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} engines: {node: '>= 14'} @@ -11481,6 +11658,10 @@ packages: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + query-string@7.1.3: resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} engines: {node: '>=6'} @@ -11514,6 +11695,10 @@ packages: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -11962,6 +12147,10 @@ packages: rou3@0.7.10: resolution: {integrity: sha512-aoFj6f7MJZ5muJ+Of79nrhs9N3oLGqi2VEMe94Zbkjb6Wupha46EuoYgpWSOZlXww3bbd8ojgXTAA2mzimX5Ww==} + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} @@ -12054,6 +12243,10 @@ packages: resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} engines: {node: '>= 0.8.0'} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + sentence-case@2.1.1: resolution: {integrity: sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==} @@ -12068,6 +12261,10 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + server-only@0.0.1: resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} @@ -12294,6 +12491,10 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -12745,6 +12946,10 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -13362,6 +13567,11 @@ packages: resolution: {integrity: sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==} engines: {node: '>=18'} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + zod@3.24.3: resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} @@ -16024,6 +16234,10 @@ snapshots: '@hexagon/base64@1.1.28': {} + '@hono/node-server@1.19.12(hono@4.12.10)': + dependencies: + hono: 4.12.10 + '@hono/zod-validator@0.7.4(hono@4.10.4)(zod@4.1.13)': dependencies: hono: 4.10.4 @@ -16367,6 +16581,28 @@ snapshots: base64-arraybuffer: 1.0.2 mitt: 3.0.1 + '@modelcontextprotocol/sdk@1.27.1(zod@4.1.13)': + dependencies: + '@hono/node-server': 1.19.12(hono@4.12.10) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.3.2(express@5.2.1) + hono: 4.12.10 + jose: 6.2.2 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.1.13 + zod-to-json-schema: 3.25.2(zod@4.1.13) + transitivePeerDependencies: + - supports-color + '@napi-rs/canvas-android-arm64@0.1.88': optional: true @@ -20696,6 +20932,11 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.15.0): dependencies: acorn: 8.15.0 @@ -20747,6 +20988,10 @@ snapshots: optionalDependencies: ajv: 8.17.1 + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + ajv-keywords@5.1.0(ajv@8.17.1): dependencies: ajv: 8.17.1 @@ -21147,6 +21392,20 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.0 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} bowser@2.11.0: {} @@ -21197,8 +21456,7 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bytes@3.1.2: - optional: true + bytes@3.1.2: {} caching-transform@4.0.0: dependencies: @@ -21486,6 +21744,10 @@ snapshots: snake-case: 2.1.0 upper-case: 1.1.3 + content-disposition@1.0.1: {} + + content-type@1.0.5: {} + conventional-changelog-angular@7.0.0: dependencies: compare-func: 2.0.0 @@ -21505,6 +21767,8 @@ snapshots: convert-source-map@2.0.0: {} + cookie-signature@1.2.2: {} + cookie@0.7.2: {} core-js-compat@3.44.0: @@ -21706,6 +21970,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + decamelize@1.2.0: {} decimal.js-light@2.5.1: {} @@ -22462,6 +22730,10 @@ snapshots: eventsource-parser@3.0.6: {} + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + exec-async@2.2.0: optional: true @@ -22660,6 +22932,44 @@ snapshots: exponential-backoff@3.1.2: {} + express-rate-limit@8.3.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.1.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.1 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + exsolve@1.0.7: {} extend@3.0.2: {} @@ -22772,6 +23082,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.1: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + find-cache-dir@3.3.2: dependencies: commondir: 1.0.1 @@ -22830,6 +23151,8 @@ snapshots: forwarded-parse@2.1.2: {} + forwarded@0.2.0: {} + fraction.js@4.3.7: {} framer-motion@12.23.24(react-dom@19.1.0(react@19.1.0))(react@19.1.0): @@ -22855,6 +23178,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + fromentries@1.3.2: {} fs-constants@1.0.0: @@ -23218,6 +23543,8 @@ snapshots: hono@4.10.4: {} + hono@4.12.10: {} + hosted-git-info@7.0.2: dependencies: lru-cache: 10.4.3 @@ -23260,6 +23587,14 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -23310,6 +23645,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -23415,11 +23754,15 @@ snapshots: dependencies: loose-envify: 1.4.0 + ip-address@10.1.0: {} + ip-address@9.0.5: dependencies: jsbn: 1.1.0 sprintf-js: 1.1.3 + ipaddr.js@1.9.1: {} + is-alphabetical@2.0.1: {} is-alphanumerical@2.0.1: @@ -23533,6 +23876,8 @@ snapshots: is-potential-custom-element-name@1.0.1: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.8 @@ -23776,6 +24121,8 @@ snapshots: jose@6.1.0: {} + jose@6.2.2: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -23838,6 +24185,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json-schema@0.4.0: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -24281,6 +24630,8 @@ snapshots: mdn-data@2.0.30: {} + media-typer@1.1.0: {} + memoize-one@5.2.1: {} memoize-one@6.0.0: @@ -24288,6 +24639,8 @@ snapshots: meow@12.1.1: {} + merge-descriptors@2.0.0: {} + merge-options@3.0.4: dependencies: is-plain-obj: 2.1.0 @@ -24689,6 +25042,10 @@ snapshots: dependencies: mime-db: 1.54.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mimic-fn@1.2.0: @@ -25340,6 +25697,8 @@ snapshots: lru-cache: 11.1.0 minipass: 7.1.2 + path-to-regexp@8.4.2: {} + path-type@4.0.0: {} pathe@2.0.3: {} @@ -25424,6 +25783,8 @@ snapshots: pirates@4.0.7: {} + pkce-challenge@5.0.1: {} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 @@ -25626,6 +25987,11 @@ snapshots: property-information@7.1.0: {} + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + proxy-agent@6.5.0: dependencies: agent-base: 7.1.4 @@ -25666,6 +26032,10 @@ snapshots: dependencies: side-channel: 1.1.0 + qs@6.15.0: + dependencies: + side-channel: 1.1.0 + query-string@7.1.3: dependencies: decode-uri-component: 0.2.2 @@ -25751,6 +26121,13 @@ snapshots: range-parser@1.2.1: {} + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -26556,6 +26933,16 @@ snapshots: rou3@0.7.10: {} + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + rrweb-cssom@0.8.0: {} rtl-detect@1.1.2: @@ -26670,6 +27057,22 @@ snapshots: - supports-color optional: true + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + sentence-case@2.1.1: dependencies: no-case: 2.3.2 @@ -26690,6 +27093,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + server-only@0.0.1: optional: true @@ -27012,6 +27424,8 @@ snapshots: statuses@2.0.1: {} + statuses@2.0.2: {} + std-env@3.10.0: {} stdin-discarder@0.2.2: {} @@ -27516,6 +27930,12 @@ snapshots: type-fest@0.8.1: {} + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -28202,6 +28622,10 @@ snapshots: yoctocolors@2.1.1: {} + zod-to-json-schema@3.25.2(zod@4.1.13): + dependencies: + zod: 4.1.13 + zod@3.24.3: {} zod@3.25.76: {}