From d90a9acb637da6ca85204c00b913db00a5c65b9d Mon Sep 17 00:00:00 2001 From: Aaron Trowbridge Date: Thu, 9 Jul 2026 11:49:05 -0400 Subject: [PATCH] =?UTF-8?q?amico-run(#112):=20B5=20=E2=80=94=20real=20MCP?= =?UTF-8?q?=20stdio=20facade=20for=20`amico=20mcp-serve`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Land the OPTIONAL MCP facade (spec §7.3): `amico mcp-serve` now stands up a real @modelcontextprotocol/sdk stdio transport that exposes the spine verbs as MCP tools. One impl, two transports — tools/call dispatches to the SAME verb function (verbs.ts) the CLI uses; the CLI and MCP paths never fork. - add @modelcontextprotocol/sdk@^1.29.0 to packages/amico-run - mcp_serve.ts: createMcpServer() wires list-tools → verb↔tool mapping and call-tool → callMcpTool (the shared verb spine); serve() attaches the stdio transport and shuts down cleanly on client disconnect / stdin EOF - amico.ts: mcp-serve is real (usage + header updated); --list still renders the mapping transport-free - tests: mcp_serve.test.ts — pure mapping, direct dispatch, an in-memory Client↔Server round-trip, and a REAL stdio round-trip against the built bundle; amico.test.ts no-flag test updated to the real (EOF-terminated) server S31 AMENDMENT (governance — needs Jack review): test/s31.test.ts carves the `modelcontextprotocol` ban out for EXACTLY ONE file (src/mcp_serve.ts), mirroring spec C's single-file SolveSpec carve-out. Only the MCP-SDK pattern is lifted, and only for that file — mcp_serve.ts stays under the HTTP/fetch bans (stdio, never network), and every other src file stays under the full ban. Two new assertions pin the carve-out to one file so it cannot silently widen. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/amico-run/package.json | 1 + packages/amico-run/src/amico.ts | 8 +- packages/amico-run/src/mcp_serve.ts | 91 +++- packages/amico-run/test/amico.test.ts | 14 +- packages/amico-run/test/mcp_serve.test.ts | 105 +++++ packages/amico-run/test/s31.test.ts | 42 +- pnpm-lock.yaml | 527 +++++++++++++++++++++- 7 files changed, 747 insertions(+), 41 deletions(-) create mode 100644 packages/amico-run/test/mcp_serve.test.ts diff --git a/packages/amico-run/package.json b/packages/amico-run/package.json index b1b18821..c5894d97 100644 --- a/packages/amico-run/package.json +++ b/packages/amico-run/package.json @@ -20,6 +20,7 @@ }, "dependencies": { "@amicode/schema": "workspace:*", + "@modelcontextprotocol/sdk": "^1.29.0", "smol-toml": "^1.3.0" }, "devDependencies": { diff --git a/packages/amico-run/src/amico.ts b/packages/amico-run/src/amico.ts index e62b159f..2da9e59d 100644 --- a/packages/amico-run/src/amico.ts +++ b/packages/amico-run/src/amico.ts @@ -7,8 +7,10 @@ // B1 SCOPE: `run` / `resolve` / `sandbox` delegate VERBATIM to the existing amico-run launch // path (src/launch.ts): `amico ` is exactly `amico-run `, so // there is no behavior fork and the amico-run test suite still covers the real bodies. The -// spine verbs (catalog/vault/device/note) and `mcp-serve` are STUB seams (see verbs.ts, -// mcp_serve.ts) — routing works today; real bodies land in later spine slices. +// spine verbs (catalog/vault/device/note) are STUB seams (see verbs.ts) — routing works +// today; real bodies land in later spine slices. +// B5 SCOPE (issue #112): `mcp-serve` is now REAL — it stands up an MCP stdio transport that +// exposes the same spine verbs as MCP tools (see mcp_serve.ts). One impl, two transports. import { launch } from "./launch.js"; import { SPINE_VERBS } from "./verbs.js"; import { serve } from "./mcp_serve.js"; @@ -19,7 +21,7 @@ function usage(): string { ["resolve --platform

--kind --size ", "tier resolution → JSON (amico-run subcommand)"], ["sandbox --packages A,B,…", "generate a per-problem Julia env (amico-run subcommand)"], ...SPINE_VERBS.map((v) => [`${v.name} …`, `${v.summary} [stub → ${v.slice}]`] as [string, string]), - ["mcp-serve [--list]", "expose the spine verbs as MCP tools (optional facade) [stub]"], + ["mcp-serve [--list]", "serve the spine verbs as MCP tools over stdio (optional facade; --list = mapping only)"], ["--help, -h", "show this verb surface"], ]; const width = Math.max(...rows.map(([u]) => u.length)); diff --git a/packages/amico-run/src/mcp_serve.ts b/packages/amico-run/src/mcp_serve.ts index f7a5bf02..81693978 100644 --- a/packages/amico-run/src/mcp_serve.ts +++ b/packages/amico-run/src/mcp_serve.ts @@ -3,16 +3,25 @@ // spine verbs as MCP tools makes them callable-by-name with typed discovery in BOTH, // without a second implementation. // -// The mapping is the whole point: each Verb becomes one MCP tool; a tools/call would -// dispatch to the SAME Verb.run the CLI uses. One impl, two transports. +// The mapping is the whole point: each Verb becomes one MCP tool; a tools/call dispatches +// to the SAME Verb.run the CLI uses. One impl, two transports. // -// B1 SCOPE (issue #108): this is a STUB seam. `--list` renders the verb↔tool mapping; the -// real transport (an MCP stdio server) is NOT wired here. Note the deliberate constraint: -// test/s31.test.ts (S31 / spec §4) forbids the MCP server SDK inside the orchestrator src, -// so this slice carries ZERO MCP dependency. Landing the real transport body requires an -// explicit, reviewed S31 amendment in a later slice — exactly as spec C amended the S31 -// SolveSpec ban to name amico-run the launch gate. Either path here exits cleanly (code 0). +// B5 SCOPE (issue #112): this lands the REAL @modelcontextprotocol/sdk stdio transport. +// ⚠️ GOVERNANCE — this is the ONLY file in the orchestrator src/ permitted to reference the +// MCP SDK. test/s31.test.ts (S31 / spec §4) bans `modelcontextprotocol` everywhere in src/; +// B5 amends that ban with a single, named carve-out for THIS file only (see the amendment +// block in s31.test.ts), mirroring spec C's single-file SolveSpec carve-out for amico-run. +// The carve-out lifts ONLY the MCP-SDK pattern here — this file stays subject to the HTTP +// and fetch bans (the transport is stdio, never network), and every other src file stays +// under the full ban. Do NOT import the MCP SDK anywhere else. +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { + CallToolRequestSchema, + ListToolsRequestSchema, + type CallToolResult, +} from "@modelcontextprotocol/sdk/types.js"; import { SPINE_VERBS, type Verb } from "./verbs.js"; interface McpToolDescriptor { @@ -35,30 +44,62 @@ export function listMcpTools(): McpToolDescriptor[] { return SPINE_VERBS.map(verbToMcpTool); } -/** tools/call handler — dispatches to the same Verb.run the CLI uses. */ -export async function callMcpTool(name: string, argv: string[]): Promise { +/** tools/call handler core — dispatches to the SAME Verb.run the CLI uses (one impl, two + * transports) and wraps the verb's JSON result as an MCP text block. A non-zero verb exit + * code surfaces as isError; an unknown tool name is an isError result (not a throw) so the + * MCP client sees a structured tool error rather than a protocol fault. */ +export async function callMcpTool(name: string, argv: string[]): Promise { const verb = SPINE_VERBS.find((v) => `amico_${v.name}` === name); - if (!verb) throw new Error(`unknown tool ${name}`); - const result = await verb.run(argv); - return result.json; + if (!verb) { + return { content: [{ type: "text", text: `amico mcp: unknown tool ${name}` }], isError: true }; + } + const { json, code } = await verb.run(argv); + return { content: [{ type: "text", text: JSON.stringify(json) }], isError: code !== 0 }; +} + +/** Build the MCP server with its two request handlers wired to the shared verb spine: + * list-tools → the verb↔tool mapping; call-tool → the same verb function the CLI dispatches. + * No transport is attached here, so this is unit-testable over an in-memory transport pair; + * serve() attaches the real stdio transport. */ +export function createMcpServer(): Server { + const server = new Server({ name: "amico", version: "0.1.0" }, { capabilities: { tools: {} } }); + server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: listMcpTools() })); + server.setRequestHandler(CallToolRequestSchema, async (req) => { + const argv = (req.params.arguments?.argv as string[] | undefined) ?? []; + return callMcpTool(req.params.name, argv); + }); + return server; } export async function serve(argv: string[]): Promise { if (argv.includes("--list")) { - // Demonstrable path: show the verb↔tool mapping without standing up a transport. + // Transport-free path: render the verb↔tool mapping (used for discovery + tests). console.log(JSON.stringify({ tools: listMcpTools() }, null, 2)); return 0; } - // ── the transport seam (the only net-new code MCP adds over the CLI) — lands in a later - // slice. It stands up an MCP stdio server whose list-tools returns listMcpTools() and - // whose call-tool dispatches to callMcpTool(name, argv). It is intentionally NOT - // imported here so this slice stays free of the MCP SDK (S31; see the file header). ── - console.log( - JSON.stringify({ - stub: true, - note: "B1 seam only — the MCP stdio transport is not wired here (S31 keeps the orchestrator SDK-free); use --list for the verb↔tool mapping", - tools: listMcpTools().map((t) => t.name), - }), - ); + // Real facade: stand up the MCP stdio server. stdout is the MCP JSON-RPC channel now, so + // NOTHING may be written to it here (no console.log) — diagnostics go to stderr. The call + // blocks until the client disconnects, then exits cleanly. + const server = createMcpServer(); + const transport = new StdioServerTransport(); + await server.connect(transport); + await new Promise((resolve) => { + let settled = false; + const finish = () => { + if (settled) return; + settled = true; + resolve(); + }; + // Protocol owns transport.onclose; hook the server's onclose so we don't clobber it — + // fires when the peer closes the session. + server.onclose = finish; + // StdioServerTransport watches stdin `data`/`error` only, NOT EOF — so a client that + // simply disconnects (stdin end) would otherwise hang the process. Close the server on + // stdin end/close so `amico mcp-serve` always exits cleanly (server.close() → onclose → + // finish; also drops the stdin listener so the event loop can drain). + const shutdown = () => void server.close().catch(finish); + process.stdin.once("end", shutdown); + process.stdin.once("close", shutdown); + }); return 0; } diff --git a/packages/amico-run/test/amico.test.ts b/packages/amico-run/test/amico.test.ts index e9f8325a..abd4dbbc 100644 --- a/packages/amico-run/test/amico.test.ts +++ b/packages/amico-run/test/amico.test.ts @@ -156,11 +156,13 @@ describe("amico router — mcp-serve facade", () => { expect.arrayContaining(["amico_catalog", "amico_vault", "amico_device", "amico_note"]), ); }); - it("no flag → stub note + tool list, exit 0 (cleanly)", () => { - const r = run(["mcp-serve"]); - expect(r.code).toBe(0); - const out = JSON.parse(r.stdout); - expect(out.stub).toBe(true); - expect(out.tools).toEqual(expect.arrayContaining(["amico_catalog"])); + it("no flag → stands up the real stdio server, exits 0 on stdin EOF (empty stdin)", () => { + // The real facade (B5) blocks on stdin serving the MCP protocol; feeding an immediate + // EOF (empty input) is a disconnected client → the server shuts down and exits cleanly. + // stdout is the MCP JSON-RPC channel, so with no client messages it stays silent. The + // full protocol round-trip (tools/list + tools/call over real stdio) lives in + // mcp_serve.test.ts. A timeout guards against a regression that would hang the server. + const out = execFileSync("node", [BUNDLE, "mcp-serve"], { encoding: "utf8", input: "", timeout: 20000 }); + expect(out).toBe(""); }); }); diff --git a/packages/amico-run/test/mcp_serve.test.ts b/packages/amico-run/test/mcp_serve.test.ts new file mode 100644 index 00000000..b11016e9 --- /dev/null +++ b/packages/amico-run/test/mcp_serve.test.ts @@ -0,0 +1,105 @@ +// B5 (issue #112): the `amico mcp-serve` MCP facade. These tests prove the two acceptance +// criteria — (1) mcp-serve LISTS the spine verbs as MCP tools, and (2) a tools/call +// DISPATCHES to the SAME verb function the CLI uses (one impl, two transports) — at three +// levels: the pure verb↔tool mapping, an in-memory Client↔Server round-trip over the real +// MCP protocol, and a real stdio round-trip against the built `amico` bundle. +// +// The SDK imports here live in TEST code, not src/ — the S31 grep guard (s31.test.ts) only +// scans src/, where the MCP SDK is carved out to mcp_serve.ts alone. +import { describe, it, expect, beforeAll } from "vitest"; +import { execFileSync } from "node:child_process"; +import { join } from "node:path"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"; +import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; +import { callMcpTool, createMcpServer, listMcpTools, verbToMcpTool } from "../src/mcp_serve.js"; +import { SPINE_VERBS } from "../src/verbs.js"; + +const BUNDLE = join(__dirname, "..", "dist", "amico.js"); +const TOOL_NAMES = ["amico_catalog", "amico_vault", "amico_device", "amico_note"]; + +// The distinctive JSON a verb.run() returns for given args — the fingerprint we assert the +// tool call reproduces, proving the call reached the SAME verb function. +async function verbJson(verbName: string, argv: string[]): Promise { + const verb = SPINE_VERBS.find((v) => v.name === verbName)!; + return (await verb.run(argv)).json; +} +function toolText(res: { content: unknown }): string { + return (res.content as { type: string; text: string }[])[0].text; +} + +describe("verb ↔ MCP-tool mapping (pure)", () => { + it("verbToMcpTool names the tool amico_, carries the summary + argv schema", () => { + const v = SPINE_VERBS.find((x) => x.name === "catalog")!; + expect(verbToMcpTool(v)).toEqual({ + name: "amico_catalog", + description: v.summary, + inputSchema: { type: "object", properties: { argv: { type: "array", items: { type: "string" } } } }, + }); + }); + it("listMcpTools exposes exactly the four spine verbs, one tool each", () => { + const tools = listMcpTools(); + expect(tools.map((t) => t.name).sort()).toEqual([...TOOL_NAMES].sort()); + expect(tools).toHaveLength(SPINE_VERBS.length); + }); +}); + +describe("callMcpTool dispatches to the same verb function (direct)", () => { + it("routes amico_note → the note verb; content text is the verb's own JSON", async () => { + const res = await callMcpTool("amico_note", ["write", "exp-42"]); + expect(res.isError).toBe(false); + expect(JSON.parse(toolText(res))).toEqual(await verbJson("note", ["write", "exp-42"])); + }); + it("unknown tool → structured isError result (not a throw)", async () => { + const res = await callMcpTool("amico_frobnicate", []); + expect(res.isError).toBe(true); + expect(toolText(res)).toMatch(/unknown tool amico_frobnicate/); + }); +}); + +describe("MCP round-trip over an in-memory transport (real Client + Server)", () => { + it("tools/list returns the spine verbs; tools/call reaches the same verb function", async () => { + const server = createMcpServer(); + const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + const client = new Client({ name: "amico-mcp-test", version: "0" }, { capabilities: {} }); + await server.connect(serverTransport); + await client.connect(clientTransport); + + const { tools } = await client.listTools(); + expect(tools.map((t) => t.name).sort()).toEqual([...TOOL_NAMES].sort()); + // description round-trips from the verb summary + const catalogTool = tools.find((t) => t.name === "amico_catalog")!; + expect(catalogTool.description).toBe(SPINE_VERBS.find((v) => v.name === "catalog")!.summary); + + const res = await client.callTool({ name: "amico_device", arguments: { argv: ["status", "--json"] } }); + expect(res.isError).toBeFalsy(); + expect(JSON.parse(toolText(res as { content: unknown }))).toEqual( + await verbJson("device", ["status", "--json"]), + ); + + await client.close(); + }); +}); + +describe("MCP round-trip over the REAL stdio transport (built bundle)", () => { + beforeAll(() => { + execFileSync("node", [join(__dirname, "..", "esbuild.config.mjs")], { cwd: join(__dirname, "..") }); + }); + + it("spawns `amico mcp-serve`, lists tools + dispatches a call over stdio", async () => { + const transport = new StdioClientTransport({ command: "node", args: [BUNDLE, "mcp-serve"] }); + const client = new Client({ name: "amico-mcp-stdio-test", version: "0" }, { capabilities: {} }); + await client.connect(transport); + + const { tools } = await client.listTools(); + expect(tools.map((t) => t.name).sort()).toEqual([...TOOL_NAMES].sort()); + + const res = await client.callTool({ name: "amico_catalog", arguments: { argv: ["lookup", "H-gate"] } }); + expect(res.isError).toBeFalsy(); + expect(JSON.parse(toolText(res as { content: unknown }))).toEqual( + await verbJson("catalog", ["lookup", "H-gate"]), + ); + + await client.close(); // terminates the spawned server + }, 30000); +}); diff --git a/packages/amico-run/test/s31.test.ts b/packages/amico-run/test/s31.test.ts index 89f6a08b..aa3b86a4 100644 --- a/packages/amico-run/test/s31.test.ts +++ b/packages/amico-run/test/s31.test.ts @@ -7,16 +7,54 @@ import { join } from "node:path"; // named SolveSpec launch gate — it validates + gates the spec before spawning // Julia. The physics-flag bans below still hold: --spec is a spec-file path, // NOT a physics knob; all physics stays in the script.) -const FORBIDDEN = [/--gate\b/, /--system\b/, /--pulse\b/, /modelcontextprotocol/i, /node:https?\b/, /\bfetch\s*\(/]; +// +// ───────────────────────────────────────────────────────────────────────────── +// S31 AMENDMENT — B5 / issue #112 (MCP facade). ⚠️ NEEDS JACK GOVERNANCE REVIEW. +// ───────────────────────────────────────────────────────────────────────────── +// B5 lands the real `amico mcp-serve` MCP stdio transport (the OPTIONAL facade that +// exposes the spine verbs as MCP tools — one impl, two transports). That requires the +// `@modelcontextprotocol/sdk` import, which the /modelcontextprotocol/ ban forbids. +// Rather than removing the ban, we carve out EXACTLY ONE file — src/mcp_serve.ts — +// mirroring spec C, which amended the SolveSpec ban with a single named carve-out +// (amico-run = the launch gate) instead of a blanket lift. The carve-out is minimal: +// • it names ONE file (MCP_SDK_ALLOWED), never the whole src/ tree; +// • it lifts ONLY the /modelcontextprotocol/ pattern — mcp_serve.ts is STILL banned +// from HTTP and fetch (the transport is stdio, never network) and from physics flags; +// • every OTHER src file — orchestrator, harness, launch path — stays under the FULL +// ban, MCP included. No orchestrator/harness code may import the MCP SDK. +// The two extra `it(...)` blocks below pin the carve-out so it cannot silently widen. +const MCP_SDK_PATTERN = /modelcontextprotocol/i; +const FORBIDDEN = [/--gate\b/, /--system\b/, /--pulse\b/, MCP_SDK_PATTERN, /node:https?\b/, /\bfetch\s*\(/]; + +// The MCP-SDK ban (/modelcontextprotocol/i) — and ONLY that ban — is lifted for these +// file(s). Keep this set at exactly the facade module. +const MCP_SDK_ALLOWED = new Set(["mcp_serve.ts"]); describe("S31 grep rule", () => { - it("src/ contains no forbidden tool-layer patterns", () => { + it("src/ contains no forbidden tool-layer patterns (MCP-SDK carve-out: mcp_serve.ts only)", () => { const srcDir = join(__dirname, "..", "src"); for (const f of readdirSync(srcDir)) { const text = readFileSync(join(srcDir, f), "utf8"); for (const re of FORBIDDEN) { + // Narrow carve-out: the MCP-facade module may reference the MCP SDK (and ONLY the + // SDK — it stays subject to every other forbidden pattern); every other file stays + // subject to this one too. + if (re === MCP_SDK_PATTERN && MCP_SDK_ALLOWED.has(f)) continue; expect(text, `${f} matches forbidden ${re}`).not.toMatch(re); } } }); + + it("the MCP-SDK carve-out is exactly one file (no scope creep)", () => { + expect([...MCP_SDK_ALLOWED]).toEqual(["mcp_serve.ts"]); + }); + + it("every non-carved-out src file is still MCP-SDK-free", () => { + const srcDir = join(__dirname, "..", "src"); + for (const f of readdirSync(srcDir)) { + if (MCP_SDK_ALLOWED.has(f)) continue; + const text = readFileSync(join(srcDir, f), "utf8"); + expect(text, `${f} must not import the MCP SDK`).not.toMatch(MCP_SDK_PATTERN); + } + }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fb4457a1..fdfdf602 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,6 +13,9 @@ importers: '@amicode/schema': specifier: workspace:* version: link:../schema + '@modelcontextprotocol/sdk': + specifier: ^1.29.0 + version: 1.29.0(zod@4.4.3) smol-toml: specifier: ^1.3.0 version: 1.6.1 @@ -440,9 +443,25 @@ packages: cpu: [x64] os: [win32] + '@hono/node-server@1.19.14': + resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@modelcontextprotocol/sdk@1.29.0': + resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -751,6 +770,10 @@ packages: engines: {node: '>= 20'} hasBin: true + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -813,6 +836,10 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -844,6 +871,10 @@ packages: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -901,6 +932,34 @@ packages: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + 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'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -945,6 +1004,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} @@ -973,9 +1036,16 @@ packages: resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==} engines: {ecmascript: '>= es5', node: '>=4'} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + encoding-sniffer@0.2.1: resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} @@ -1027,9 +1097,24 @@ packages: engines: {node: '>=18'} hasBin: true + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.1.0: + resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -1038,6 +1123,16 @@ packages: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} + express-rate-limit@8.5.2: + resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1055,10 +1150,22 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + form-data@4.0.6: resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} engines: {node: '>= 6'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -1124,6 +1231,10 @@ packages: resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} engines: {node: '>= 0.4'} + hono@4.12.28: + resolution: {integrity: sha512-YwUvVpSF7m1yOblFPrU3Hbo8XhPheBoiyfGuII6z19LnOr6JpDnyyp7LFNrfV56wS8tpvtBFGRISHN02pDdLOA==} + engines: {node: '>=16.9.0'} + hosted-git-info@4.1.0: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} @@ -1135,6 +1246,10 @@ packages: htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + 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'} @@ -1147,6 +1262,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -1164,6 +1283,14 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ip-address@10.2.0: + resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1190,14 +1317,23 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-wsl@3.1.1: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + istextorbinary@9.5.0: resolution: {integrity: sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==} engines: {node: '>=4'} + jose@6.2.3: + resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -1208,6 +1344,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==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -1294,6 +1433,14 @@ packages: mdurl@2.0.0: resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1306,10 +1453,18 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} 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'} @@ -1347,6 +1502,10 @@ packages: napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + node-abi@3.92.0: resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} engines: {node: '>=10'} @@ -1365,10 +1524,18 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -1396,10 +1563,21 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + path-scurry@2.0.2: resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} engines: {node: 18 || 20 || >=22} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + path-type@6.0.0: resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} engines: {node: '>=18'} @@ -1421,6 +1599,10 @@ packages: resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + pluralize@2.0.0: resolution: {integrity: sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==} @@ -1438,6 +1620,10 @@ packages: deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. hasBin: true + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -1452,6 +1638,14 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc-config-loader@4.1.4: resolution: {integrity: sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==} @@ -1484,6 +1678,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -1515,6 +1713,25 @@ packages: engines: {node: '>=10'} hasBin: true + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + side-channel-list@1.0.1: resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} @@ -1571,6 +1788,10 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -1652,6 +1873,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -1666,6 +1891,10 @@ packages: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + typed-rest-client@1.8.11: resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} @@ -1699,6 +1928,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} @@ -1708,6 +1941,10 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + version-range@4.15.0: resolution: {integrity: sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==} engines: {node: '>=4'} @@ -1786,6 +2023,11 @@ packages: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -1833,6 +2075,14 @@ packages: yazl@2.5.1: resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + snapshots: '@azu/format-text@1.0.2': {} @@ -2075,8 +2325,34 @@ snapshots: '@esbuild/win32-x64@0.24.2': optional: true + '@hono/node-server@1.19.14(hono@4.12.28)': + dependencies: + hono: 4.12.28 + '@jridgewell/sourcemap-codec@1.5.5': {} + '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': + dependencies: + '@hono/node-server': 1.19.14(hono@4.12.28) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.0 + express: 5.2.1 + express-rate-limit: 8.5.2(express@5.2.1) + hono: 4.12.28 + jose: 6.2.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -2410,6 +2686,11 @@ snapshots: transitivePeerDependencies: - supports-color + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + agent-base@7.1.4: {} ajv-formats@3.0.1(ajv@8.20.0): @@ -2464,6 +2745,20 @@ snapshots: readable-stream: 3.6.2 optional: true + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.15.2 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + boolbase@1.0.0: {} boundary@2.0.0: {} @@ -2494,6 +2789,8 @@ snapshots: dependencies: run-applescript: 7.1.0 + bytes@3.1.2: {} + cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -2563,6 +2860,27 @@ snapshots: commander@12.1.0: {} + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -2598,6 +2916,8 @@ snapshots: delayed-stream@1.0.0: {} + depd@2.0.0: {} + detect-libc@2.1.2: optional: true @@ -2633,8 +2953,12 @@ snapshots: dependencies: version-range: 4.15.0 + ee-first@1.1.1: {} + emoji-regex@8.0.0: {} + encodeurl@2.0.0: {} + encoding-sniffer@0.2.1: dependencies: iconv-lite: 0.6.3 @@ -2724,15 +3048,63 @@ snapshots: '@esbuild/win32-ia32': 0.24.2 '@esbuild/win32-x64': 0.24.2 + escape-html@1.0.3: {} + estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 + etag@1.8.1: {} + + eventsource-parser@3.1.0: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.0 + expand-template@2.0.3: optional: true expect-type@1.3.0: {} + express-rate-limit@8.5.2(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.2.0 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + 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.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.2 + range-parser: 1.3.0 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -2753,6 +3125,17 @@ snapshots: dependencies: to-regex-range: 5.0.1 + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + form-data@4.0.6: dependencies: asynckit: 0.4.0 @@ -2761,6 +3144,10 @@ snapshots: hasown: 2.0.4 mime-types: 2.1.35 + forwarded@0.2.0: {} + + fresh@2.0.0: {} + fs-constants@1.0.0: optional: true @@ -2844,6 +3231,8 @@ snapshots: dependencies: function-bind: 1.1.2 + hono@4.12.28: {} + hosted-git-info@4.1.0: dependencies: lru-cache: 6.0.0 @@ -2859,6 +3248,14 @@ snapshots: domutils: 3.2.2 entities: 7.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 @@ -2877,6 +3274,10 @@ snapshots: dependencies: safer-buffer: 2.1.2 + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: optional: true @@ -2884,12 +3285,15 @@ snapshots: index-to-position@1.2.0: {} - inherits@2.0.4: - optional: true + inherits@2.0.4: {} ini@1.3.8: optional: true + ip-address@10.2.0: {} + + ipaddr.js@1.9.1: {} + is-docker@3.0.0: {} is-extglob@2.1.1: {} @@ -2906,16 +3310,22 @@ snapshots: is-number@7.0.0: {} + is-promise@4.0.0: {} + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 + isexe@2.0.0: {} + istextorbinary@9.5.0: dependencies: binaryextensions: 6.11.0 editions: 6.22.0 textextensions: 6.11.0 + jose@6.2.3: {} + js-tokens@4.0.0: {} js-yaml@4.2.0: @@ -2924,6 +3334,8 @@ snapshots: json-schema-traverse@1.0.0: {} + json-schema-typed@8.0.2: {} + json5@2.2.3: {} jsonc-parser@3.3.1: {} @@ -3015,6 +3427,10 @@ snapshots: mdurl@2.0.0: {} + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + merge2@1.4.1: {} micromatch@4.0.8: @@ -3024,10 +3440,16 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mimic-response@3.1.0: @@ -3054,6 +3476,8 @@ snapshots: napi-build-utils@2.0.0: optional: true + negotiator@1.0.0: {} + node-abi@3.92.0: dependencies: semver: 7.8.4 @@ -3077,12 +3501,17 @@ snapshots: dependencies: boolbase: 1.0.0 + object-assign@4.1.1: {} + object-inspect@1.13.4: {} + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + once@1.4.0: dependencies: wrappy: 1.0.2 - optional: true open@10.2.0: dependencies: @@ -3116,11 +3545,17 @@ snapshots: dependencies: entities: 6.0.1 + parseurl@1.3.3: {} + + path-key@3.1.1: {} + path-scurry@2.0.2: dependencies: lru-cache: 11.5.1 minipass: 7.1.3 + path-to-regexp@8.4.2: {} + path-type@6.0.0: {} pathe@1.1.2: {} @@ -3133,6 +3568,8 @@ snapshots: picomatch@2.3.2: {} + pkce-challenge@5.0.1: {} + pluralize@2.0.0: {} pluralize@8.0.0: {} @@ -3159,6 +3596,11 @@ snapshots: tunnel-agent: 0.6.0 optional: true + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -3173,6 +3615,15 @@ snapshots: queue-microtask@1.2.3: {} + range-parser@1.3.0: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + rc-config-loader@4.1.4: dependencies: debug: 4.4.3 @@ -3244,6 +3695,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.61.1 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + run-applescript@7.1.0: {} run-parallel@1.2.0: @@ -3272,6 +3733,39 @@ snapshots: semver@7.8.4: {} + 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.3.0 + statuses: 2.0.2 + 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 + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 @@ -3340,6 +3834,8 @@ snapshots: stackback@0.0.2: {} + statuses@2.0.2: {} + std-env@3.10.0: {} string-width@4.2.3: @@ -3429,6 +3925,8 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + tslib@2.8.1: {} tunnel-agent@0.6.0: @@ -3440,6 +3938,12 @@ snapshots: type-fest@4.41.0: {} + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.0 + mime-types: 3.0.2 + typed-rest-client@1.8.11: dependencies: qs: 6.15.2 @@ -3462,6 +3966,8 @@ snapshots: universalify@2.0.1: {} + unpipe@1.0.0: {} + url-join@4.0.1: {} util-deprecate@1.0.2: @@ -3472,6 +3978,8 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 + vary@1.1.2: {} + version-range@4.15.0: {} vite-node@2.1.9(@types/node@22.19.19): @@ -3545,13 +4053,16 @@ snapshots: whatwg-mimetype@4.0.0: {} + which@2.0.2: + dependencies: + isexe: 2.0.0 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - wrappy@1.0.2: - optional: true + wrappy@1.0.2: {} ws@8.21.0: {} @@ -3577,3 +4088,9 @@ snapshots: yazl@2.5.1: dependencies: buffer-crc32: 0.2.13 + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {}