diff --git a/mcp-server/.gitignore b/mcp-server/.gitignore new file mode 100644 index 0000000..0caaefa --- /dev/null +++ b/mcp-server/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +*.js +*.d.ts +*.js.map +*.d.ts.map +!api/ diff --git a/mcp-server/.npmignore b/mcp-server/.npmignore new file mode 100644 index 0000000..3d47613 --- /dev/null +++ b/mcp-server/.npmignore @@ -0,0 +1,4 @@ +.mcpregistry_* +src/ +tsconfig.json +*.ts.new diff --git a/mcp-server/Dockerfile b/mcp-server/Dockerfile new file mode 100644 index 0000000..72ec753 --- /dev/null +++ b/mcp-server/Dockerfile @@ -0,0 +1,29 @@ +FROM node:22-slim AS build +WORKDIR /app + +# Copy full repo (src/ is needed at runtime for the MCP explorer) +COPY . . + +# Build MCP server +WORKDIR /app/mcp-server +RUN npm ci && npm run build + +# --------------------------------------------------------------------------- +FROM node:22-slim +WORKDIR /app + +# Copy built MCP server and source code it explores +COPY --from=build /app/mcp-server/dist /app/mcp-server/dist +COPY --from=build /app/mcp-server/node_modules /app/mcp-server/node_modules +COPY --from=build /app/mcp-server/package.json /app/mcp-server/package.json +COPY --from=build /app/src /app/src +COPY --from=build /app/README.md /app/README.md + +ENV NODE_ENV=production +ENV CLAUDE_CODE_SRC_ROOT=/app/src +ENV PORT=3000 + +EXPOSE 3000 + +WORKDIR /app/mcp-server +CMD ["node", "dist/http.js"] diff --git a/mcp-server/README.md b/mcp-server/README.md new file mode 100644 index 0000000..2d03819 --- /dev/null +++ b/mcp-server/README.md @@ -0,0 +1,279 @@ +# warrioraashuu Codemaster — MCP Server + +A standalone [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that lets any MCP-compatible client explore the Claude Code source code. Rebranded and published by [warrioraashuu](https://www.npmjs.com/~warrioraashuu). Supports **STDIO**, **Streamable HTTP**, and **SSE** transports. + +## What It Does + +Exposes 8 tools, 3 resources, and 5 prompts for navigating the ~1,900-file, 512K+ line Claude Code codebase. This is the official npm package: `warrioraashuu-codemaster`. + +### Transports + +| Transport | Endpoint | Best For | +|-----------|----------|----------| +| **STDIO** | `node dist/index.js` | Claude Desktop, local Claude Code, VS Code | +| **Streamable HTTP** | `POST/GET /mcp` | Modern MCP clients, remote hosting | +| **Legacy SSE** | `GET /sse` + `POST /messages` | Older MCP clients | + +### Tools + +| Tool | Description | +|------|-------------| +| `list_tools` | List all 40+ agent tools (BashTool, FileEditTool, etc.) | +| `list_commands` | List all 50+ slash commands (/commit, /review, etc.) | +| `get_tool_source` | Read a specific tool's implementation | +| `get_command_source` | Read a specific command's implementation | +| `read_source_file` | Read any file from `src/` by relative path | +| `search_source` | Regex search across the entire source tree | +| `list_directory` | List contents of any directory under `src/` | +| `get_architecture` | Get a full architecture overview | + +### Resources + +| URI | Description | +|-----|-------------| +| `claude-code://architecture` | README / architecture overview | +| `claude-code://tools` | Tool registry (JSON) | +| `claude-code://commands` | Command registry (JSON) | +| `claude-code://source/{path}` | Any source file (template) | + +### Prompts + +| Prompt | Description | +|--------|-------------| +| `explain_tool` | Deep-dive explanation of a specific tool's purpose, schema, permissions, and flow | +| `explain_command` | Explanation of a specific slash command's behavior and implementation | +| `architecture_overview` | Guided tour of the full Claude Code architecture | +| `how_does_it_work` | Explain a feature/subsystem (permissions, MCP, bridge, etc.) | +| `compare_tools` | Side-by-side comparison of two tools | + +## Setup + +```bash +cd mcp-server +npm install +npm run build +``` + +### Run Locally (STDIO) + +```bash +npm start +# or with custom source path: +CLAUDE_CODE_SRC_ROOT=/path/to/src npm start +``` + +### Run Locally (HTTP) + +```bash +npm run start:http +# Streamable HTTP at http://localhost:3000/mcp +# Legacy SSE at http://localhost:3000/sse +# Health check at http://localhost:3000/health +``` + +### With Authentication + +```bash +MCP_API_KEY=your-secret-token npm run start:http +# Clients must include: Authorization: Bearer your-secret-token +``` + +## Configuration + +### Claude Desktop + +Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): + +```json +{ + "mcpServers": { + "warrioraashuu-codemaster": { + "command": "node", + "args": ["/absolute/path/to/claude-code/mcp-server/dist/index.js"], + "env": { + "CLAUDE_CODE_SRC_ROOT": "/absolute/path/to/claude-code/src" + } + } + } +} +``` + +### VS Code (GitHub Copilot) + +Add to `.vscode/mcp.json` in your workspace: + +```json +{ + "servers": { + "claude-code-explorer": { + "type": "stdio", + "command": "node", + "args": ["${workspaceFolder}/mcp-server/dist/index.js"], + "env": { + "CLAUDE_CODE_SRC_ROOT": "${workspaceFolder}/src" + } + } + } +} +``` + +### Cursor + +Add to `~/.cursor/mcp.json`: + +```json +{ + "mcpServers": { + "claude-code-explorer": { + "command": "node", + "args": ["/absolute/path/to/claude-code/mcp-server/dist/index.js"], + "env": { + "CLAUDE_CODE_SRC_ROOT": "/absolute/path/to/claude-code/src" + } + } + } +} +``` + +## Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `CLAUDE_CODE_SRC_ROOT` | `../src` (relative to dist/) | Path to the Claude Code `src/` directory | +| `PORT` | `3000` | HTTP server port (HTTP mode only) | +| `MCP_API_KEY` | _(none)_ | Bearer token for HTTP auth (optional) | + +## Remote HTTP Client Configuration + +For Claude Desktop connecting to a remote server: + +```json +{ + "mcpServers": { + "claude-code-explorer": { + "url": "https://your-deployment.railway.app/mcp", + "headers": { + "Authorization": "Bearer your-secret-key" + } + } + } +} +``` + +## Deployment + +### Railway + +1. Connect your GitHub repo to [Railway](https://railway.app) +2. Railway automatically detects the `mcp-server/Dockerfile` +3. Set environment variables in the Railway dashboard: + - `MCP_API_KEY` — a secret bearer token + - `PORT` is set automatically by Railway +4. Deploy — available at `your-app.railway.app` + +Or via CLI: + +```bash +railway init +railway up +``` + +### Vercel + +```bash +npx vercel +``` + +Set environment variables in the Vercel dashboard: +- `CLAUDE_CODE_SRC_ROOT` — path where src/ files are bundled +- `MCP_API_KEY` — bearer token + +> **Note**: Vercel functions are stateless with execution time limits (10s hobby / 60s pro). Best for simple tool calls. For persistent SSE streams, use Railway or Docker. + +### Docker + +```bash +# From repo root +docker build -f mcp-server/Dockerfile -t claude-code-mcp . +docker run -p 3000:3000 -e MCP_API_KEY=your-secret claude-code-mcp +``` + +Works on any Docker host: Fly.io, Render, AWS ECS, Google Cloud Run, etc. + +## Prompts + +The server also exposes prompt templates for guided exploration: + +| Prompt | Description | +|--------|-------------| +| `explain_tool` | Deep-dive explanation of a specific tool (input schema, permissions, execution flow) | +| `explain_command` | Explain how a slash command works | +| `architecture_overview` | Guided tour of the entire Claude Code architecture | +| `how_does_it_work` | Explain a feature or subsystem (e.g. "permission system", "MCP client", "query engine") | +| `compare_tools` | Side-by-side comparison of two tools | + +## Example Usage + +Once connected, you can ask your AI assistant things like: + +- "List all Claude Code tools" +- "Show me the BashTool implementation" +- "Search for how permissions are checked" +- "What files are in the bridge directory?" +- "Read the QueryEngine.ts file, lines 1-100" +- "How does the MCP client connection work?" +- Use the `explain_tool` prompt with "FileEditTool" to get a full breakdown +- Use `how_does_it_work` with "bridge" to understand IDE integration + +## Publishing to MCP Registry + +This server is published to the [MCP Registry](https://registry.modelcontextprotocol.io) via GitHub Actions. On a tagged release (`v*`), the workflow: + +1. Publishes the npm package to npmjs.org +2. Authenticates with the MCP Registry using GitHub OIDC +3. Publishes the `server.json` metadata to the registry + +To publish manually: + +```bash +# Install the MCP Publisher CLI +curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher + +# Authenticate (GitHub OAuth) +./mcp-publisher login github + +# Publish +cd mcp-server +../mcp-publisher publish +``` + +Registry name: `io.github.codeaashu/claude-code-explorer-mcp` + +## Development + +```bash +npm install +npm run dev # Watch mode TypeScript compilation +npm run build # Compile TypeScript to dist/ +npm start # Run STDIO server +npm run start:http # Run HTTP server +``` + +## Architecture + +``` +mcp-server/ +├── src/ +│ ├── server.ts — Shared MCP server (tools, resources, prompts) — transport-agnostic +│ ├── index.ts — STDIO entrypoint (local) +│ └── http.ts — HTTP + SSE entrypoint (remote) +├── api/ +│ ├── index.ts — Vercel serverless function +│ └── vercelApp.ts — Express app for Vercel +├── Dockerfile — Docker build (Railway, Fly.io, etc.) +├── railway.json — Railway deployment config +├── package.json +└── tsconfig.json +``` + + diff --git a/mcp-server/api/index.ts b/mcp-server/api/index.ts new file mode 100644 index 0000000..6903bcd --- /dev/null +++ b/mcp-server/api/index.ts @@ -0,0 +1,21 @@ +/** + * Vercel serverless function — proxies requests to the Express HTTP server. + * + * This file re-exports the Express app as a Vercel serverless handler. + * Vercel automatically routes /api/* to this function. + * + * Deploy: + * cd mcp-server && npx vercel + * + * Environment variables (set in Vercel dashboard): + * CLAUDE_CODE_SRC_ROOT — absolute path where src/ is deployed + * MCP_API_KEY — optional bearer token for auth + * + * NOTE: Vercel serverless functions are stateless, so the Streamable HTTP + * transport (which requires sessions) won't persist across invocations. + * For production use with session-based MCP clients, prefer Railway/Render/VPS. + * The legacy SSE transport and stateless tool calls work fine on Vercel. + */ + +export { app as default } from "./vercelApp.js"; + diff --git a/mcp-server/api/vercelApp.ts b/mcp-server/api/vercelApp.ts new file mode 100644 index 0000000..0a46234 --- /dev/null +++ b/mcp-server/api/vercelApp.ts @@ -0,0 +1,96 @@ +/** + * Express app exported for Vercel serverless. + * Shares the same logic as http.ts but is importable as a module. + */ + +import express from "express"; +import { randomUUID } from "node:crypto"; +import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; +import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; +import { createServer, SRC_ROOT } from "../src/server.js"; + +const API_KEY = process.env.MCP_API_KEY; + +export const app = express(); +app.use(express.json()); + +// Auth +app.use((req, res, next) => { + if (!API_KEY || req.path === "/health" || req.path === "/api") return next(); + const auth = req.headers.authorization; + if (!auth || auth !== `Bearer ${API_KEY}`) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + next(); +}); + +// Health +app.get("/health", (_req, res) => { + res.json({ status: "ok", server: "claude-code-explorer", version: "1.1.0", srcRoot: SRC_ROOT }); +}); +app.get("/api", (_req, res) => { + res.json({ status: "ok", server: "claude-code-explorer", version: "1.1.0", srcRoot: SRC_ROOT }); +}); + +// Streamable HTTP +const transports = new Map(); + +app.post("/mcp", async (req, res) => { + const sessionId = (req.headers["mcp-session-id"] as string) ?? undefined; + let transport = sessionId ? transports.get(sessionId) : undefined; + + if (!transport) { + const server = createServer(); + transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() }); + await server.connect(transport); + transport.onclose = () => { + if (transport!.sessionId) transports.delete(transport!.sessionId); + }; + } + + await transport.handleRequest(req, res, req.body); + + if (transport.sessionId && !transports.has(transport.sessionId)) { + transports.set(transport.sessionId, transport); + } +}); + +app.get("/mcp", async (req, res) => { + const sessionId = req.headers["mcp-session-id"] as string | undefined; + if (!sessionId || !transports.has(sessionId)) { + res.status(400).json({ error: "Invalid or missing session ID" }); + return; + } + await transports.get(sessionId)!.handleRequest(req, res); +}); + +app.delete("/mcp", async (req, res) => { + const sessionId = req.headers["mcp-session-id"] as string | undefined; + if (sessionId && transports.has(sessionId)) { + await transports.get(sessionId)!.close(); + transports.delete(sessionId); + } + res.status(200).json({ ok: true }); +}); + +// Legacy SSE +const sseTransports = new Map(); + +app.get("/sse", async (_req, res) => { + const server = createServer(); + const transport = new SSEServerTransport("/messages", res); + sseTransports.set(transport.sessionId, transport); + transport.onclose = () => sseTransports.delete(transport.sessionId); + await server.connect(transport); +}); + +app.post("/messages", async (req, res) => { + const sessionId = req.query.sessionId as string; + const transport = sseTransports.get(sessionId); + if (!transport) { + res.status(400).json({ error: "Unknown session" }); + return; + } + await transport.handlePostMessage(req, res, req.body); +}); diff --git a/mcp-server/package-lock.json b/mcp-server/package-lock.json new file mode 100644 index 0000000..13a95fd --- /dev/null +++ b/mcp-server/package-lock.json @@ -0,0 +1,2183 @@ +{ + "name": "warrioraashuu-codemaster", + "version": "1.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "warrioraashuu-codemaster", + "version": "1.1.0", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.12.1", + "express": "^4.21.0" + }, + "bin": { + "warrioraashuu-codemaster": "dist/index.js" + }, + "devDependencies": { + "@types/express": "^5.0.0", + "@types/node": "^22.0.0", + "tsx": "^4.19.0", + "typescript": "^5.7.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@hono/node-server": { + "version": "1.19.12", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.12.tgz", + "integrity": "sha512-txsUW4SQ1iilgE0l9/e9VQWmELXifEFvmdA1j6WFh/aFPj99hIntrSsq/if0UWyGVkmrRPKA1wCeP+UCr1B9Uw==", + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "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.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/@modelcontextprotocol/sdk/node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz", + "integrity": "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "license": "MIT", + "peer": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.14.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.2.tgz", + "integrity": "sha512-77VmFeJkO0/rvimEDuUC5H30oqUC4EyOhyGccfqoLebB0oiEYfM7nwPrsDsBL1gsTpwfzX8SFy2MT3TDyRq+bg==", + "license": "MIT", + "dependencies": { + "ip-address": "10.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.7", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.7.tgz", + "integrity": "sha512-7tN6rFgBlMgpBML5j8typ92BKFi2sFQvIdpAqLA2beia5avZDrMs0FLZiM5etShWq5irVyGcGMEA1jcDaK7A/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.12.9", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.9.tgz", + "integrity": "sha512-wy3T8Zm2bsEvxKZM5w21VdHDDcwVS1yUFFY6i8UobSsKfFceT7TOwhbhfKsDyx7tYQlmRM5FLpIuYvNFyjctiA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz", + "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "license": "BSD-2-Clause" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/router/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/router/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/router/node_modules/path-to-regexp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.1.tgz", + "integrity": "sha512-fvU78fIjZ+SBM9YwCknCvKOUKkLVqtWDVctl0s7xIqfmfb38t2TT4ZU2gHm+Z8xGwgW+QWEU3oQSAzIbo89Ggw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + } + } +} diff --git a/mcp-server/package.json b/mcp-server/package.json new file mode 100644 index 0000000..5a580b8 --- /dev/null +++ b/mcp-server/package.json @@ -0,0 +1,38 @@ +{ + "name": "warrioraashuu-codemaster", + "version": "1.1.0", + "mcpName": "io.github.warrioraashuu/warrioraashuu-codemaster", + "description": "MCP server for exploring the Claude Code source code — rebranded and published by warrioraashuu. STDIO, HTTP, and SSE transports.", + "repository": { + "type": "git", + "url": "https://github.com/codeaashu/claude-code.git" + }, + "author": "warrioraashuu ", + "homepage": "https://github.com/codeaashu/claude-code#readme", + "bugs": { + "url": "https://github.com/codeaashu/claude-code/issues" + }, + "type": "module", + "main": "dist/index.js", + "bin": { + "warrioraashuu-codemaster": "dist/index.js" + }, + "scripts": { + "build": "tsc", + "start": "node dist/index.js", + "start:http": "node dist/http.js", + "dev": "npx tsx src/index.ts" + }, + "dependencies": { + "@modelcontextprotocol/sdk": "^1.12.1", + "express": "^4.21.0" + }, + "devDependencies": { + "@types/express": "^5.0.0", + "@types/node": "^22.0.0", + "tsx": "^4.19.0", + "typescript": "^5.7.0" + } +} + + diff --git a/mcp-server/railway.json b/mcp-server/railway.json new file mode 100644 index 0000000..b153f64 --- /dev/null +++ b/mcp-server/railway.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://railway.com/railway.schema.json", + "build": { + "builder": "DOCKERFILE", + "dockerfilePath": "mcp-server/Dockerfile" + }, + "deploy": { + "startCommand": "node dist/http.js", + "healthcheckPath": "/health", + "restartPolicyType": "ON_FAILURE", + "restartPolicyMaxRetries": 3 + } +} diff --git a/mcp-server/server.json b/mcp-server/server.json new file mode 100644 index 0000000..fdb5872 --- /dev/null +++ b/mcp-server/server.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", + "name": "io.github.codeaashu/claude-code-explorer-mcp", + "title": "Claude Code Explorer MCP", + "description": "Explore the Claude Code CLI source — browse tools, commands, search code, and more.", + "repository": { + "url": "https://github.com/codeaashu/claude-code", + "source": "github", + "subfolder": "mcp-server" + }, + "version": "1.1.0", + "packages": [ + { + "registryType": "npm", + "registryBaseUrl": "https://registry.npmjs.org", + "identifier": "claude-code-explorer-mcp", + "version": "1.1.0", + "transport": { + "type": "stdio" + }, + "runtimeHint": "node" + } + ] +} diff --git a/mcp-server/src/http.ts b/mcp-server/src/http.ts new file mode 100644 index 0000000..e5c67d9 --- /dev/null +++ b/mcp-server/src/http.ts @@ -0,0 +1,172 @@ +#!/usr/bin/env node +/** + * HTTP + SSE entrypoint — for remote hosting (Railway, Render, VPS, etc.) + * + * Supports: + * - Streamable HTTP transport (POST /mcp for JSON-RPC, GET /mcp for SSE) + * - Health check at GET /health + * + * Environment: + * PORT — HTTP port (default: 3000) + * CLAUDE_CODE_SRC_ROOT — Path to Claude Code src/ directory + * MCP_API_KEY — Optional bearer token for authentication + */ + +import express from "express"; +import { randomUUID } from "node:crypto"; +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; +import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; +import { createServer, validateSrcRoot, SRC_ROOT } from "./server.js"; + +const PORT = parseInt(process.env.PORT ?? "3000", 10); +const API_KEY = process.env.MCP_API_KEY; + +// --------------------------------------------------------------------------- +// Auth middleware (optional — only active when MCP_API_KEY is set) +// --------------------------------------------------------------------------- + +function authMiddleware( + req: express.Request, + res: express.Response, + next: express.NextFunction +): void { + if (!API_KEY) return next(); + // Skip auth for health check + if (req.path === "/health") return next(); + + const auth = req.headers.authorization; + if (!auth || auth !== `Bearer ${API_KEY}`) { + res.status(401).json({ error: "Unauthorized" }); + return; + } + next(); +} + +// --------------------------------------------------------------------------- +// Streamable HTTP transport (modern MCP protocol) +// --------------------------------------------------------------------------- + +async function startStreamableHTTP(app: express.Express): Promise { + // Map of session ID -> transport + const transports = new Map(); + + app.post("/mcp", async (req, res) => { + const sessionId = + (req.headers["mcp-session-id"] as string) ?? undefined; + let transport = sessionId ? transports.get(sessionId) : undefined; + + if (!transport) { + // New session + const server = createServer(); + transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: () => randomUUID(), + }); + await server.connect(transport); + + // Store session after first request so we can retrieve it later + transport.onclose = () => { + if (transport!.sessionId) { + transports.delete(transport!.sessionId); + } + }; + } + + await transport.handleRequest(req, res, req.body); + + // After handling, store with the now-known session ID + if (transport.sessionId && !transports.has(transport.sessionId)) { + transports.set(transport.sessionId, transport); + } + }); + + // SSE stream endpoint for Streamable HTTP + app.get("/mcp", async (req, res) => { + const sessionId = req.headers["mcp-session-id"] as string | undefined; + if (!sessionId || !transports.has(sessionId)) { + res.status(400).json({ error: "Invalid or missing session ID" }); + return; + } + const transport = transports.get(sessionId)!; + await transport.handleRequest(req, res); + }); + + // DELETE — session cleanup + app.delete("/mcp", async (req, res) => { + const sessionId = req.headers["mcp-session-id"] as string | undefined; + if (sessionId && transports.has(sessionId)) { + const transport = transports.get(sessionId)!; + await transport.close(); + transports.delete(sessionId); + } + res.status(200).json({ ok: true }); + }); +} + +// --------------------------------------------------------------------------- +// Legacy SSE transport (for older clients) +// --------------------------------------------------------------------------- + +async function startLegacySSE(app: express.Express): Promise { + const transports = new Map(); + + app.get("/sse", async (_req, res) => { + const server = createServer(); + const transport = new SSEServerTransport("/messages", res); + transports.set(transport.sessionId, transport); + transport.onclose = () => { + transports.delete(transport.sessionId); + }; + await server.connect(transport); + }); + + app.post("/messages", async (req, res) => { + const sessionId = req.query.sessionId as string; + const transport = transports.get(sessionId); + if (!transport) { + res.status(400).json({ error: "Unknown session" }); + return; + } + await transport.handlePostMessage(req, res, req.body); + }); +} + +// --------------------------------------------------------------------------- +// Main +// --------------------------------------------------------------------------- + +async function main(): Promise { + await validateSrcRoot(); + + const app = express(); + app.use(express.json()); + app.use(authMiddleware); + + // Health check + app.get("/health", (_req, res) => { + res.json({ + status: "ok", + server: "claude-code-explorer", + version: "1.1.0", + srcRoot: SRC_ROOT, + }); + }); + + // Register both transports + await startStreamableHTTP(app); + await startLegacySSE(app); + + app.listen(PORT, () => { + console.log(`Claude Code Explorer MCP (HTTP) listening on port ${PORT}`); + console.log(` Streamable HTTP: POST/GET http://localhost:${PORT}/mcp`); + console.log(` Legacy SSE: GET http://localhost:${PORT}/sse`); + console.log(` Health: GET http://localhost:${PORT}/health`); + console.log(` Source root: ${SRC_ROOT}`); + if (API_KEY) console.log(" Auth: Bearer token required"); + }); +} + +main().catch((err) => { + console.error("Fatal error:", err); + process.exit(1); +}); diff --git a/mcp-server/src/index.ts b/mcp-server/src/index.ts new file mode 100644 index 0000000..b49f61c --- /dev/null +++ b/mcp-server/src/index.ts @@ -0,0 +1,24 @@ +#!/usr/bin/env node +/** + * STDIO entrypoint — for local use with Claude Desktop, Claude Code, etc. + * + * Usage: + * node dist/index.js + * CLAUDE_CODE_SRC_ROOT=/path/to/src node dist/index.js + */ + +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { createServer, validateSrcRoot, SRC_ROOT } from "./server.js"; + +async function main() { + await validateSrcRoot(); + const server = createServer(); + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error(`Claude Code Explorer MCP (stdio) started — src: ${SRC_ROOT}`); +} + +main().catch((err) => { + console.error("Fatal error:", err); + process.exit(1); +}); diff --git a/mcp-server/src/index.ts.new b/mcp-server/src/index.ts.new new file mode 100644 index 0000000..b49f61c --- /dev/null +++ b/mcp-server/src/index.ts.new @@ -0,0 +1,24 @@ +#!/usr/bin/env node +/** + * STDIO entrypoint — for local use with Claude Desktop, Claude Code, etc. + * + * Usage: + * node dist/index.js + * CLAUDE_CODE_SRC_ROOT=/path/to/src node dist/index.js + */ + +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { createServer, validateSrcRoot, SRC_ROOT } from "./server.js"; + +async function main() { + await validateSrcRoot(); + const server = createServer(); + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error(`Claude Code Explorer MCP (stdio) started — src: ${SRC_ROOT}`); +} + +main().catch((err) => { + console.error("Fatal error:", err); + process.exit(1); +}); diff --git a/mcp-server/src/server.ts b/mcp-server/src/server.ts new file mode 100644 index 0000000..3c43002 --- /dev/null +++ b/mcp-server/src/server.ts @@ -0,0 +1,958 @@ +/** + * Shared MCP server definition — transport-agnostic. + * + * Exposes tools and resources for exploring the Claude Code source code. + * This module is imported by both the STDIO and HTTP entrypoints. + */ + +import { Server } from "@modelcontextprotocol/sdk/server/index.js"; +import { + CallToolRequestSchema, + ListToolsRequestSchema, + ListResourcesRequestSchema, + ReadResourceRequestSchema, + ListResourceTemplatesRequestSchema, + ListPromptsRequestSchema, + GetPromptRequestSchema, +} from "@modelcontextprotocol/sdk/types.js"; +import * as fs from "node:fs/promises"; +import * as path from "node:path"; +import { fileURLToPath } from "node:url"; + +// --------------------------------------------------------------------------- +// Configuration +// --------------------------------------------------------------------------- + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export const SRC_ROOT = path.resolve( + process.env.CLAUDE_CODE_SRC_ROOT ?? path.join(__dirname, "..", "..", "src") +); + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +async function dirExists(p: string): Promise { + try { + return (await fs.stat(p)).isDirectory(); + } catch { + return false; + } +} + +async function fileExists(p: string): Promise { + try { + return (await fs.stat(p)).isFile(); + } catch { + return false; + } +} + +async function listDir(dir: string): Promise { + try { + const entries = await fs.readdir(dir, { withFileTypes: true }); + return entries + .map((e) => (e.isDirectory() ? e.name + "/" : e.name)) + .sort(); + } catch { + return []; + } +} + +async function walkFiles(root: string, rel = ""): Promise { + const results: string[] = []; + let entries; + try { + entries = await fs.readdir(path.join(root, rel), { withFileTypes: true }); + } catch { + return results; + } + for (const e of entries) { + const child = rel ? `${rel}/${e.name}` : e.name; + if (e.isDirectory()) { + results.push(...(await walkFiles(root, child))); + } else { + results.push(child); + } + } + return results; +} + +/** Safely resolve a user-supplied relative path under SRC_ROOT (blocks path traversal). */ +function safePath(relPath: string): string | null { + const resolved = path.resolve(SRC_ROOT, relPath); + if (!resolved.startsWith(SRC_ROOT)) return null; + return resolved; +} + +// --------------------------------------------------------------------------- +// Metadata Types +// --------------------------------------------------------------------------- + +interface ToolInfo { + name: string; + directory: string; + files: string[]; +} + +interface CommandInfo { + name: string; + path: string; + isDirectory: boolean; + files?: string[]; +} + +async function getToolList(): Promise { + const toolsDir = path.join(SRC_ROOT, "tools"); + const entries = await fs.readdir(toolsDir, { withFileTypes: true }); + const tools: ToolInfo[] = []; + for (const e of entries) { + if (!e.isDirectory() || e.name === "shared" || e.name === "testing") + continue; + const files = await listDir(path.join(toolsDir, e.name)); + tools.push({ name: e.name, directory: `tools/${e.name}`, files }); + } + return tools.sort((a, b) => a.name.localeCompare(b.name)); +} + +async function getCommandList(): Promise { + const cmdsDir = path.join(SRC_ROOT, "commands"); + const entries = await fs.readdir(cmdsDir, { withFileTypes: true }); + const commands: CommandInfo[] = []; + for (const e of entries) { + if (e.isDirectory()) { + const files = await listDir(path.join(cmdsDir, e.name)); + commands.push({ + name: e.name, + path: `commands/${e.name}`, + isDirectory: true, + files, + }); + } else { + commands.push({ + name: e.name.replace(/\.(ts|tsx)$/, ""), + path: `commands/${e.name}`, + isDirectory: false, + }); + } + } + return commands.sort((a, b) => a.name.localeCompare(b.name)); +} + +// --------------------------------------------------------------------------- +// Server Factory +// --------------------------------------------------------------------------- + +export function createServer(): Server { + const server = new Server( + { name: "claude-code-explorer", version: "1.1.0" }, + { + capabilities: { + tools: {}, + resources: {}, + prompts: {}, + }, + } + ); + + // ---- Resources --------------------------------------------------------- + + server.setRequestHandler(ListResourcesRequestSchema, async () => ({ + resources: [ + { + uri: "claude-code://architecture", + name: "Architecture Overview", + description: + "High-level overview of the Claude Code source architecture", + mimeType: "text/markdown", + }, + { + uri: "claude-code://tools", + name: "Tool Registry", + description: "List of all agent tools with their files", + mimeType: "application/json", + }, + { + uri: "claude-code://commands", + name: "Command Registry", + description: "List of all slash commands", + mimeType: "application/json", + }, + ], + })); + + server.setRequestHandler( + ListResourceTemplatesRequestSchema, + async () => ({ + resourceTemplates: [ + { + uriTemplate: "claude-code://source/{path}", + name: "Source file", + description: + "Read a source file from the Claude Code src/ directory", + mimeType: "text/plain", + }, + ], + }) + ); + + server.setRequestHandler( + ReadResourceRequestSchema, + async (request: { params: { uri: string } }) => { + const { uri } = request.params; + + if (uri === "claude-code://architecture") { + const readmePath = path.resolve(SRC_ROOT, "..", "README.md"); + let text: string; + try { + text = await fs.readFile(readmePath, "utf-8"); + } catch { + text = "README.md not found."; + } + return { contents: [{ uri, mimeType: "text/markdown", text }] }; + } + + if (uri === "claude-code://tools") { + const tools = await getToolList(); + return { + contents: [ + { + uri, + mimeType: "application/json", + text: JSON.stringify(tools, null, 2), + }, + ], + }; + } + + if (uri === "claude-code://commands") { + const commands = await getCommandList(); + return { + contents: [ + { + uri, + mimeType: "application/json", + text: JSON.stringify(commands, null, 2), + }, + ], + }; + } + + if (uri.startsWith("claude-code://source/")) { + const relPath = uri.slice("claude-code://source/".length); + const abs = safePath(relPath); + if (!abs) throw new Error("Invalid path"); + const text = await fs.readFile(abs, "utf-8"); + return { contents: [{ uri, mimeType: "text/plain", text }] }; + } + + throw new Error(`Unknown resource: ${uri}`); + } + ); + + // ---- Tools ------------------------------------------------------------- + + server.setRequestHandler(ListToolsRequestSchema, async () => ({ + tools: [ + { + name: "list_tools", + description: + "List all Claude Code agent tools (BashTool, FileReadTool, etc.) with their source files.", + inputSchema: { type: "object" as const, properties: {} }, + }, + { + name: "list_commands", + description: + "List all Claude Code slash commands (/commit, /review, /mcp, etc.) with their source files.", + inputSchema: { type: "object" as const, properties: {} }, + }, + { + name: "get_tool_source", + description: + "Read the full source code of a specific Claude Code tool implementation.", + inputSchema: { + type: "object" as const, + properties: { + toolName: { + type: "string", + description: "Tool directory name, e.g. 'BashTool'", + }, + fileName: { + type: "string", + description: + "Specific file within the tool directory. Omit for the main file.", + }, + }, + required: ["toolName"], + }, + }, + { + name: "get_command_source", + description: + "Read the source code of a specific Claude Code slash command.", + inputSchema: { + type: "object" as const, + properties: { + commandName: { + type: "string", + description: "Command name, e.g. 'commit', 'review'", + }, + fileName: { + type: "string", + description: "Specific file within the command directory.", + }, + }, + required: ["commandName"], + }, + }, + { + name: "read_source_file", + description: + "Read any source file from the Claude Code src/ directory by relative path.", + inputSchema: { + type: "object" as const, + properties: { + path: { + type: "string", + description: "Relative path from src/, e.g. 'QueryEngine.ts'", + }, + startLine: { + type: "number", + description: "1-based start line.", + }, + endLine: { + type: "number", + description: "1-based end line.", + }, + }, + required: ["path"], + }, + }, + { + name: "search_source", + description: + "Search for a regex pattern across the Claude Code source. Returns matching lines with paths and line numbers.", + inputSchema: { + type: "object" as const, + properties: { + pattern: { + type: "string", + description: "Search pattern (regex).", + }, + filePattern: { + type: "string", + description: "File extension filter, e.g. '.ts'", + }, + maxResults: { + type: "number", + description: "Max matches (default: 50).", + }, + }, + required: ["pattern"], + }, + }, + { + name: "list_directory", + description: "List files and subdirectories under src/.", + inputSchema: { + type: "object" as const, + properties: { + path: { + type: "string", + description: "Relative path from src/, e.g. 'services'. '' for root.", + }, + }, + required: ["path"], + }, + }, + { + name: "get_architecture", + description: + "Get a high-level architecture overview of Claude Code.", + inputSchema: { type: "object" as const, properties: {} }, + }, + ], + })); + + server.setRequestHandler( + CallToolRequestSchema, + async (request: { + params: { name: string; arguments?: Record }; + }) => { + const { name, arguments: args } = request.params; + + switch (name) { + case "list_tools": { + const tools = await getToolList(); + return { + content: [ + { type: "text" as const, text: JSON.stringify(tools, null, 2) }, + ], + }; + } + + case "list_commands": { + const commands = await getCommandList(); + return { + content: [ + { + type: "text" as const, + text: JSON.stringify(commands, null, 2), + }, + ], + }; + } + + case "get_tool_source": { + const toolName = (args as Record) + ?.toolName as string; + if (!toolName) throw new Error("toolName is required"); + const toolDir = safePath(`tools/${toolName}`); + if (!toolDir || !(await dirExists(toolDir))) + throw new Error(`Tool not found: ${toolName}`); + + let fileName = (args as Record)?.fileName as + | string + | undefined; + if (!fileName) { + const files = await listDir(toolDir); + const main = + files.find( + (f) => f === `${toolName}.ts` || f === `${toolName}.tsx` + ) ?? + files.find((f) => f.endsWith(".ts") || f.endsWith(".tsx")); + if (!main) throw new Error(`No source files in ${toolName}`); + fileName = main; + } + + const filePath = safePath(`tools/${toolName}/${fileName}`); + if (!filePath || !(await fileExists(filePath))) + throw new Error(`File not found: tools/${toolName}/${fileName}`); + const content = await fs.readFile(filePath, "utf-8"); + return { + content: [ + { + type: "text" as const, + text: `// tools/${toolName}/${fileName}\n// ${content.split("\n").length} lines\n\n${content}`, + }, + ], + }; + } + + case "get_command_source": { + const commandName = (args as Record) + ?.commandName as string; + if (!commandName) throw new Error("commandName is required"); + + const candidates = [ + `commands/${commandName}`, + `commands/${commandName}.ts`, + `commands/${commandName}.tsx`, + ]; + let found: string | null = null; + let isDir = false; + for (const c of candidates) { + const abs = safePath(c); + if (abs && (await dirExists(abs))) { + found = abs; + isDir = true; + break; + } + if (abs && (await fileExists(abs))) { + found = abs; + break; + } + } + if (!found) throw new Error(`Command not found: ${commandName}`); + + if (!isDir) { + const content = await fs.readFile(found, "utf-8"); + return { content: [{ type: "text" as const, text: content }] }; + } + + const reqFile = (args as Record)?.fileName as + | string + | undefined; + if (reqFile) { + const filePath = safePath(`commands/${commandName}/${reqFile}`); + if (!filePath || !(await fileExists(filePath))) + throw new Error( + `File not found: commands/${commandName}/${reqFile}` + ); + const content = await fs.readFile(filePath, "utf-8"); + return { content: [{ type: "text" as const, text: content }] }; + } + + const files = await listDir(found); + return { + content: [ + { + type: "text" as const, + text: `Command: ${commandName}\nFiles:\n${files.map((f) => ` ${f}`).join("\n")}`, + }, + ], + }; + } + + case "read_source_file": { + const relPath = (args as Record)?.path as string; + if (!relPath) throw new Error("path is required"); + const abs = safePath(relPath); + if (!abs || !(await fileExists(abs))) + throw new Error(`File not found: ${relPath}`); + const content = await fs.readFile(abs, "utf-8"); + const lines = content.split("\n"); + const start = + ((args as Record)?.startLine as number) ?? 1; + const end = + ((args as Record)?.endLine as number) ?? + lines.length; + const slice = lines.slice( + Math.max(0, start - 1), + Math.min(lines.length, end) + ); + return { + content: [ + { + type: "text" as const, + text: slice + .map( + (l: string, i: number) => + `${(start + i).toString().padStart(5)} | ${l}` + ) + .join("\n"), + }, + ], + }; + } + + case "search_source": { + const pattern = (args as Record) + ?.pattern as string; + if (!pattern) throw new Error("pattern is required"); + const filePattern = (args as Record) + ?.filePattern as string | undefined; + const maxResults = + ((args as Record)?.maxResults as number) ?? 50; + + let regex: RegExp; + try { + regex = new RegExp(pattern, "i"); + } catch { + throw new Error(`Invalid regex pattern: ${pattern}`); + } + + const allFiles = await walkFiles(SRC_ROOT); + const filtered = filePattern + ? allFiles.filter((f) => f.endsWith(filePattern)) + : allFiles; + + const matches: string[] = []; + for (const file of filtered) { + if (matches.length >= maxResults) break; + const abs = path.join(SRC_ROOT, file); + let content: string; + try { + content = await fs.readFile(abs, "utf-8"); + } catch { + continue; + } + const lines = content.split("\n"); + for (let i = 0; i < lines.length; i++) { + if (matches.length >= maxResults) break; + if (regex.test(lines[i]!)) { + matches.push(`${file}:${i + 1}: ${lines[i]!.trim()}`); + } + } + } + + return { + content: [ + { + type: "text" as const, + text: + matches.length > 0 + ? `Found ${matches.length} match(es):\n\n${matches.join("\n")}` + : "No matches found.", + }, + ], + }; + } + + case "list_directory": { + const relPath = + ((args as Record)?.path as string) ?? ""; + const abs = safePath(relPath); + if (!abs || !(await dirExists(abs))) + throw new Error(`Directory not found: ${relPath}`); + const entries = await listDir(abs); + return { + content: [ + { + type: "text" as const, + text: + entries.length > 0 + ? entries.join("\n") + : "(empty directory)", + }, + ], + }; + } + + case "get_architecture": { + const topLevel = await listDir(SRC_ROOT); + const tools = await getToolList(); + const commands = await getCommandList(); + + const overview = `# Claude Code Architecture Overview + +## Source Root +${SRC_ROOT} + +## Top-Level Entries +${topLevel.map((e) => `- ${e}`).join("\n")} + +## Agent Tools (${tools.length}) +${tools.map((t) => `- **${t.name}** — ${t.files.length} files: ${t.files.join(", ")}`).join("\n")} + +## Slash Commands (${commands.length}) +${commands.map((c) => `- **${c.name}** ${c.isDirectory ? "(directory)" : "(file)"}${c.files ? ": " + c.files.join(", ") : ""}`).join("\n")} + +## Key Files +- **main.tsx** — CLI entrypoint (Commander.js) +- **QueryEngine.ts** — Core LLM API caller, streaming, tool loops +- **Tool.ts** — Base tool types, schemas, permission model +- **commands.ts** — Command registry and loader +- **tools.ts** — Tool registry and loader +- **context.ts** — System/user context collection + +## Core Subsystems +- **bridge/** — IDE integration (VS Code, JetBrains) +- **coordinator/** — Multi-agent orchestration +- **services/mcp/** — MCP client connections +- **services/api/** — Anthropic API client +- **plugins/** — Plugin system +- **skills/** — Skill system +- **tasks/** — Background task management +- **server/** — Server/remote mode +`; + return { content: [{ type: "text" as const, text: overview }] }; + } + + default: + throw new Error(`Unknown tool: ${name}`); + } + } + ); + + // ---- Prompts ----------------------------------------------------------- + + server.setRequestHandler(ListPromptsRequestSchema, async () => ({ + prompts: [ + { + name: "explain_tool", + description: + "Explain how a specific Claude Code tool works, including its input schema, permissions, and execution flow.", + arguments: [ + { + name: "toolName", + description: "Tool directory name, e.g. 'BashTool', 'FileEditTool'", + required: true, + }, + ], + }, + { + name: "explain_command", + description: "Explain how a specific Claude Code slash command works.", + arguments: [ + { + name: "commandName", + description: "Command name, e.g. 'commit', 'review', 'mcp'", + required: true, + }, + ], + }, + { + name: "architecture_overview", + description: + "Get a guided tour of the Claude Code architecture with explanations of each subsystem.", + }, + { + name: "how_does_it_work", + description: + "Explain how a specific feature or subsystem of Claude Code works.", + arguments: [ + { + name: "feature", + description: + "Feature or subsystem, e.g. 'permission system', 'MCP client', 'query engine', 'bridge'", + required: true, + }, + ], + }, + { + name: "compare_tools", + description: + "Compare two Claude Code tools side by side — purpose, inputs, permissions, implementation.", + arguments: [ + { name: "tool1", description: "First tool name", required: true }, + { name: "tool2", description: "Second tool name", required: true }, + ], + }, + ], + })); + + server.setRequestHandler( + GetPromptRequestSchema, + async (request: { + params: { name: string; arguments?: Record }; + }) => { + const { name, arguments: args } = request.params; + + switch (name) { + case "explain_tool": { + const toolName = args?.toolName; + if (!toolName) throw new Error("toolName argument is required"); + const toolDir = safePath(`tools/${toolName}`); + if (!toolDir || !(await dirExists(toolDir))) + throw new Error(`Tool not found: ${toolName}`); + const files = await listDir(toolDir); + const mainFile = + files.find( + (f) => f === `${toolName}.ts` || f === `${toolName}.tsx` + ) ?? files.find((f) => f.endsWith(".ts") || f.endsWith(".tsx")); + let source = ""; + if (mainFile) { + source = await fs.readFile(path.join(toolDir, mainFile), "utf-8"); + } + return { + description: `Explanation of the ${toolName} tool`, + messages: [ + { + role: "user" as const, + content: { + type: "text" as const, + text: `Analyze and explain this Claude Code tool implementation. Cover:\n1. Purpose\n2. Input Schema\n3. Permissions\n4. Execution Flow\n5. Output\n6. Safety characteristics\n\nFiles in tools/${toolName}/: ${files.join(", ")}\n\nMain source (${mainFile ?? "not found"}):\n\`\`\`typescript\n${source}\n\`\`\``, + }, + }, + ], + }; + } + + case "explain_command": { + const commandName = args?.commandName; + if (!commandName) + throw new Error("commandName argument is required"); + const candidates = [ + `commands/${commandName}`, + `commands/${commandName}.ts`, + `commands/${commandName}.tsx`, + ]; + let found: string | null = null; + let isDir = false; + for (const c of candidates) { + const abs = safePath(c); + if (abs && (await dirExists(abs))) { + found = abs; + isDir = true; + break; + } + if (abs && (await fileExists(abs))) { + found = abs; + break; + } + } + if (!found) throw new Error(`Command not found: ${commandName}`); + let source = ""; + let fileList = ""; + if (isDir) { + const files = await listDir(found); + fileList = files.join(", "); + const indexFile = files.find( + (f) => f === "index.ts" || f === "index.tsx" + ); + if (indexFile) { + source = await fs.readFile( + path.join(found, indexFile), + "utf-8" + ); + } + } else { + source = await fs.readFile(found, "utf-8"); + fileList = path.basename(found); + } + return { + description: `Explanation of the /${commandName} command`, + messages: [ + { + role: "user" as const, + content: { + type: "text" as const, + text: `Analyze and explain this Claude Code slash command. Cover:\n1. Purpose\n2. Type (prompt vs action)\n3. Allowed Tools\n4. Arguments\n5. Implementation\n\nFiles: ${fileList}\n\nSource:\n\`\`\`typescript\n${source}\n\`\`\``, + }, + }, + ], + }; + } + + case "architecture_overview": { + const readmePath = path.resolve(SRC_ROOT, "..", "README.md"); + let readme = ""; + try { + readme = await fs.readFile(readmePath, "utf-8"); + } catch { + /* */ + } + const topLevel = await listDir(SRC_ROOT); + const tools = await getToolList(); + const commands = await getCommandList(); + return { + description: "Architecture overview of Claude Code", + messages: [ + { + role: "user" as const, + content: { + type: "text" as const, + text: `Give a comprehensive guided tour of the Claude Code architecture.\n\n## README\n${readme}\n\n## src/ entries\n${topLevel.join("\n")}\n\n## Tools (${tools.length})\n${tools.map((t) => `- ${t.name}: ${t.files.join(", ")}`).join("\n")}\n\n## Commands (${commands.length})\n${commands.map((c) => `- ${c.name} ${c.isDirectory ? "(dir)" : "(file)"}`).join("\n")}`, + }, + }, + ], + }; + } + + case "how_does_it_work": { + const feature = args?.feature; + if (!feature) throw new Error("feature argument is required"); + const featureMap: Record = { + "permission system": [ + "utils/permissions/", + "hooks/toolPermission/", + "Tool.ts", + ], + permissions: [ + "utils/permissions/", + "hooks/toolPermission/", + "Tool.ts", + ], + "mcp client": [ + "services/mcp/", + "tools/MCPTool/", + "tools/ListMcpResourcesTool/", + ], + mcp: ["services/mcp/", "entrypoints/mcp.ts", "tools/MCPTool/"], + "tool system": ["Tool.ts", "tools.ts", "tools/"], + tools: ["Tool.ts", "tools.ts"], + "query engine": ["QueryEngine.ts", "query/"], + bridge: ["bridge/"], + "ide integration": ["bridge/"], + context: ["context.ts", "context/"], + commands: ["commands.ts", "types/command.ts"], + "command system": ["commands.ts", "types/command.ts", "commands/"], + plugins: ["plugins/"], + skills: ["skills/"], + tasks: ["tasks.ts", "tasks/", "tools/TaskCreateTool/"], + coordinator: ["coordinator/", "tools/AgentTool/"], + "multi-agent": ["coordinator/", "tools/AgentTool/"], + memory: ["memdir/", "commands/memory/"], + voice: ["voice/"], + server: ["server/"], + }; + const paths = featureMap[feature.toLowerCase()] ?? []; + let contextFiles = ""; + for (const p of paths) { + const abs = safePath(p); + if (!abs) continue; + try { + const stat = await fs.stat(abs); + if (stat.isDirectory()) { + const files = await listDir(abs); + contextFiles += `\n### ${p}\nFiles: ${files.join(", ")}\n`; + } else { + const content = await fs.readFile(abs, "utf-8"); + const preview = content.split("\n").slice(0, 200).join("\n"); + contextFiles += `\n### ${p} (first 200 lines)\n\`\`\`typescript\n${preview}\n\`\`\`\n`; + } + } catch { + /* skip */ + } + } + return { + description: `How ${feature} works in Claude Code`, + messages: [ + { + role: "user" as const, + content: { + type: "text" as const, + text: `Explain how "${feature}" works in the Claude Code CLI.\n${contextFiles || "(No specific files mapped — use search_source and read_source_file to find relevant code.)"}`, + }, + }, + ], + }; + } + + case "compare_tools": { + const tool1 = args?.tool1; + const tool2 = args?.tool2; + if (!tool1 || !tool2) + throw new Error("Both tool1 and tool2 arguments are required"); + const sources: string[] = []; + for (const toolName of [tool1, tool2]) { + const toolDir = safePath(`tools/${toolName}`); + if (!toolDir || !(await dirExists(toolDir))) { + sources.push(`// Tool not found: ${toolName}`); + continue; + } + const files = await listDir(toolDir); + const mainFile = + files.find( + (f) => f === `${toolName}.ts` || f === `${toolName}.tsx` + ) ?? files.find((f) => f.endsWith(".ts") || f.endsWith(".tsx")); + if (mainFile) { + const content = await fs.readFile( + path.join(toolDir, mainFile), + "utf-8" + ); + sources.push(`// tools/${toolName}/${mainFile}\n${content}`); + } else { + sources.push(`// No main source found for ${toolName}`); + } + } + return { + description: `Comparison of ${tool1} vs ${tool2}`, + messages: [ + { + role: "user" as const, + content: { + type: "text" as const, + text: `Compare these two Claude Code tools:\n\n## ${tool1}\n\`\`\`typescript\n${sources[0]}\n\`\`\`\n\n## ${tool2}\n\`\`\`typescript\n${sources[1]}\n\`\`\``, + }, + }, + ], + }; + } + + default: + throw new Error(`Unknown prompt: ${name}`); + } + } + ); + + return server; +} + +/** Validate that SRC_ROOT exists. Exits with error if not. */ +export async function validateSrcRoot(): Promise { + if (!(await dirExists(SRC_ROOT))) { + console.error( + `Error: Claude Code src/ directory not found at ${SRC_ROOT}` + ); + console.error( + "Set CLAUDE_CODE_SRC_ROOT environment variable to the src/ directory path." + ); + process.exit(1); + } +} + + diff --git a/mcp-server/tsconfig.json b/mcp-server/tsconfig.json new file mode 100644 index 0000000..a4435a7 --- /dev/null +++ b/mcp-server/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "Node16", + "moduleResolution": "Node16", + "outDir": "./dist", + "rootDir": ".", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["src/**/*", "api/**/*"], + "exclude": ["node_modules", "dist"] +} + +