@robinbraemer/codemode 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/executor/auto.ts","../src/request-bridge.ts","../src/tools.ts","../src/codemode.ts"],"sourcesContent":["import type { Executor, SandboxOptions } from \"../types.js\";\n\n/**\n * Auto-detect and create an executor from available peer dependencies.\n * Tries isolated-vm first, then quickjs-emscripten.\n */\nexport async function createExecutor(\n options: SandboxOptions = {},\n): Promise<Executor> {\n // Try isolated-vm first (faster, V8-native)\n try {\n // @ts-ignore — optional peer dependency\n await import(\"isolated-vm\");\n const { IsolatedVMExecutor } = await import(\"./isolated-vm.js\");\n return new IsolatedVMExecutor(options);\n } catch {\n // Not available\n }\n\n // Try quickjs-emscripten (portable WASM)\n try {\n await import(\"quickjs-emscripten\");\n const { QuickJSExecutor } = await import(\"./quickjs.js\");\n return new QuickJSExecutor(options);\n } catch {\n // Not available\n }\n\n throw new Error(\n \"No sandbox runtime found. Install one of:\\n\" +\n \" npm install isolated-vm # V8 isolates, fastest (Node.js only)\\n\" +\n \" npm install quickjs-emscripten # WASM sandbox, portable (Node.js, Bun, browsers)\",\n );\n}\n","import type { RequestHandler } from \"./types.js\";\n\n/**\n * Options for a sandbox request call.\n * This is what the LLM-generated code passes to `{namespace}.request()`.\n */\nexport interface SandboxRequestOptions {\n method: string;\n path: string;\n query?: Record<string, string | number | boolean>;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\n/**\n * Response returned to the sandbox from a request call.\n */\nexport interface SandboxResponse {\n status: number;\n headers: Record<string, string>;\n body: unknown;\n}\n\n/**\n * Creates the `request()` function that gets injected into the execute sandbox.\n * Bridges sandbox API calls to the host request handler (Hono app.request, fetch, etc.).\n */\nexport function createRequestBridge(\n handler: RequestHandler,\n baseUrl: string,\n): (options: SandboxRequestOptions) => Promise<SandboxResponse> {\n return async (options: SandboxRequestOptions): Promise<SandboxResponse> => {\n const { method, path, query, body, headers } = options;\n\n // Build URL\n const url = new URL(path, baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n url.searchParams.set(key, String(value));\n }\n }\n\n // Build request init\n const init: RequestInit = {\n method: method.toUpperCase(),\n headers: {\n ...headers,\n },\n };\n\n if (body !== undefined && body !== null) {\n init.body = JSON.stringify(body);\n (init.headers as Record<string, string>)[\"content-type\"] =\n (init.headers as Record<string, string>)[\"content-type\"] ?? \"application/json\";\n }\n\n // Call the host handler\n const response = await handler(url.toString(), init);\n\n // Parse response\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n let responseBody: unknown;\n if (contentType.includes(\"application/json\")) {\n try {\n responseBody = await response.json();\n } catch {\n responseBody = await response.text();\n }\n } else {\n responseBody = await response.text();\n }\n\n return {\n status: response.status,\n headers: responseHeaders,\n body: responseBody,\n };\n };\n}\n","import type { ToolDefinition } from \"./types.js\";\n\nexport function createSearchToolDefinition(toolName: string): ToolDefinition {\n return {\n name: toolName,\n description: `Search the API specification to discover available endpoints.\n\nWrite an async JavaScript arrow function that filters and explores the \\`spec\\` object (an OpenAPI 3.x document). The full spec is available as a global variable.\n\nCommon patterns:\n- Find endpoints by path: \\`spec.paths\\` is an object keyed by path string\n- Each path has HTTP methods (get, post, put, delete, patch) as keys\n- Each operation has: summary, description, parameters, requestBody, responses\n- Use spec.components.schemas for data models\n\nExamples:\n // Find all cluster-related endpoints\n async () => {\n return Object.entries(spec.paths)\n .filter(([p]) => p.includes('/clusters'))\n .flatMap(([path, methods]) =>\n Object.entries(methods)\n .filter(([m]) => ['get','post','put','delete','patch'].includes(m))\n .map(([method, op]) => ({\n method: method.toUpperCase(), path, summary: op.summary\n }))\n );\n }\n\n // Get the schema for a specific model\n async () => {\n return spec.components?.schemas?.Product;\n }\n\nReturn the matching endpoints/schemas as a structured result the agent can use to plan execute() calls.`,\n inputSchema: {\n type: \"object\",\n properties: {\n code: {\n type: \"string\",\n description:\n \"An async JavaScript arrow function that searches the `spec` object. Must return a value.\",\n },\n },\n required: [\"code\"],\n },\n };\n}\n\nexport function createExecuteToolDefinition(\n toolName: string,\n namespace: string,\n): ToolDefinition {\n return {\n name: toolName,\n description: `Execute API calls by writing JavaScript code.\n\nWrite an async JavaScript arrow function that uses \\`${namespace}.request()\\` to make API calls. The request function handles authentication automatically.\n\n\\`${namespace}.request(options)\\` takes:\n - method: HTTP method string (\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\")\n - path: API path string (e.g. \"/v1/clusters\")\n - query: optional object of query parameters\n - body: optional request body (will be JSON-serialized)\n - headers: optional object of additional headers\n\nReturns: { status: number, headers: object, body: unknown }\n\nExamples:\n // List resources\n async () => {\n const res = await ${namespace}.request({ method: \"GET\", path: \"/v1/clusters\" });\n return res.body;\n }\n\n // Create a resource\n async () => {\n return ${namespace}.request({\n method: \"POST\",\n path: \"/v1/products\",\n body: { name: \"My Product\", chart: \"nginx\" }\n });\n }\n\n // Chain multiple calls\n async () => {\n const clusters = await ${namespace}.request({ method: \"GET\", path: \"/v1/clusters\" });\n const details = await Promise.all(\n clusters.body.map(c =>\n ${namespace}.request({ method: \"GET\", path: \\`/v1/clusters/\\${c.id}\\` })\n )\n );\n return details.map(d => d.body);\n }\n\nWrite clean, focused code. Return the data the user needs.`,\n inputSchema: {\n type: \"object\",\n properties: {\n code: {\n type: \"string\",\n description: `An async JavaScript arrow function that uses \\`${namespace}.request()\\` to make API calls.`,\n },\n },\n required: [\"code\"],\n },\n };\n}\n","import { createExecutor } from \"./executor/auto.js\";\nimport { createRequestBridge } from \"./request-bridge.js\";\nimport { createExecuteToolDefinition, createSearchToolDefinition } from \"./tools.js\";\nimport type {\n CodeModeOptions,\n Executor,\n OpenAPISpec,\n SpecProvider,\n ToolCallResult,\n ToolDefinition,\n} from \"./types.js\";\n\n/**\n * CodeMode provides `search` and `execute` MCP tools that let an AI agent\n * discover and call your API by writing JavaScript code in a sandboxed runtime.\n *\n * Instead of defining hundreds of individual MCP tools (one per API endpoint),\n * CodeMode exposes just two tools:\n * - `search` — the agent writes JS to filter your OpenAPI spec\n * - `execute` — the agent writes JS to call your API via a typed client\n *\n * @example\n * ```ts\n * import { CodeMode } from 'codemode';\n * import { Hono } from 'hono';\n *\n * const app = new Hono();\n * // ... define routes ...\n *\n * const codemode = new CodeMode({\n * spec: () => generateOpenAPISpec(app),\n * request: app.request.bind(app),\n * namespace: 'cnap',\n * });\n *\n * // Get MCP tool definitions\n * const tools = codemode.tools();\n *\n * // Handle a tool call\n * const result = await codemode.callTool('search', { code: 'async () => ...' });\n * ```\n */\nexport class CodeMode {\n private specProvider: SpecProvider;\n private requestBridge: (...args: unknown[]) => Promise<unknown>;\n private namespace: string;\n private executor: Executor | null;\n private executorPromise: Promise<Executor> | null = null;\n private options: CodeModeOptions;\n private searchToolName: string;\n private executeToolName: string;\n\n constructor(options: CodeModeOptions) {\n this.options = options;\n this.specProvider = options.spec;\n this.namespace = options.namespace ?? \"api\";\n this.executor = options.executor ?? null;\n this.searchToolName = \"search\";\n this.executeToolName = \"execute\";\n\n const baseUrl = options.baseUrl ?? \"http://localhost\";\n const bridge = createRequestBridge(options.request, baseUrl);\n this.requestBridge = (...args: unknown[]) => bridge(args[0] as any);\n }\n\n /**\n * Override the default tool names.\n */\n setToolNames(search: string, execute: string): this {\n this.searchToolName = search;\n this.executeToolName = execute;\n return this;\n }\n\n /**\n * Returns MCP tool definitions for search and execute.\n */\n tools(): ToolDefinition[] {\n return [\n createSearchToolDefinition(this.searchToolName),\n createExecuteToolDefinition(this.executeToolName, this.namespace),\n ];\n }\n\n /**\n * Handle an MCP tool call.\n */\n async callTool(\n toolName: string,\n args: { code: string },\n ): Promise<ToolCallResult> {\n if (toolName === this.searchToolName) {\n return this.search(args.code);\n }\n if (toolName === this.executeToolName) {\n return this.execute(args.code);\n }\n return {\n content: [{ type: \"text\", text: `Unknown tool: ${toolName}` }],\n isError: true,\n };\n }\n\n /**\n * Execute a search against the OpenAPI spec.\n * The code runs in a sandbox with `spec` available as a global.\n */\n async search(code: string): Promise<ToolCallResult> {\n const executor = await this.getExecutor();\n const spec = await this.resolveSpec();\n\n const result = await executor.execute(code, { spec });\n\n return formatResult(result);\n }\n\n /**\n * Execute API calls in the sandbox.\n * The code runs with `{namespace}.request()` available as a global.\n */\n async execute(code: string): Promise<ToolCallResult> {\n const executor = await this.getExecutor();\n\n const client = {\n request: this.requestBridge,\n };\n\n const result = await executor.execute(code, {\n [this.namespace]: client,\n });\n\n return formatResult(result);\n }\n\n /**\n * Clean up sandbox resources.\n */\n dispose(): void {\n this.executor?.dispose?.();\n }\n\n private async resolveSpec(): Promise<OpenAPISpec> {\n if (typeof this.specProvider === \"function\") {\n return await this.specProvider();\n }\n return this.specProvider;\n }\n\n private async getExecutor(): Promise<Executor> {\n if (this.executor) return this.executor;\n\n // Lazy-init with deduplication\n if (!this.executorPromise) {\n this.executorPromise = createExecutor(this.options.sandbox).then(\n (executor) => {\n this.executor = executor;\n return executor;\n },\n );\n }\n return this.executorPromise;\n }\n}\n\nfunction formatResult(result: {\n result: unknown;\n error?: string;\n logs: string[];\n}): ToolCallResult {\n if (result.error) {\n const parts: string[] = [];\n if (result.logs.length > 0) {\n parts.push(`Console output:\\n${result.logs.join(\"\\n\")}`);\n }\n parts.push(`Error: ${result.error}`);\n return {\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n isError: true,\n };\n }\n\n const parts: string[] = [];\n if (result.logs.length > 0) {\n parts.push(`Console output:\\n${result.logs.join(\"\\n\")}`);\n }\n\n const resultText =\n typeof result.result === \"string\"\n ? result.result\n : JSON.stringify(result.result, null, 2);\n parts.push(resultText);\n\n return {\n content: [{ type: \"text\", text: parts.join(\"\\n\\n\") }],\n };\n}\n"],"mappings":"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","names":["IsolatedVMExecutor","QuickJSExecutor","parts"]}
1
+ {"version":3,"sources":["../src/executor/auto.ts","../src/request-bridge.ts","../src/spec.ts","../src/tools.ts","../src/truncate.ts","../src/codemode.ts"],"sourcesContent":["import type { Executor, SandboxOptions } from \"../types.js\";\n\n/**\n * Create an executor using the isolated-vm peer dependency.\n */\nexport async function createExecutor(\n options: SandboxOptions = {},\n): Promise<Executor> {\n try {\n // @ts-ignore — optional peer dependency\n await import(\"isolated-vm\");\n const { IsolatedVMExecutor } = await import(\"./isolated-vm.js\");\n return new IsolatedVMExecutor(options);\n } catch {\n // Not available\n }\n\n throw new Error(\n \"No sandbox runtime found. Install isolated-vm:\\n\" +\n \" npm install isolated-vm # V8 isolates (Node.js)\",\n );\n}\n","import type { RequestHandler } from \"./types.js\";\n\n/**\n * Options for a sandbox request call.\n * This is what the LLM-generated code passes to `{namespace}.request()`.\n */\nexport interface SandboxRequestOptions {\n method: string;\n path: string;\n query?: Record<string, string | number | boolean>;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\n/**\n * Response returned to the sandbox from a request call.\n */\nexport interface SandboxResponse {\n status: number;\n headers: Record<string, string>;\n body: unknown;\n}\n\n/**\n * Options for configuring the request bridge.\n */\nexport interface RequestBridgeOptions {\n /** Maximum number of requests per bridge instance. Default: 50. */\n maxRequests?: number;\n /** Maximum response body size in bytes. Default: 10MB. */\n maxResponseBytes?: number;\n /** Allowed headers whitelist. When undefined, uses default blocklist. */\n allowedHeaders?: string[];\n}\n\nconst ALLOWED_METHODS = new Set([\n \"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\", \"OPTIONS\",\n]);\n\nconst BLOCKED_HEADER_PATTERNS = [\n /^authorization$/i,\n /^cookie$/i,\n /^host$/i,\n /^origin$/i,\n /^referer$/i,\n /^x-forwarded-/i,\n /^x-real-ip$/i,\n /^x-client-ip$/i,\n /^cf-connecting-ip$/i,\n /^true-client-ip$/i,\n /^proxy-/i,\n /^transfer-encoding$/i,\n /^connection$/i,\n /^upgrade$/i,\n /^te$/i,\n];\n\nconst DEFAULT_MAX_REQUESTS = 50;\nconst DEFAULT_MAX_RESPONSE_BYTES = 10 * 1024 * 1024; // 10MB\n\n/**\n * Read a response body as text, aborting early if it exceeds maxBytes.\n * Streams the body in chunks to avoid buffering the entire response\n * into host memory before checking the size limit.\n */\nasync function readResponseWithLimit(\n response: Response,\n maxBytes: number,\n): Promise<string> {\n const reader = response.body?.getReader();\n if (!reader) {\n // No body stream — fall back to .text() (e.g., empty responses)\n const text = await response.text();\n if (text.length > maxBytes) {\n throw new Error(\n `Response too large: ${text.length} bytes exceeds limit of ${maxBytes} bytes`,\n );\n }\n return text;\n }\n\n const chunks: Uint8Array[] = [];\n let totalBytes = 0;\n try {\n // Streaming read — must be sequential\n for (;;) {\n const { done, value } = await reader.read(); // oxlint-disable-line no-await-in-loop\n if (done) break;\n totalBytes += value.byteLength;\n if (totalBytes > maxBytes) {\n throw new Error(\n `Response too large: exceeded limit of ${maxBytes} bytes`,\n );\n }\n chunks.push(value);\n }\n } finally {\n reader.releaseLock();\n }\n\n const decoder = new TextDecoder();\n if (chunks.length === 1) return decoder.decode(chunks[0]);\n // Concatenate chunks\n const combined = new Uint8Array(totalBytes);\n let offset = 0;\n for (const chunk of chunks) {\n combined.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return decoder.decode(combined);\n}\n\n/**\n * Validate that a path is safe (no SSRF, no request smuggling).\n */\nfunction validatePath(path: string): void {\n if (path.includes(\"://\")) {\n throw new Error(`Invalid path: must not contain \"://\" — got \"${path}\"`);\n }\n if (!path.startsWith(\"/\")) {\n throw new Error(`Invalid path: must start with \"/\" — got \"${path}\"`);\n }\n if (path.startsWith(\"//\")) {\n throw new Error(`Invalid path: must not start with \"//\" — got \"${path}\"`);\n }\n if (path.includes(\"\\0\")) {\n throw new Error(\"Invalid path: must not contain null bytes\");\n }\n if (/[\\r\\n]/.test(path)) {\n throw new Error(\"Invalid path: must not contain CR/LF characters\");\n }\n if (path.includes(\"\\\\\")) {\n throw new Error(\"Invalid path: must not contain backslashes\");\n }\n}\n\n/**\n * Filter headers based on allowedHeaders whitelist or default blocklist.\n */\nfunction filterHeaders(\n headers: Record<string, string> | undefined,\n allowedHeaders: string[] | undefined,\n): Record<string, string> {\n if (!headers) return {};\n\n if (allowedHeaders) {\n // Whitelist mode: only forward explicitly allowed headers\n const allowed = new Set(allowedHeaders.map((h) => h.toLowerCase()));\n const filtered: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n if (allowed.has(key.toLowerCase())) {\n filtered[key] = value;\n }\n }\n return filtered;\n }\n\n // Blocklist mode: strip dangerous headers\n const filtered: Record<string, string> = {};\n for (const [key, value] of Object.entries(headers)) {\n const blocked = BLOCKED_HEADER_PATTERNS.some((p) => p.test(key));\n if (!blocked) {\n filtered[key] = value;\n }\n }\n return filtered;\n}\n\n/**\n * Creates the `request()` function that gets injected into the execute sandbox.\n * Bridges sandbox API calls to the host request handler (Hono app.request, fetch, etc.).\n */\nexport function createRequestBridge(\n handler: RequestHandler,\n baseUrl: string,\n options: RequestBridgeOptions = {},\n): (options: SandboxRequestOptions) => Promise<SandboxResponse> {\n const maxRequests = options.maxRequests ?? DEFAULT_MAX_REQUESTS;\n const maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;\n const allowedHeaders = options.allowedHeaders;\n\n let requestCount = 0;\n\n return async (opts: SandboxRequestOptions): Promise<SandboxResponse> => {\n const { method, path, query, body, headers } = opts;\n\n // Validate request count\n if (++requestCount > maxRequests) {\n throw new Error(\n `Request limit exceeded: max ${maxRequests} requests per execution`,\n );\n }\n\n // Validate HTTP method\n const upperMethod = method.toUpperCase();\n if (!ALLOWED_METHODS.has(upperMethod)) {\n throw new Error(\n `Invalid HTTP method: \"${method}\". Allowed: ${[...ALLOWED_METHODS].join(\", \")}`,\n );\n }\n\n // Validate path (SSRF prevention)\n validatePath(path);\n\n // Build URL\n const url = new URL(path, baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n url.searchParams.set(key, String(value));\n }\n }\n\n // Filter headers\n const filteredHeaders = filterHeaders(headers, allowedHeaders);\n\n // Build request init\n const init: RequestInit = {\n method: upperMethod,\n headers: { ...filteredHeaders },\n };\n\n if (body !== undefined && body !== null) {\n init.body = JSON.stringify(body);\n (init.headers as Record<string, string>)[\"content-type\"] =\n (init.headers as Record<string, string>)[\"content-type\"] ?? \"application/json\";\n }\n\n // Call the host handler\n const response = await handler(url.toString(), init);\n\n // Parse response headers\n const responseHeaders: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n responseHeaders[key] = value;\n });\n\n // Read response body with streaming size limit to avoid host OOM.\n // Abort as soon as accumulated bytes exceed the limit.\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const text = await readResponseWithLimit(response, maxResponseBytes);\n\n let responseBody: unknown;\n if (contentType.includes(\"application/json\")) {\n try {\n responseBody = JSON.parse(text);\n } catch {\n responseBody = text;\n }\n } else {\n responseBody = text;\n }\n\n return {\n status: response.status,\n headers: responseHeaders,\n body: responseBody,\n };\n };\n}\n","import type { OpenAPISpec } from \"./types.js\";\n\nconst HTTP_METHODS = [\"get\", \"post\", \"put\", \"patch\", \"delete\"] as const;\n\nconst DEFAULT_MAX_REF_DEPTH = 50;\n\n/** Keys that must never be traversed or copied during $ref resolution. */\nconst DANGEROUS_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\n/**\n * Recursively resolve all `$ref` pointers in an OpenAPI spec inline.\n * Circular references are replaced with `{ $circular: ref }`.\n *\n * The `seen` set tracks the current ancestor chain only (not globally),\n * so the same $ref used in sibling positions resolves correctly.\n * A memoization cache avoids re-resolving the same $ref multiple times.\n *\n * @param maxDepth - Maximum $ref resolution depth (default: 50)\n */\nexport function resolveRefs(\n obj: unknown,\n root: Record<string, unknown>,\n seen = new Set<string>(),\n maxDepth = DEFAULT_MAX_REF_DEPTH,\n _cache = new Map<string, unknown>(),\n): unknown {\n if (obj === null || obj === undefined) return obj;\n if (typeof obj !== \"object\") return obj;\n if (Array.isArray(obj))\n return obj.map((item) => resolveRefs(item, root, seen, maxDepth, _cache));\n\n const record = obj as Record<string, unknown>;\n\n if (\"$ref\" in record && typeof record.$ref === \"string\") {\n const ref = record.$ref;\n\n // Circular: this $ref is already in the current ancestor chain\n if (seen.has(ref)) return { $circular: ref };\n\n // Depth limit\n if (seen.size >= maxDepth) {\n return { $circular: ref, $reason: \"max depth exceeded\" };\n }\n\n // Memoization: return cached result if available\n if (_cache.has(ref)) return _cache.get(ref);\n\n const parts = ref.replace(\"#/\", \"\").split(\"/\");\n let resolved: unknown = root;\n for (const part of parts) {\n if (DANGEROUS_KEYS.has(part)) return { $ref: ref, $error: \"unsafe ref path\" };\n resolved = (resolved as Record<string, unknown>)?.[part];\n }\n\n // Clone seen for this branch so siblings don't share state\n const branchSeen = new Set(seen);\n branchSeen.add(ref);\n\n const result = resolveRefs(resolved, root, branchSeen, maxDepth, _cache);\n _cache.set(ref, result);\n return result;\n }\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(record)) {\n if (DANGEROUS_KEYS.has(key)) continue;\n result[key] = resolveRefs(value, root, seen, maxDepth, _cache);\n }\n return result;\n}\n\ninterface OperationObject {\n summary?: string;\n description?: string;\n tags?: string[];\n operationId?: string;\n parameters?: unknown;\n requestBody?: unknown;\n responses?: unknown;\n}\n\n/**\n * Extract the base path from the first server URL in the spec.\n * e.g. \"https://petstore.io/api/v3\" → \"/api/v3\"\n * e.g. \"/api/v3\" → \"/api/v3\"\n * e.g. \"https://api.example.com\" → \"\"\n */\nexport function extractServerBasePath(spec: OpenAPISpec): string {\n const servers = (spec as Record<string, unknown>).servers as\n | Array<{ url: string }>\n | undefined;\n if (!servers?.length) return \"\";\n\n const url = servers[0]!.url;\n try {\n // Full URL like \"https://petstore.io/api/v3\"\n const parsed = new URL(url);\n return parsed.pathname.replace(/\\/+$/, \"\");\n } catch {\n // Relative path like \"/api/v3\"\n return url.replace(/\\/+$/, \"\");\n }\n}\n\n/**\n * Process an OpenAPI spec into a simplified format for the search tool.\n * Resolves all $refs inline and extracts only the fields needed for search.\n * Prepends the server base path to all path keys so they're directly usable.\n * Preserves info and components.schemas alongside processed paths.\n *\n * @param maxRefDepth - Maximum $ref resolution depth (default: 50)\n */\nexport function processSpec(\n spec: OpenAPISpec,\n maxRefDepth = DEFAULT_MAX_REF_DEPTH,\n): Record<string, unknown> {\n const rawPaths = (spec.paths ?? {}) as Record<\n string,\n Record<string, OperationObject>\n >;\n const basePath = extractServerBasePath(spec);\n const paths: Record<string, Record<string, unknown>> = {};\n\n for (const [path, pathItem] of Object.entries(rawPaths)) {\n if (!pathItem) continue;\n const fullPath = basePath ? basePath + path : path;\n paths[fullPath] = {};\n\n for (const method of HTTP_METHODS) {\n const op = pathItem[method];\n if (op) {\n paths[fullPath][method] = {\n summary: op.summary,\n description: op.description,\n tags: op.tags,\n operationId: op.operationId,\n parameters: resolveRefs(\n op.parameters,\n spec as Record<string, unknown>,\n undefined,\n maxRefDepth,\n ),\n requestBody: resolveRefs(\n op.requestBody,\n spec as Record<string, unknown>,\n undefined,\n maxRefDepth,\n ),\n responses: resolveRefs(\n op.responses,\n spec as Record<string, unknown>,\n undefined,\n maxRefDepth,\n ),\n };\n }\n }\n }\n\n const result: Record<string, unknown> = { paths };\n\n if (spec.info) result.info = spec.info;\n // servers is omitted — the base path is already prepended to all path keys\n if ((spec as Record<string, unknown>).components) {\n result.components = resolveRefs(\n (spec as Record<string, unknown>).components,\n spec as Record<string, unknown>,\n undefined,\n maxRefDepth,\n );\n }\n\n return result;\n}\n\n/**\n * Extract unique tags from the spec, sorted by frequency (most common first).\n */\nexport function extractTags(spec: OpenAPISpec): string[] {\n const rawPaths = spec.paths as\n | Record<string, Record<string, OperationObject>>\n | undefined;\n if (!rawPaths) return [];\n\n const tags = new Map<string, number>();\n for (const pathItem of Object.values(rawPaths)) {\n if (!pathItem) continue;\n for (const method of HTTP_METHODS) {\n const op = pathItem[method];\n if (op?.tags) {\n for (const tag of op.tags) {\n tags.set(tag, (tags.get(tag) ?? 0) + 1);\n }\n }\n }\n }\n\n return [...tags.entries()].toSorted((a, b) => b[1] - a[1]).map(([t]) => t);\n}\n","import type { ToolDefinition } from \"./types.js\";\n\nconst SPEC_TYPES = `\ninterface OperationInfo {\n summary?: string;\n description?: string;\n tags?: string[];\n operationId?: string;\n parameters?: Array<{ name: string; in: string; required?: boolean; schema?: unknown; description?: string }>;\n requestBody?: { required?: boolean; content?: Record<string, { schema?: unknown }> };\n responses?: Record<string, { description?: string; content?: Record<string, { schema?: unknown }> }>;\n}\n\ninterface PathItem {\n get?: OperationInfo;\n post?: OperationInfo;\n put?: OperationInfo;\n patch?: OperationInfo;\n delete?: OperationInfo;\n}\n\ndeclare const spec: {\n paths: Record<string, PathItem>;\n components?: { schemas?: Record<string, unknown> };\n info?: { title?: string; version?: string; description?: string };\n};\n`;\n\nexport function createSearchToolDefinition(\n toolName: string,\n context?: { tags?: string[]; endpointCount?: number },\n): ToolDefinition {\n const parts: string[] = [];\n\n parts.push(\n `Search the API specification to discover available endpoints. All $refs are pre-resolved inline.`,\n );\n\n if (context?.tags && context.tags.length > 0) {\n const shown = context.tags.slice(0, 30).join(\", \");\n const suffix =\n context.tags.length > 30 ? `... (${context.tags.length} total)` : \"\";\n parts.push(`Tags: ${shown}${suffix}`);\n }\n\n if (context?.endpointCount) {\n parts.push(`Endpoints: ${context.endpointCount}`);\n }\n\n parts.push(`Types:\n${SPEC_TYPES}`);\n\n const exampleTag = context?.tags?.[0]?.toLowerCase() ?? \"items\";\n\n parts.push(`Your code must be an async arrow function that returns the result.\n\nExamples:\n\n// List all endpoints\nasync () => {\n const results = [];\n for (const [path, methods] of Object.entries(spec.paths)) {\n for (const [method, op] of Object.entries(methods)) {\n results.push({ method: method.toUpperCase(), path, summary: op.summary });\n }\n }\n return results;\n}\n\n// Find endpoints by tag\nasync () => {\n const results = [];\n for (const [path, methods] of Object.entries(spec.paths)) {\n for (const [method, op] of Object.entries(methods)) {\n if (op.tags?.some(t => t.toLowerCase() === '${exampleTag}')) {\n results.push({ method: method.toUpperCase(), path, summary: op.summary });\n }\n }\n }\n return results;\n}\n\n// Get full details for a specific endpoint (refs are already resolved)\nasync () => {\n const op = spec.paths['/example']?.get;\n return { summary: op?.summary, parameters: op?.parameters, requestBody: op?.requestBody };\n}`);\n\n return {\n name: toolName,\n description: parts.join(\"\\n\\n\"),\n inputSchema: {\n type: \"object\",\n properties: {\n code: {\n type: \"string\",\n description:\n \"JavaScript async arrow function to search the `spec` object\",\n },\n },\n required: [\"code\"],\n },\n };\n}\n\nexport function createExecuteToolDefinition(\n toolName: string,\n namespace: string,\n): ToolDefinition {\n const types = `\ninterface RequestOptions {\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n path: string;\n query?: Record<string, string | number | boolean>;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\ninterface Response<T = unknown> {\n status: number;\n headers: Record<string, string>;\n body: T;\n}\n\ndeclare const ${namespace}: {\n request<T = unknown>(options: RequestOptions): Promise<Response<T>>;\n};\n`;\n\n return {\n name: toolName,\n description: `Execute API calls by writing JavaScript code. First use the 'search' tool to find the right endpoints.\n\nAvailable in your code:\n${types}\nYour code must be an async arrow function that returns the result.\n\nExamples:\n\n// List resources\nasync () => {\n const res = await ${namespace}.request({ method: \"GET\", path: \"/v1/items\" });\n return res.body;\n}\n\n// Create a resource\nasync () => {\n const res = await ${namespace}.request({\n method: \"POST\",\n path: \"/v1/items\",\n body: { name: \"Widget\" }\n });\n return { status: res.status, body: res.body };\n}\n\n// Chain multiple calls\nasync () => {\n const list = await ${namespace}.request({ method: \"GET\", path: \"/v1/items\" });\n const details = await Promise.all(\n list.body.map(item =>\n ${namespace}.request({ method: \"GET\", path: \\`/v1/items/\\${item.id}\\` })\n )\n );\n return details.map(d => d.body);\n}`,\n inputSchema: {\n type: \"object\",\n properties: {\n code: {\n type: \"string\",\n description: `JavaScript async arrow function that uses \\`${namespace}.request()\\` to make API calls`,\n },\n },\n required: [\"code\"],\n },\n };\n}\n","const CHARS_PER_TOKEN = 4;\nconst DEFAULT_MAX_TOKENS = 25_000;\n\n/**\n * Truncate a response to fit within a token budget.\n * Uses a ~4 chars/token estimate.\n */\nexport function truncateResponse(\n content: unknown,\n maxTokens: number = DEFAULT_MAX_TOKENS,\n): string {\n const text =\n typeof content === \"string\"\n ? content\n : JSON.stringify(content, null, 2);\n\n const maxChars = maxTokens * CHARS_PER_TOKEN;\n\n if (text.length <= maxChars) {\n return text;\n }\n\n const truncated = text.slice(0, maxChars);\n const estimatedTokens = Math.ceil(text.length / CHARS_PER_TOKEN);\n\n return `${truncated}\\n\\n--- TRUNCATED ---\\nResponse was ~${estimatedTokens.toLocaleString()} tokens (limit: ${maxTokens.toLocaleString()}). Use more specific queries to reduce response size.`;\n}\n","import { createExecutor } from \"./executor/auto.js\";\nimport { createRequestBridge, type SandboxRequestOptions } from \"./request-bridge.js\";\nimport { extractTags, processSpec } from \"./spec.js\";\nimport { createExecuteToolDefinition, createSearchToolDefinition } from \"./tools.js\";\nimport { truncateResponse } from \"./truncate.js\";\nimport type {\n CodeModeOptions,\n Executor,\n OpenAPISpec,\n RequestHandler,\n SpecProvider,\n ToolCallResult,\n ToolDefinition,\n} from \"./types.js\";\n\nconst RESERVED_NAMES = new Set([\n \"Object\", \"Array\", \"Promise\", \"Function\", \"String\", \"Number\", \"Boolean\",\n \"Symbol\", \"Map\", \"Set\", \"WeakMap\", \"WeakSet\", \"Date\", \"RegExp\", \"Error\",\n \"JSON\", \"Math\", \"Proxy\", \"Reflect\", \"globalThis\", \"undefined\", \"null\",\n \"NaN\", \"Infinity\", \"console\", \"spec\", \"global\",\n]);\n\nconst VALID_JS_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nfunction validateNamespace(namespace: string): void {\n if (!VALID_JS_IDENTIFIER.test(namespace)) {\n throw new Error(\n `Invalid namespace \"${namespace}\": must be a valid JavaScript identifier`,\n );\n }\n if (RESERVED_NAMES.has(namespace)) {\n throw new Error(\n `Invalid namespace \"${namespace}\": conflicts with reserved name`,\n );\n }\n}\n\n/**\n * CodeMode provides `search` and `execute` MCP tools that let an AI agent\n * discover and call your API by writing JavaScript code in a sandboxed runtime.\n *\n * Instead of defining hundreds of individual MCP tools (one per API endpoint),\n * CodeMode exposes just two tools:\n * - `search` — the agent writes JS to filter your OpenAPI spec\n * - `execute` — the agent writes JS to call your API via a typed client\n *\n * @example\n * ```ts\n * import { CodeMode } from 'codemode';\n * import { Hono } from 'hono';\n *\n * const app = new Hono();\n * // ... define routes ...\n *\n * const codemode = new CodeMode({\n * spec: () => generateOpenAPISpec(app),\n * request: app.request.bind(app),\n * namespace: 'cnap',\n * });\n *\n * // Get MCP tool definitions\n * const tools = codemode.tools();\n *\n * // Handle a tool call\n * const result = await codemode.callTool('search', { code: 'async () => ...' });\n * ```\n */\nexport class CodeMode {\n private specProvider: SpecProvider;\n private namespace: string;\n private executor: Executor | null;\n private executorPromise: Promise<Executor> | null = null;\n private options: CodeModeOptions;\n private searchToolName: string;\n private executeToolName: string;\n private maxResponseTokens: number;\n\n // Bridge config — a fresh bridge is created per execute() call\n // so the request counter resets each time.\n private bridgeHandler: RequestHandler;\n private bridgeBaseUrl: string;\n private bridgeOptions: { maxRequests?: number; maxResponseBytes?: number; allowedHeaders?: string[] };\n\n // Cached processed spec & context for tool descriptions\n private processedSpec: Record<string, unknown> | null = null;\n private specContext: { tags: string[]; endpointCount: number } | null = null;\n\n constructor(options: CodeModeOptions) {\n this.options = options;\n this.specProvider = options.spec;\n this.namespace = options.namespace ?? \"api\";\n this.executor = options.executor ?? null;\n this.searchToolName = \"search\";\n this.executeToolName = \"execute\";\n this.maxResponseTokens = options.maxResponseTokens ?? 25_000;\n\n validateNamespace(this.namespace);\n\n this.bridgeHandler = options.request;\n this.bridgeBaseUrl = options.baseUrl ?? \"http://localhost\";\n this.bridgeOptions = {\n maxRequests: options.maxRequests,\n maxResponseBytes: options.maxResponseBytes,\n allowedHeaders: options.allowedHeaders,\n };\n }\n\n /**\n * Override the default tool names.\n */\n setToolNames(search: string, execute: string): this {\n this.searchToolName = search;\n this.executeToolName = execute;\n return this;\n }\n\n /**\n * Returns MCP tool definitions for search and execute.\n */\n tools(): ToolDefinition[] {\n return [\n createSearchToolDefinition(this.searchToolName, this.specContext ?? undefined),\n createExecuteToolDefinition(this.executeToolName, this.namespace),\n ];\n }\n\n /**\n * Handle an MCP tool call.\n */\n async callTool(\n toolName: string,\n args: { code: string },\n ): Promise<ToolCallResult> {\n if (toolName === this.searchToolName) {\n return this.search(args.code);\n }\n if (toolName === this.executeToolName) {\n return this.execute(args.code);\n }\n return {\n content: [{ type: \"text\", text: `Unknown tool: ${toolName}` }],\n isError: true,\n };\n }\n\n /**\n * Execute a search against the OpenAPI spec.\n * The code runs in a sandbox with `spec` available as a global.\n * All $refs are pre-resolved inline.\n */\n async search(code: string): Promise<ToolCallResult> {\n const executor = await this.getExecutor();\n const spec = await this.getProcessedSpec();\n\n const result = await executor.execute(code, { spec });\n\n return this.formatResult(result);\n }\n\n /**\n * Execute API calls in the sandbox.\n * The code runs with `{namespace}.request()` available as a global.\n */\n async execute(code: string): Promise<ToolCallResult> {\n const executor = await this.getExecutor();\n\n // Fresh bridge per execution — request counter resets each time\n const bridge = createRequestBridge(\n this.bridgeHandler, this.bridgeBaseUrl, this.bridgeOptions,\n );\n const client = {\n request: (...args: unknown[]) => bridge(args[0] as SandboxRequestOptions),\n };\n\n const result = await executor.execute(code, {\n [this.namespace]: client,\n });\n\n return this.formatResult(result);\n }\n\n /**\n * Clean up sandbox resources.\n */\n dispose(): void {\n this.executor?.dispose?.();\n }\n\n private async resolveSpec(): Promise<OpenAPISpec> {\n if (typeof this.specProvider === \"function\") {\n return await this.specProvider();\n }\n return this.specProvider;\n }\n\n /**\n * Get the processed spec (refs resolved, fields extracted).\n * Caches the result after first call.\n */\n private async getProcessedSpec(): Promise<Record<string, unknown>> {\n if (this.processedSpec) return this.processedSpec;\n\n const raw = await this.resolveSpec();\n this.processedSpec = processSpec(raw, this.options.maxRefDepth);\n\n // Extract context for tool descriptions\n const tags = extractTags(raw);\n const endpointCount = Object.keys(raw.paths ?? {}).length;\n this.specContext = { tags, endpointCount };\n\n return this.processedSpec;\n }\n\n private async getExecutor(): Promise<Executor> {\n if (this.executor) return this.executor;\n\n // Lazy-init with deduplication\n if (!this.executorPromise) {\n this.executorPromise = createExecutor(this.options.sandbox).then(\n (executor) => {\n this.executor = executor;\n return executor;\n },\n );\n }\n return this.executorPromise;\n }\n\n private formatResult(result: {\n result: unknown;\n error?: string;\n }): ToolCallResult {\n if (result.error) {\n return {\n content: [{ type: \"text\", text: `Error: ${result.error}` }],\n isError: true,\n };\n }\n\n const resultText =\n typeof result.result === \"string\"\n ? result.result\n : JSON.stringify(result.result, null, 2);\n\n return {\n content: [{ type: \"text\", text: truncateResponse(resultText, this.maxResponseTokens) }],\n };\n }\n}\n"],"mappings":"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","names":["IsolatedVMExecutor","filtered","result"]}
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  IsolatedVMExecutor
3
- } from "./chunk-NSUQUO7S.js";
3
+ } from "./chunk-M4AL5G4U.js";
4
4
  import "./chunk-PZ5AY32C.js";
5
5
  export {
6
6
  IsolatedVMExecutor
7
7
  };
8
- //# sourceMappingURL=isolated-vm-57EIYEJM.js.map
8
+ //# sourceMappingURL=isolated-vm-7REUQAB5.js.map
package/dist/mcp.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- import { C as CodeMode } from './codemode-DbXujxeq.js';
2
- import { z } from 'zod';
1
+ import { C as CodeMode } from './codemode-C8y0tnb7.js';
3
2
 
4
3
  /**
5
4
  * MCP server integration for CodeMode.
@@ -23,16 +22,10 @@ import { z } from 'zod';
23
22
  /**
24
23
  * Register CodeMode's search and execute tools on an MCP server.
25
24
  *
26
- * This uses the `@modelcontextprotocol/sdk` `McpServer.tool()` API
27
- * to register both tools with proper Zod schemas.
25
+ * Uses the `McpServer.registerTool()` API from `@modelcontextprotocol/sdk`.
28
26
  */
29
- declare function registerTools(codemode: CodeMode, server: McpServerLike): void;
30
- /**
31
- * Minimal interface for MCP server tool registration.
32
- * Compatible with `McpServer` from `@modelcontextprotocol/sdk`.
33
- */
34
- interface McpServerLike {
35
- tool(name: string, description: string, schema: Record<string, z.ZodType>, handler: (args: Record<string, unknown>) => Promise<unknown>): void;
36
- }
27
+ declare function registerTools(codemode: CodeMode, server: {
28
+ registerTool: (...args: any[]) => any;
29
+ }): void;
37
30
 
38
31
  export { registerTools };
package/dist/mcp.js CHANGED
@@ -4047,10 +4047,12 @@ var NEVER = INVALID;
4047
4047
  function registerTools(codemode, server) {
4048
4048
  const toolDefs = codemode.tools();
4049
4049
  for (const def of toolDefs) {
4050
- server.tool(
4050
+ server.registerTool(
4051
4051
  def.name,
4052
- def.description,
4053
- { code: external_exports.string().describe("JavaScript code to execute") },
4052
+ {
4053
+ description: def.description,
4054
+ inputSchema: { code: external_exports.string().describe("JavaScript code to execute") }
4055
+ },
4054
4056
  async (args) => {
4055
4057
  return codemode.callTool(def.name, { code: args.code });
4056
4058
  }