From b7a0462286358fc11ca96a300b504d83182dc09e Mon Sep 17 00:00:00 2001 From: Larry-Osakwe Date: Mon, 6 Apr 2026 10:50:17 -0700 Subject: [PATCH 1/4] feat(pi-mono): add @keycardai/pi-mono package for pi-mono agent integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new package that enables pi-mono coding agents to use Keycard-protected MCP servers. Converts MCP tools to pi-mono's AgentTool format, handles OAuth auth detection, and generates auth-aware system prompts. - PiMonoClient: main adapter (detect auth, get tools, system prompt) - Tool conversion: MCP Tool → AgentTool via Type.Unsafe() for schema bridging - Auth tools: pluggable AuthToolHandler with Default/Console implementations - Prompt builder: auth-aware system prompt section generator - Unit tests: 44 tests covering tools, auth, prompt, client - E2E test: local MCP server + InMemoryTransport + pi-mono agent session - SDK re-export via @keycardai/sdk/pi-mono subpath - README: "Which Package?" table for user guidance Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 3 +- README.md | 17 + packages/pi-mono/e2e/e2e.test.ts | 243 +++ packages/pi-mono/jest.config.js | 12 + packages/pi-mono/package.json | 69 + packages/pi-mono/src/auth-tools.test.ts | 134 ++ packages/pi-mono/src/auth-tools.ts | 141 ++ packages/pi-mono/src/client.test.ts | 230 +++ packages/pi-mono/src/client.ts | 249 +++ packages/pi-mono/src/index.ts | 47 + packages/pi-mono/src/prompt.test.ts | 41 + packages/pi-mono/src/prompt.ts | 53 + packages/pi-mono/src/tools.test.ts | 187 ++ packages/pi-mono/src/tools.ts | 152 ++ packages/pi-mono/src/types.ts | 69 + packages/pi-mono/tsconfig.cjs.json | 9 + packages/pi-mono/tsconfig.json | 11 + packages/pi-mono/tsconfig.prod.json | 7 + packages/sdk/package.json | 8 + packages/sdk/src/pi-mono.ts | 20 + pnpm-lock.yaml | 2250 ++++++++++++++++++++++- 21 files changed, 3931 insertions(+), 21 deletions(-) create mode 100644 packages/pi-mono/e2e/e2e.test.ts create mode 100644 packages/pi-mono/jest.config.js create mode 100644 packages/pi-mono/package.json create mode 100644 packages/pi-mono/src/auth-tools.test.ts create mode 100644 packages/pi-mono/src/auth-tools.ts create mode 100644 packages/pi-mono/src/client.test.ts create mode 100644 packages/pi-mono/src/client.ts create mode 100644 packages/pi-mono/src/index.ts create mode 100644 packages/pi-mono/src/prompt.test.ts create mode 100644 packages/pi-mono/src/prompt.ts create mode 100644 packages/pi-mono/src/tools.test.ts create mode 100644 packages/pi-mono/src/tools.ts create mode 100644 packages/pi-mono/src/types.ts create mode 100644 packages/pi-mono/tsconfig.cjs.json create mode 100644 packages/pi-mono/tsconfig.json create mode 100644 packages/pi-mono/tsconfig.prod.json create mode 100644 packages/sdk/src/pi-mono.ts diff --git a/CLAUDE.md b/CLAUDE.md index bb2510c..3885ef9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,6 +6,7 @@ This is a pnpm monorepo with the following packages: - `packages/oauth` (`@keycardai/oauth`) - Pure OAuth 2.0 primitives (no MCP dependency) - `packages/mcp` (`@keycardai/mcp`) - MCP-specific OAuth integration +- `packages/pi-mono` (`@keycardai/pi-mono`) - Pi-mono agent integration (MCP tool → AgentTool conversion, OAuth auth) - `packages/sdk` (`@keycardai/sdk`) - Aggregate package re-exporting from oauth + mcp ## Git Commits @@ -14,7 +15,7 @@ Follow conventional commits: `type(scope): description` Types: `docs`, `feat`, `fix`, `refactor`, `test`, `chore` -Scopes: `oauth`, `mcp`, `sdk`, `deps`, `docs` +Scopes: `oauth`, `mcp`, `pi-mono`, `sdk`, `deps`, `docs` ## Build Order diff --git a/README.md b/README.md index 66939fb..109c3c6 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,17 @@ A collection of TypeScript packages for Keycard services, organized as a pnpm wo |---|---|---| | [`@keycardai/oauth`](packages/oauth/) | Pure OAuth 2.0 primitives — JWKS key management, JWT signing/verification, authorization server discovery | [![npm](https://img.shields.io/npm/v/@keycardai/oauth)](https://www.npmjs.com/package/@keycardai/oauth) | | [`@keycardai/mcp`](packages/mcp/) | MCP OAuth integration — Express middleware, token verification, client providers | [![npm](https://img.shields.io/npm/v/@keycardai/mcp)](https://www.npmjs.com/package/@keycardai/mcp) | +| [`@keycardai/pi-mono`](packages/pi-mono/) | Pi-mono agent integration — MCP tool conversion, OAuth auth, system prompts | [![npm](https://img.shields.io/npm/v/@keycardai/pi-mono)](https://www.npmjs.com/package/@keycardai/pi-mono) | | [`@keycardai/sdk`](packages/sdk/) | Aggregate package re-exporting from oauth + mcp | [![npm](https://img.shields.io/npm/v/@keycardai/sdk)](https://www.npmjs.com/package/@keycardai/sdk) | +## Which Package? + +| You want to... | Install | +|---|---| +| Add auth to your MCP server (Express) | `@keycardai/mcp` | +| Connect to MCP servers from a pi-mono agent | `@keycardai/pi-mono` | +| Use OAuth 2.0 primitives directly | `@keycardai/oauth` | + ## Key Concepts - **Zone** — A Keycard environment that groups your identity providers, MCP resources, and access policies. Get your zone ID from [console.keycard.ai](https://console.keycard.ai). @@ -36,6 +45,14 @@ npm install @keycardai/mcp @modelcontextprotocol/sdk `@keycardai/mcp` requires `@modelcontextprotocol/sdk` as a peer dependency (`^1.15.0`). This includes `@keycardai/oauth` as a dependency. +### For Pi-Mono Agent Integration + +If you're building a pi-mono agent that connects to Keycard-protected MCP servers: + +```bash +npm install @keycardai/pi-mono @mariozechner/pi-agent-core @mariozechner/pi-ai @modelcontextprotocol/sdk @sinclair/typebox +``` + ### For OAuth Functionality Only If you only need OAuth primitives (JWT signing, JWKS key management, discovery): diff --git a/packages/pi-mono/e2e/e2e.test.ts b/packages/pi-mono/e2e/e2e.test.ts new file mode 100644 index 0000000..e04d296 --- /dev/null +++ b/packages/pi-mono/e2e/e2e.test.ts @@ -0,0 +1,243 @@ +/** + * End-to-end test: PiMonoClient + local MCP server + pi-mono agent session. + * + * Spins up an in-process MCP server with a simple tool, connects via + * InMemoryTransport, converts tools through PiMonoClient, and: + * 1. Verifies direct tool execution works (always runs) + * 2. Runs a pi-mono agent session (only with ANTHROPIC_API_KEY) + * + * Run: + * npx tsx e2e/e2e.test.ts # direct execution only + * ANTHROPIC_API_KEY=sk-... npx tsx e2e/e2e.test.ts # full agent session + */ + +import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js"; +import { z } from "zod"; +import { PiMonoClient } from "../src/client.js"; + +// --------------------------------------------------------------------------- +// 1. Create a local MCP server with a simple tool +// --------------------------------------------------------------------------- + +const mcpServer = new McpServer({ name: "test-server", version: "1.0.0" }); + +mcpServer.tool( + "get_greeting", + "Returns a greeting for the given name", + { name: z.string().describe("The name to greet") }, + async ({ name }) => ({ + content: [{ type: "text", text: `Hello, ${name}! Welcome from the MCP server.` }], + }), +); + +mcpServer.tool( + "add_numbers", + "Adds two numbers together", + { a: z.number(), b: z.number() }, + async ({ a, b }) => ({ + content: [{ type: "text", text: String(a + b) }], + }), +); + +// --------------------------------------------------------------------------- +// 2. Connect client ↔ server via in-memory transport +// --------------------------------------------------------------------------- + +const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair(); + +const mcpClient = new Client({ name: "e2e-test", version: "1.0.0" }); + +await mcpServer.server.connect(serverTransport); +await mcpClient.connect(clientTransport); + +console.log("✅ MCP client ↔ server connected via InMemoryTransport"); + +// --------------------------------------------------------------------------- +// 3. Create PiMonoClient and convert tools +// --------------------------------------------------------------------------- + +const adapter = new PiMonoClient({ + servers: [{ name: "test", client: mcpClient }], +}); + +await adapter.detectAuthStatus(); + +const authorizedServers = adapter.getAuthorizedServers(); +const unauthorizedServers = adapter.getUnauthorizedServers(); + +console.log(" Authorized servers:", authorizedServers); +console.log(" Unauthorized servers:", unauthorizedServers); + +if (authorizedServers.length !== 1 || authorizedServers[0] !== "test") { + console.error("❌ Expected 'test' server to be authorized"); + process.exit(1); +} + +const tools = await adapter.getTools(); +console.log(` Converted ${tools.length} tool(s):`, tools.map((t) => t.name)); + +if (tools.length !== 2) { + console.error(`❌ Expected 2 tools, got ${tools.length}`); + process.exit(1); +} + +const systemPrompt = adapter.getSystemPrompt("You are a test assistant."); +if (!systemPrompt.includes("Authorized and available: test")) { + console.error("❌ System prompt missing authorized server info"); + process.exit(1); +} +console.log(" System prompt generated ✅"); + +// --------------------------------------------------------------------------- +// 4. Verify tool execution works directly (no LLM needed) +// --------------------------------------------------------------------------- + +// Test get_greeting +const greetingTool = tools.find((t) => t.name === "test__get_greeting"); +if (!greetingTool) { + console.error("❌ Tool 'test__get_greeting' not found"); + process.exit(1); +} + +const greetResult = await greetingTool.execute("call-1", { name: "Keycard" }); +const greetText = greetResult.content + .filter((c): c is { type: "text"; text: string } => c.type === "text") + .map((c) => c.text) + .join(""); + +if (!greetText.includes("Hello, Keycard!")) { + console.error("❌ get_greeting returned unexpected result:", greetText); + process.exit(1); +} +console.log("✅ get_greeting tool works:", greetText); + +// Test add_numbers +const addTool = tools.find((t) => t.name === "test__add_numbers"); +if (!addTool) { + console.error("❌ Tool 'test__add_numbers' not found"); + process.exit(1); +} + +const addResult = await addTool.execute("call-2", { a: 17, b: 25 }); +const addText = addResult.content + .filter((c): c is { type: "text"; text: string } => c.type === "text") + .map((c) => c.text) + .join(""); + +if (addText !== "42") { + console.error("❌ add_numbers returned unexpected result:", addText); + process.exit(1); +} +console.log("✅ add_numbers tool works: 17 + 25 =", addText); + +// --------------------------------------------------------------------------- +// 5. Test mixed auth scenario +// --------------------------------------------------------------------------- + +const unauthorizedClient = new Client({ name: "unauth-test", version: "1.0.0" }); +// Don't connect — listTools will fail + +const mixedAdapter = new PiMonoClient({ + servers: [ + { name: "authorized", client: mcpClient }, + { name: "unauthorized", client: unauthorizedClient }, + ], + generateAuthUrl: async (name) => `https://auth.example.com/authorize?server=${name}`, +}); + +await mixedAdapter.detectAuthStatus(); + +if (mixedAdapter.getAuthorizedServers().length !== 1) { + console.error("❌ Expected 1 authorized server in mixed scenario"); + process.exit(1); +} +if (mixedAdapter.getUnauthorizedServers().length !== 1) { + console.error("❌ Expected 1 unauthorized server in mixed scenario"); + process.exit(1); +} + +const authTools = await mixedAdapter.getAuthTools(); +if (authTools.length !== 1 || authTools[0].name !== "request_authorization") { + console.error("❌ Expected request_authorization tool"); + process.exit(1); +} + +const mixedPrompt = mixedAdapter.getSystemPrompt(); +if (!mixedPrompt.includes("authorized") || !mixedPrompt.includes("unauthorized")) { + console.error("❌ Mixed prompt missing auth status info"); + process.exit(1); +} +console.log("✅ Mixed auth scenario works correctly"); + +// --------------------------------------------------------------------------- +// 6. Run pi-mono agent session (requires ANTHROPIC_API_KEY) +// --------------------------------------------------------------------------- + +if (!process.env.ANTHROPIC_API_KEY) { + console.log("\n⏭️ Skipping agent session test (no ANTHROPIC_API_KEY set)"); + console.log(" Set ANTHROPIC_API_KEY to run the full LLM-powered e2e test.\n"); + await cleanup(); + console.log("\n✅ E2E test passed (direct execution)"); + process.exit(0); +} + +console.log("\n🤖 Starting pi-mono agent session with LLM..."); + +// Dynamic import — only when we actually need it (avoids resolution errors +// when @mariozechner/pi-coding-agent is a peer dep, not installed directly) +const { + createAgentSession, + SessionManager, + AuthStorage, + ModelRegistry, +} = await import("@mariozechner/pi-coding-agent"); + +const authStorage = AuthStorage.create(); +authStorage.setRuntimeApiKey("anthropic", process.env.ANTHROPIC_API_KEY); +const modelRegistry = ModelRegistry.create(authStorage); + +const { session } = await createAgentSession({ + sessionManager: SessionManager.inMemory(), + authStorage, + modelRegistry, + tools, + systemPrompt: `You are a test assistant. ${systemPrompt}\n\nIMPORTANT: When asked to greet someone, use the test__get_greeting tool. Respond with ONLY the tool's output, nothing else.`, +}); + +let agentOutput = ""; + +session.subscribe((event: Record) => { + if ( + event.type === "message_update" && + typeof event.assistantMessageEvent === "object" && + event.assistantMessageEvent !== null + ) { + const ame = event.assistantMessageEvent as Record; + if (ame.type === "text_delta" && typeof ame.delta === "string") { + agentOutput += ame.delta; + } + } +}); + +await session.prompt("Greet someone named 'E2E Test'."); + +console.log(" Agent output:", agentOutput.trim()); + +if (agentOutput.includes("Hello, E2E Test!")) { + console.log("✅ Full e2e test passed — agent used MCP tool via PiMonoClient"); +} else { + console.log("⚠️ Agent responded but may not have used the tool. Output above."); +} + +// --------------------------------------------------------------------------- +// Cleanup +// --------------------------------------------------------------------------- + +async function cleanup() { + await mcpClient.close(); + await mcpServer.server.close(); +} + +await cleanup(); diff --git a/packages/pi-mono/jest.config.js b/packages/pi-mono/jest.config.js new file mode 100644 index 0000000..6a8f3cd --- /dev/null +++ b/packages/pi-mono/jest.config.js @@ -0,0 +1,12 @@ +import { createDefaultEsmPreset } from "ts-jest"; + +const defaultEsmPreset = createDefaultEsmPreset(); + +/** @type {import('ts-jest').JestConfigWithTsJest} **/ +export default { + ...defaultEsmPreset, + moduleNameMapper: { + "^(\\.{1,2}/.*)\\.js$": "$1", + }, + testPathIgnorePatterns: ["/node_modules/", "/dist/", "/e2e/"], +}; diff --git a/packages/pi-mono/package.json b/packages/pi-mono/package.json new file mode 100644 index 0000000..df8e963 --- /dev/null +++ b/packages/pi-mono/package.json @@ -0,0 +1,69 @@ +{ + "name": "@keycardai/pi-mono", + "version": "0.1.0", + "description": "Pi-mono (coding agent) integration for Keycard — converts MCP tools to pi-mono AgentTool format with OAuth authentication", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+https://github.com/keycardai/typescript-sdk.git", + "directory": "packages/pi-mono" + }, + "type": "module", + "exports": { + ".": { + "import": "./dist/esm/index.js", + "require": "./dist/cjs/index.js", + "types": "./dist/esm/index.d.ts" + }, + "./auth-tools": { + "import": "./dist/esm/auth-tools.js", + "require": "./dist/cjs/auth-tools.js", + "types": "./dist/esm/auth-tools.d.ts" + }, + "./tools": { + "import": "./dist/esm/tools.js", + "require": "./dist/cjs/tools.js", + "types": "./dist/esm/tools.d.ts" + } + }, + "files": [ + "dist" + ], + "typesVersions": { + "*": { + "*": [ + "./dist/esm/*" + ] + } + }, + "scripts": { + "build": "pnpm run build:esm && pnpm run build:cjs", + "build:esm": "tsc -p tsconfig.prod.json && echo '{\"type\": \"module\"}' > dist/esm/package.json", + "build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > dist/cjs/package.json", + "test": "NODE_OPTIONS='--experimental-vm-modules' jest --passWithNoTests", + "test:e2e": "npx tsx e2e/e2e.test.ts", + "typecheck": "tsc --noEmit", + "clean": "rm -rf dist" + }, + "dependencies": { + "@keycardai/oauth": "workspace:*" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.15.0", + "@mariozechner/pi-agent-core": ">=0.60.0", + "@mariozechner/pi-ai": ">=0.60.0", + "@sinclair/typebox": ">=0.30.0" + }, + "devDependencies": { + "@jest/globals": "^30.0.4", + "@mariozechner/pi-agent-core": ">=0.60.0", + "@mariozechner/pi-ai": ">=0.60.0", + "@mariozechner/pi-coding-agent": ">=0.60.0", + "@modelcontextprotocol/sdk": "^1.15.0", + "@sinclair/typebox": ">=0.30.0", + "jest": "^30.0.4", + "ts-jest": "^29.4.0", + "typescript": "^5.8.3", + "zod": "^3.25.0" + } +} diff --git a/packages/pi-mono/src/auth-tools.test.ts b/packages/pi-mono/src/auth-tools.test.ts new file mode 100644 index 0000000..6fb17d2 --- /dev/null +++ b/packages/pi-mono/src/auth-tools.test.ts @@ -0,0 +1,134 @@ +import { jest } from "@jest/globals"; +import { + DefaultAuthToolHandler, + ConsoleAuthToolHandler, + createAuthRequestTool, +} from "./auth-tools.js"; +import type { AuthToolHandler } from "./types.js"; + +// --------------------------------------------------------------------------- +// DefaultAuthToolHandler +// --------------------------------------------------------------------------- + +describe("DefaultAuthToolHandler", () => { + const handler = new DefaultAuthToolHandler(); + + it("returns auth URL message with reason", async () => { + const msg = await handler.handleAuthRequest("github", "https://auth.example.com", "needs PR access"); + expect(msg).toContain("github"); + expect(msg).toContain("https://auth.example.com"); + expect(msg).toContain("needs PR access"); + }); + + it("returns auth URL message without reason", async () => { + const msg = await handler.handleAuthRequest("github", "https://auth.example.com"); + expect(msg).toContain("github"); + expect(msg).toContain("https://auth.example.com"); + expect(msg).not.toContain("undefined"); + }); + + it("returns error message", async () => { + const msg = await handler.handleAuthError!("github", new Error("timeout")); + expect(msg).toContain("github"); + expect(msg).toContain("timeout"); + }); +}); + +// --------------------------------------------------------------------------- +// ConsoleAuthToolHandler +// --------------------------------------------------------------------------- + +describe("ConsoleAuthToolHandler", () => { + const handler = new ConsoleAuthToolHandler(); + + it("prints to console and returns confirmation", async () => { + const logSpy = jest.spyOn(console, "log").mockImplementation(() => {}); + const msg = await handler.handleAuthRequest("slack", "https://auth.example.com/slack"); + expect(logSpy).toHaveBeenCalled(); + expect(msg).toContain("printed to the console"); + logSpy.mockRestore(); + }); + + it("prints error to stderr", async () => { + const errorSpy = jest.spyOn(console, "error").mockImplementation(() => {}); + await handler.handleAuthError!("slack", new Error("failed")); + expect(errorSpy).toHaveBeenCalled(); + errorSpy.mockRestore(); + }); +}); + +// --------------------------------------------------------------------------- +// createAuthRequestTool +// --------------------------------------------------------------------------- + +describe("createAuthRequestTool", () => { + const mockHandler: AuthToolHandler = { + handleAuthRequest: jest.fn() + .mockResolvedValue("Please visit the auth link"), + handleAuthError: jest.fn>() + .mockResolvedValue("Auth failed"), + }; + + const generateAuthUrl = jest.fn<(name: string) => Promise>() + .mockResolvedValue("https://auth.example.com/authorize?server=github"); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("creates a tool with correct metadata", () => { + const tool = createAuthRequestTool(["github", "slack"], mockHandler, generateAuthUrl); + expect(tool.name).toBe("request_authorization"); + expect(tool.label).toBe("Request Authorization"); + expect(tool.description).toContain("github, slack"); + }); + + it("calls generateAuthUrl and handler on execute", async () => { + const tool = createAuthRequestTool(["github"], mockHandler, generateAuthUrl); + const result = await tool.execute("call-1", { service: "github", reason: "need PRs" }); + + expect(generateAuthUrl).toHaveBeenCalledWith("github"); + expect(mockHandler.handleAuthRequest).toHaveBeenCalledWith( + "github", + "https://auth.example.com/authorize?server=github", + "need PRs", + ); + expect(result.content[0]).toEqual({ type: "text", text: "Please visit the auth link" }); + }); + + it("rejects unknown services", async () => { + const tool = createAuthRequestTool(["github"], mockHandler, generateAuthUrl); + const result = await tool.execute("call-1", { service: "unknown" }); + + expect(generateAuthUrl).not.toHaveBeenCalled(); + expect(result.content[0]).toEqual( + expect.objectContaining({ + type: "text", + text: expect.stringContaining("not in the list"), + }), + ); + }); + + it("handles generateAuthUrl errors gracefully", async () => { + const failingGenerate = jest.fn<(name: string) => Promise>() + .mockRejectedValue(new Error("network error")); + const tool = createAuthRequestTool(["github"], mockHandler, failingGenerate); + const result = await tool.execute("call-1", { service: "github" }); + + expect(mockHandler.handleAuthError).toHaveBeenCalledWith("github", expect.any(Error)); + expect(result.content[0]).toEqual({ type: "text", text: "Auth failed" }); + }); + + it("handles missing params gracefully", async () => { + const tool = createAuthRequestTool(["github"], mockHandler, generateAuthUrl); + const result = await tool.execute("call-1", null); + + // Empty string from typeof check — won't match any server + expect(result.content[0]).toEqual( + expect.objectContaining({ + type: "text", + text: expect.stringContaining("not in the list"), + }), + ); + }); +}); diff --git a/packages/pi-mono/src/auth-tools.ts b/packages/pi-mono/src/auth-tools.ts new file mode 100644 index 0000000..4fb69c1 --- /dev/null +++ b/packages/pi-mono/src/auth-tools.ts @@ -0,0 +1,141 @@ +/** + * Auth tool handlers and the "request_authorization" AgentTool. + * + * Follows the same pluggable AuthToolHandler pattern as the Python SDK. + * The agent can call request_authorization to trigger an OAuth flow + * for a server that hasn't been authorized yet. + */ + +import { Type } from "@sinclair/typebox"; +import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; +import type { AuthToolHandler } from "./types.js"; + +// --------------------------------------------------------------------------- +// Built-in AuthToolHandler implementations +// --------------------------------------------------------------------------- + +/** + * Default auth handler — returns the auth URL as a message string. + * The agent can then display this to the user in whatever UI it's running in. + */ +export class DefaultAuthToolHandler implements AuthToolHandler { + async handleAuthRequest( + serverName: string, + authUrl: string, + reason?: string, + ): Promise { + const msg = reason + ? `To use ${serverName} (${reason}), please authorize by visiting:\n${authUrl}` + : `To use ${serverName}, please authorize by visiting:\n${authUrl}`; + return msg; + } + + async handleAuthError(serverName: string, error: Error): Promise { + return `Failed to generate authorization link for ${serverName}: ${error.message}`; + } +} + +/** + * Console auth handler — prints the auth URL to stdout. + * Suitable for CLI applications. + */ +export class ConsoleAuthToolHandler implements AuthToolHandler { + async handleAuthRequest( + serverName: string, + authUrl: string, + reason?: string, + ): Promise { + const header = reason + ? `\n🔑 Authorize ${serverName} (${reason}):` + : `\n🔑 Authorize ${serverName}:`; + console.log(header); + console.log(` ${authUrl}\n`); + return `Authorization link for ${serverName} has been printed to the console.`; + } + + async handleAuthError(serverName: string, error: Error): Promise { + console.error(`\n❌ Auth error for ${serverName}: ${error.message}\n`); + return `Failed to generate authorization link for ${serverName}: ${error.message}`; + } +} + +// --------------------------------------------------------------------------- +// Auth AgentTool factory +// --------------------------------------------------------------------------- + +/** + * Create a pi-mono AgentTool that the agent can call to request OAuth + * authorization for a pending server. + * + * @param unauthorizedServers - Names of servers that need authorization. + * @param authHandler - Handler that delivers the auth link to the user. + * @param generateAuthUrl - Function that generates the OAuth authorization URL for a server. + * @returns An AgentTool the agent can invoke to request authorization. + */ +export function createAuthRequestTool( + unauthorizedServers: string[], + authHandler: AuthToolHandler, + generateAuthUrl: (serverName: string) => Promise, +): AgentTool { + const serviceList = unauthorizedServers.join(", "); + + return { + name: "request_authorization", + description: + `Request user authorization for services that need it. ` + + `Available services: ${serviceList}. ` + + `Call this when the user wants to use one of these services.`, + label: "Request Authorization", + parameters: Type.Object({ + service: Type.String({ + description: `The service to authorize. One of: ${serviceList}`, + }), + reason: Type.Optional( + Type.String({ + description: "Why the agent needs access to this service.", + }), + ), + }), + + async execute( + _toolCallId: string, + params: unknown, + ): Promise> { + const p = (params != null && typeof params === "object" ? params : {}) as Record; + const service = typeof p.service === "string" ? p.service : ""; + const reason = typeof p.reason === "string" ? p.reason : undefined; + + if (!unauthorizedServers.includes(service)) { + return { + content: [ + { + type: "text", + text: `Service "${service}" is not in the list of unauthorized services. Available: ${serviceList}`, + }, + ], + details: undefined, + }; + } + + try { + const authUrl = await generateAuthUrl(service); + const message = await authHandler.handleAuthRequest(service, authUrl, reason); + return { + content: [{ type: "text", text: message }], + details: undefined, + }; + } catch (error) { + const errMessage = authHandler.handleAuthError + ? await authHandler.handleAuthError( + service, + error instanceof Error ? error : new Error(String(error)), + ) + : `Failed to generate auth link for ${service}: ${error}`; + return { + content: [{ type: "text", text: errMessage }], + details: undefined, + }; + } + }, + }; +} diff --git a/packages/pi-mono/src/client.test.ts b/packages/pi-mono/src/client.test.ts new file mode 100644 index 0000000..76df1b5 --- /dev/null +++ b/packages/pi-mono/src/client.test.ts @@ -0,0 +1,230 @@ +import { jest } from "@jest/globals"; +import { PiMonoClient } from "./client.js"; +import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import type { AuthToolHandler } from "./types.js"; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function makeMockClient(authorized: boolean): Client { + const listTools = authorized + ? jest.fn().mockResolvedValue({ + tools: [ + { + name: "list_repos", + description: "List repos", + inputSchema: { type: "object" as const }, + }, + ], + }) + : jest.fn().mockRejectedValue(new Error("Unauthorized")); + + const callTool = jest.fn().mockResolvedValue({ + content: [{ type: "text", text: "ok" }], + }); + + return { listTools, callTool } as unknown as Client; +} + +// --------------------------------------------------------------------------- +// PiMonoClient +// --------------------------------------------------------------------------- + +describe("PiMonoClient", () => { + describe("detectAuthStatus", () => { + it("marks servers as authorized when listTools succeeds", async () => { + const client = new PiMonoClient({ + servers: [{ name: "github", client: makeMockClient(true) }], + }); + + await client.detectAuthStatus(); + + expect(client.getAuthorizedServers()).toEqual(["github"]); + expect(client.getUnauthorizedServers()).toEqual([]); + }); + + it("marks servers as unauthorized when listTools fails", async () => { + const client = new PiMonoClient({ + servers: [{ name: "github", client: makeMockClient(false) }], + }); + + await client.detectAuthStatus(); + + expect(client.getAuthorizedServers()).toEqual([]); + expect(client.getUnauthorizedServers()).toEqual(["github"]); + }); + + it("handles mixed authorized/unauthorized servers", async () => { + const client = new PiMonoClient({ + servers: [ + { name: "github", client: makeMockClient(true) }, + { name: "slack", client: makeMockClient(false) }, + { name: "linear", client: makeMockClient(true) }, + ], + }); + + await client.detectAuthStatus(); + + expect(client.getAuthorizedServers()).toEqual(["github", "linear"]); + expect(client.getUnauthorizedServers()).toEqual(["slack"]); + }); + + it("clears previous state on re-detect", async () => { + const toggleClient = makeMockClient(false); + const client = new PiMonoClient({ + servers: [{ name: "github", client: toggleClient }], + }); + + await client.detectAuthStatus(); + expect(client.getUnauthorizedServers()).toEqual(["github"]); + + // Now make it succeed + (toggleClient.listTools as jest.Mock).mockResolvedValue({ tools: [] }); + await client.detectAuthStatus(); + expect(client.getAuthorizedServers()).toEqual(["github"]); + expect(client.getUnauthorizedServers()).toEqual([]); + }); + }); + + describe("getTools", () => { + it("returns converted tools from authorized servers only", async () => { + const client = new PiMonoClient({ + servers: [ + { name: "github", client: makeMockClient(true) }, + { name: "slack", client: makeMockClient(false) }, + ], + }); + await client.detectAuthStatus(); + + const tools = await client.getTools(); + + expect(tools).toHaveLength(1); + expect(tools[0].name).toBe("github__list_repos"); + }); + + it("caches tools on subsequent calls", async () => { + const mockClient = makeMockClient(true); + const client = new PiMonoClient({ + servers: [{ name: "github", client: mockClient }], + }); + await client.detectAuthStatus(); + + const tools1 = await client.getTools(); + const tools2 = await client.getTools(); + + expect(tools1).toBe(tools2); // Same reference = cached + // listTools called once during detectAuthStatus + once during getTools + expect(mockClient.listTools).toHaveBeenCalledTimes(2); + }); + + it("clears cache on clearCache()", async () => { + const mockClient = makeMockClient(true); + const client = new PiMonoClient({ + servers: [{ name: "github", client: mockClient }], + }); + await client.detectAuthStatus(); + + await client.getTools(); + client.clearCache(); + await client.getTools(); + + // detectAuthStatus(1) + getTools(1) + getTools after clear(1) + expect(mockClient.listTools).toHaveBeenCalledTimes(3); + }); + + it("returns empty array when no servers are authorized", async () => { + const client = new PiMonoClient({ + servers: [{ name: "github", client: makeMockClient(false) }], + }); + await client.detectAuthStatus(); + + const tools = await client.getTools(); + expect(tools).toEqual([]); + }); + }); + + describe("getAuthTools", () => { + it("returns auth tool when servers are unauthorized and generateAuthUrl provided", async () => { + const client = new PiMonoClient({ + servers: [{ name: "github", client: makeMockClient(false) }], + generateAuthUrl: async () => "https://auth.example.com", + }); + await client.detectAuthStatus(); + + const authTools = await client.getAuthTools(); + + expect(authTools).toHaveLength(1); + expect(authTools[0].name).toBe("request_authorization"); + }); + + it("returns empty when all servers authorized", async () => { + const client = new PiMonoClient({ + servers: [{ name: "github", client: makeMockClient(true) }], + generateAuthUrl: async () => "https://auth.example.com", + }); + await client.detectAuthStatus(); + + const authTools = await client.getAuthTools(); + expect(authTools).toEqual([]); + }); + + it("returns empty when no generateAuthUrl provided", async () => { + const client = new PiMonoClient({ + servers: [{ name: "github", client: makeMockClient(false) }], + }); + await client.detectAuthStatus(); + + const authTools = await client.getAuthTools(); + expect(authTools).toEqual([]); + }); + }); + + describe("getSystemPrompt", () => { + it("includes authorized and unauthorized servers", async () => { + const client = new PiMonoClient({ + servers: [ + { name: "github", client: makeMockClient(true) }, + { name: "slack", client: makeMockClient(false) }, + ], + }); + await client.detectAuthStatus(); + + const prompt = client.getSystemPrompt(); + + expect(prompt).toContain("github"); + expect(prompt).toContain("slack"); + expect(prompt).toContain("Authorized and available"); + expect(prompt).toContain("Not yet authorized"); + }); + + it("prepends base instructions", async () => { + const client = new PiMonoClient({ + servers: [{ name: "github", client: makeMockClient(true) }], + }); + await client.detectAuthStatus(); + + const prompt = client.getSystemPrompt("You are a helpful assistant."); + expect(prompt).toMatch(/^You are a helpful assistant\./); + }); + }); + + describe("getServerStates", () => { + it("returns readonly map of all server states", async () => { + const client = new PiMonoClient({ + servers: [ + { name: "github", client: makeMockClient(true) }, + { name: "slack", client: makeMockClient(false) }, + ], + }); + await client.detectAuthStatus(); + + const states = client.getServerStates(); + + expect(states.size).toBe(2); + expect(states.get("github")?.status).toBe("authorized"); + expect(states.get("slack")?.status).toBe("unauthorized"); + expect(states.get("slack")?.error).toBe("Unauthorized"); + }); + }); +}); diff --git a/packages/pi-mono/src/client.ts b/packages/pi-mono/src/client.ts new file mode 100644 index 0000000..4c7f59a --- /dev/null +++ b/packages/pi-mono/src/client.ts @@ -0,0 +1,249 @@ +/** + * PiMonoClient — main adapter for using Keycard-protected MCP servers + * with the pi-mono coding agent framework. + * + * Manages MCP server connections, converts tools to pi-mono AgentTool format, + * handles OAuth auth status, and generates auth-aware system prompts. + */ + +import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import type { AgentTool } from "@mariozechner/pi-agent-core"; +import type { + ServerState, + AuthToolHandler, +} from "./types.js"; +import { convertServerTools } from "./tools.js"; +import { DefaultAuthToolHandler, createAuthRequestTool } from "./auth-tools.js"; +import { buildSystemPromptSection } from "./prompt.js"; + +// --------------------------------------------------------------------------- +// Server connection descriptor +// --------------------------------------------------------------------------- + +/** + * A connected MCP server with its client instance. + * Users create these by setting up MCP Client + Transport themselves, + * then pass them to PiMonoClient. + */ +export interface ConnectedServer { + /** Unique name for this server (used as tool prefix). */ + name: string; + /** The connected MCP Client instance. */ + client: Client; +} + +/** Options for creating a PiMonoClient. */ +export interface PiMonoClientConfig { + /** + * List of Keycard-protected MCP servers to configure. + * These are server descriptors — not yet connected. + * The client will attempt to list tools from each to detect auth status. + */ + servers: ConnectedServer[]; + + /** + * Pluggable handler for delivering OAuth authorization links to the user. + * Defaults to DefaultAuthToolHandler (returns URL string for agent to display). + */ + authHandler?: AuthToolHandler; + + /** + * Function to generate an OAuth authorization URL for a server. + * Called when the agent invokes the request_authorization tool. + * + * This is application-specific — you'll typically discover the server's + * authorization endpoint and build a PKCE auth URL. + */ + generateAuthUrl?: (serverName: string) => Promise; +} + +/** + * PiMonoClient — adapter for using Keycard-protected MCP servers + * with pi-mono's coding agent. + * + * Usage: + * ```typescript + * // 1. Set up MCP clients for each server (with Keycard OAuth transports) + * const githubClient = new Client({ name: "github", version: "1.0" }); + * await githubClient.connect(githubTransport); + * + * // 2. Create the adapter + * const adapter = new PiMonoClient({ + * servers: [{ name: "github", client: githubClient }], + * }); + * + * // 3. Detect auth status + * await adapter.detectAuthStatus(); + * + * // 4. Get pi-mono tools and system prompt + * const tools = await adapter.getTools(); + * const authTools = await adapter.getAuthTools(); + * const prompt = adapter.getSystemPrompt("You are a helpful assistant."); + * ``` + */ +export class PiMonoClient { + readonly #servers: ConnectedServer[]; + readonly #authHandler: AuthToolHandler; + readonly #generateAuthUrl?: (serverName: string) => Promise; + + #serverStates: Map = new Map(); + #toolsCache: AgentTool[] | undefined; + + constructor(config: PiMonoClientConfig) { + this.#servers = config.servers; + this.#authHandler = config.authHandler ?? new DefaultAuthToolHandler(); + this.#generateAuthUrl = config.generateAuthUrl; + } + + /** + * Detect auth status of each server by attempting to list tools. + * + * Servers that respond successfully are marked "authorized". + * Servers that throw (auth required, network error, etc.) are marked accordingly. + * + * Call this after connecting your MCP clients but before calling getTools(). + */ + async detectAuthStatus(): Promise { + this.#serverStates.clear(); + this.#toolsCache = undefined; + + const results = await Promise.allSettled( + this.#servers.map(async (server) => { + try { + // Attempt to list tools — this will fail if not authorized + await server.client.listTools(); + return { server, status: "authorized" as const, error: undefined }; + } catch (error) { + return { + server, + status: "unauthorized" as const, + error: error instanceof Error ? error.message : String(error), + }; + } + }), + ); + + for (const result of results) { + if (result.status === "fulfilled") { + const { server, status, error } = result.value; + this.#serverStates.set(server.name, { + name: server.name, + status, + client: status === "authorized" ? server.client : undefined, + error, + }); + } else { + // Promise.allSettled rejected — shouldn't happen but handle gracefully + console.error("Unexpected server detection failure:", result.reason); + } + } + } + + /** + * Get MCP tools converted to pi-mono AgentTool[] format. + * + * Only returns tools from authorized servers. Tools are prefixed with the + * server name (e.g., "github__list_repos") to avoid naming collisions. + * + * Results are cached — call detectAuthStatus() again to refresh. + */ + async getTools(): Promise { + if (this.#toolsCache) { + return this.#toolsCache; + } + + const tools: AgentTool[] = []; + + for (const [name, state] of this.#serverStates) { + if (state.status !== "authorized" || !state.client) continue; + + try { + const serverTools = await convertServerTools(name, state.client); + tools.push(...serverTools); + } catch (error) { + console.error(`Failed to list tools for ${name}:`, error); + } + } + + this.#toolsCache = tools; + return tools; + } + + /** + * Get auth request tools for unauthorized servers. + * + * Returns a single "request_authorization" AgentTool if any servers + * need authorization. The agent can call this to trigger OAuth flows. + * + * Returns an empty array if all servers are authorized or if no + * generateAuthUrl function was provided. + */ + async getAuthTools(): Promise { + const unauthorized = this.getUnauthorizedServers(); + if (unauthorized.length === 0 || !this.#generateAuthUrl) { + return []; + } + + return [ + createAuthRequestTool( + unauthorized, + this.#authHandler, + this.#generateAuthUrl, + ), + ]; + } + + /** + * Generate an auth-aware system prompt section. + * + * Lists which servers are authorized and available, and which need + * authorization. Instructs the agent to use request_authorization + * for pending servers. + * + * @param baseInstructions - Optional base instructions to prepend. + */ + getSystemPrompt(baseInstructions?: string): string { + return buildSystemPromptSection( + this.getAuthorizedServers(), + this.getUnauthorizedServers(), + baseInstructions, + ); + } + + /** Get names of servers that are connected and authorized. */ + getAuthorizedServers(): string[] { + const names: string[] = []; + for (const [name, state] of this.#serverStates) { + if (state.status === "authorized") names.push(name); + } + return names; + } + + /** Get names of servers that need OAuth authorization. */ + getUnauthorizedServers(): string[] { + const names: string[] = []; + for (const [name, state] of this.#serverStates) { + if (state.status === "unauthorized") names.push(name); + } + return names; + } + + /** Get names of servers that had connection errors. */ + getErrorServers(): string[] { + const names: string[] = []; + for (const [name, state] of this.#serverStates) { + if (state.status === "error") names.push(name); + } + return names; + } + + /** Get the full state map for all servers. */ + getServerStates(): ReadonlyMap { + return this.#serverStates; + } + + /** Clear the tools cache, forcing re-fetch on next getTools() call. */ + clearCache(): void { + this.#toolsCache = undefined; + } +} diff --git a/packages/pi-mono/src/index.ts b/packages/pi-mono/src/index.ts new file mode 100644 index 0000000..3e7610d --- /dev/null +++ b/packages/pi-mono/src/index.ts @@ -0,0 +1,47 @@ +/** + * @keycardai/pi-mono — Pi-mono (coding agent) integration for Keycard. + * + * Converts MCP tools from Keycard-protected servers into pi-mono AgentTool + * instances with OAuth auth handling and auth-aware system prompts. + * + * @example + * ```typescript + * import { PiMonoClient } from "@keycardai/pi-mono"; + * import { createAgentSession, SessionManager } from "@mariozechner/pi-coding-agent"; // or pi-agent-core + * + * const adapter = new PiMonoClient({ + * servers: [{ name: "github", client: githubMcpClient }], + * }); + * await adapter.detectAuthStatus(); + * + * const tools = await adapter.getTools(); + * const authTools = await adapter.getAuthTools(); + * const prompt = adapter.getSystemPrompt("You are a helpful assistant."); + * + * const { session } = await createAgentSession({ + * tools: [...tools, ...authTools], + * systemPrompt: prompt, + * sessionManager: SessionManager.inMemory(), + * }); + * ``` + */ + +// Main client +export { PiMonoClient } from "./client.js"; +export type { ConnectedServer, PiMonoClientConfig } from "./client.js"; + +// Auth tool handlers +export { DefaultAuthToolHandler, ConsoleAuthToolHandler, createAuthRequestTool } from "./auth-tools.js"; + +// Tool conversion utilities +export { convertMcpToolToAgentTool, convertServerTools, jsonSchemaToTypeBox } from "./tools.js"; + +// Prompt builder +export { buildSystemPromptSection } from "./prompt.js"; + +// Types +export type { + ServerAuthStatus, + ServerState, + AuthToolHandler, +} from "./types.js"; diff --git a/packages/pi-mono/src/prompt.test.ts b/packages/pi-mono/src/prompt.test.ts new file mode 100644 index 0000000..077c4cc --- /dev/null +++ b/packages/pi-mono/src/prompt.test.ts @@ -0,0 +1,41 @@ +import { buildSystemPromptSection } from "./prompt.js"; + +describe("buildSystemPromptSection", () => { + it("lists authorized servers", () => { + const result = buildSystemPromptSection(["github", "slack"], []); + expect(result).toContain("Authorized and available: github, slack"); + }); + + it("lists unauthorized servers with instructions", () => { + const result = buildSystemPromptSection([], ["linear"]); + expect(result).toContain("Not yet authorized (tools unavailable): linear"); + expect(result).toContain("request_authorization"); + }); + + it("shows both authorized and unauthorized", () => { + const result = buildSystemPromptSection(["github"], ["linear", "slack"]); + expect(result).toContain("Authorized and available: github"); + expect(result).toContain("Not yet authorized (tools unavailable): linear, slack"); + }); + + it("shows no-servers-configured when both lists empty", () => { + const result = buildSystemPromptSection([], []); + expect(result).toContain("No MCP servers are configured"); + }); + + it("shows none-authorized message when only unauthorized exist", () => { + const result = buildSystemPromptSection([], ["github"]); + expect(result).toContain("No MCP servers are currently authorized"); + }); + + it("prepends base instructions", () => { + const result = buildSystemPromptSection(["github"], [], "You are a helpful bot."); + expect(result).toMatch(/^You are a helpful bot\./); + expect(result).toContain("Authorized and available: github"); + }); + + it("always includes the header", () => { + const result = buildSystemPromptSection(["github"], []); + expect(result).toContain("## MCP Server Status"); + }); +}); diff --git a/packages/pi-mono/src/prompt.ts b/packages/pi-mono/src/prompt.ts new file mode 100644 index 0000000..967c820 --- /dev/null +++ b/packages/pi-mono/src/prompt.ts @@ -0,0 +1,53 @@ +/** + * Auth-aware system prompt generation. + * + * Generates a section to append to the agent's system prompt + * that describes which MCP servers are available vs pending authorization. + */ + +/** + * Build a system prompt section describing MCP server auth status. + * + * @param authorizedServers - Names of servers that are connected and authorized. + * @param unauthorizedServers - Names of servers that need OAuth authorization. + * @param baseInstructions - Optional base instructions to prepend. + * @returns A system prompt string to append to the agent's instructions. + */ +export function buildSystemPromptSection( + authorizedServers: string[], + unauthorizedServers: string[], + baseInstructions?: string, +): string { + const lines: string[] = []; + + if (baseInstructions) { + lines.push(baseInstructions, ""); + } + + lines.push("## MCP Server Status"); + + if (authorizedServers.length > 0) { + lines.push(`Authorized and available: ${authorizedServers.join(", ")}`); + } + + if (unauthorizedServers.length > 0) { + lines.push( + `Not yet authorized (tools unavailable): ${unauthorizedServers.join(", ")}`, + "", + "When the user asks about or needs an unauthorized service, use the", + "request_authorization tool to initiate the OAuth flow for that service.", + ); + } + + if (authorizedServers.length === 0 && unauthorizedServers.length === 0) { + lines.push("No MCP servers are configured."); + } else if (authorizedServers.length === 0) { + lines.push( + "", + "No MCP servers are currently authorized.", + "Use the request_authorization tool when the user wants to connect a service.", + ); + } + + return lines.join("\n"); +} diff --git a/packages/pi-mono/src/tools.test.ts b/packages/pi-mono/src/tools.test.ts new file mode 100644 index 0000000..046e88a --- /dev/null +++ b/packages/pi-mono/src/tools.test.ts @@ -0,0 +1,187 @@ +import { jest } from "@jest/globals"; +import { jsonSchemaToTypeBox, convertMcpToolToAgentTool, convertServerTools } from "./tools.js"; +import { Kind } from "@sinclair/typebox"; +import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import type { Tool } from "@modelcontextprotocol/sdk/types.js"; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function makeMcpTool(overrides: Partial = {}): Tool { + return { + name: "list_repos", + description: "List repositories", + inputSchema: { + type: "object" as const, + properties: { + owner: { type: "string", description: "The owner" }, + }, + required: ["owner"], + }, + ...overrides, + }; +} + +function makeMockClient(overrides: Partial = {}): Client { + return { + callTool: jest.fn(), + listTools: jest.fn(), + ...overrides, + } as unknown as Client; +} + +// --------------------------------------------------------------------------- +// jsonSchemaToTypeBox +// --------------------------------------------------------------------------- + +describe("jsonSchemaToTypeBox", () => { + it("returns an empty Type.Object for undefined input", () => { + const schema = jsonSchemaToTypeBox(undefined); + expect(schema[Kind]).toBe("Object"); + }); + + it("wraps a JSON schema via Type.Unsafe", () => { + const inputSchema = { + type: "object" as const, + properties: { name: { type: "string" } }, + }; + const schema = jsonSchemaToTypeBox(inputSchema); + // Type.Unsafe preserves the original schema properties + expect(schema.type).toBe("object"); + expect(schema.properties).toEqual({ name: { type: "string" } }); + }); +}); + +// --------------------------------------------------------------------------- +// convertMcpToolToAgentTool +// --------------------------------------------------------------------------- + +describe("convertMcpToolToAgentTool", () => { + it("sets name with server prefix", () => { + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", makeMockClient()); + expect(tool.name).toBe("github__list_repos"); + }); + + it("sets label and description", () => { + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", makeMockClient()); + expect(tool.label).toBe("github: list_repos"); + expect(tool.description).toBe("List repositories"); + }); + + it("uses fallback description when none provided", () => { + const mcpTool = makeMcpTool({ description: undefined }); + const tool = convertMcpToolToAgentTool(mcpTool, "github", makeMockClient()); + expect(tool.description).toBe("Tool from github"); + }); + + it("converts inputSchema to TypeBox", () => { + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", makeMockClient()); + expect(tool.parameters.type).toBe("object"); + }); + + it("calls client.callTool on execute with correct arguments", async () => { + const callTool = jest.fn().mockResolvedValue({ + content: [{ type: "text", text: "result text" }], + }); + const client = makeMockClient({ callTool }); + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", client); + + const result = await tool.execute("call-1", { owner: "keycardai" }); + + expect(callTool).toHaveBeenCalledWith( + { name: "list_repos", arguments: { owner: "keycardai" } }, + undefined, + { signal: undefined }, + ); + expect(result.content).toEqual([{ type: "text", text: "result text" }]); + expect(result.details).toBeUndefined(); + }); + + it("handles null params", async () => { + const callTool = jest.fn().mockResolvedValue({ + content: [{ type: "text", text: "ok" }], + }); + const client = makeMockClient({ callTool }); + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", client); + + await tool.execute("call-1", null); + + expect(callTool).toHaveBeenCalledWith( + { name: "list_repos", arguments: undefined }, + undefined, + { signal: undefined }, + ); + }); + + it("converts image content blocks", async () => { + const callTool = jest.fn().mockResolvedValue({ + content: [{ type: "image", data: "base64data", mimeType: "image/png" }], + }); + const client = makeMockClient({ callTool }); + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", client); + + const result = await tool.execute("call-1", {}); + + expect(result.content).toEqual([ + { type: "image", data: "base64data", mimeType: "image/png" }, + ]); + }); + + it("returns fallback text when content is empty", async () => { + const callTool = jest.fn().mockResolvedValue({ + content: [], + }); + const client = makeMockClient({ callTool }); + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", client); + + const result = await tool.execute("call-1", {}); + + expect(result.content).toEqual([{ type: "text", text: "(no output)" }]); + }); + + it("throws on error results", async () => { + const callTool = jest.fn().mockResolvedValue({ + content: [{ type: "text", text: "something went wrong" }], + isError: true, + }); + const client = makeMockClient({ callTool }); + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", client); + + await expect(tool.execute("call-1", {})).rejects.toThrow("something went wrong"); + }); + + it("throws 'Unknown error' when error result has no text", async () => { + const callTool = jest.fn().mockResolvedValue({ + content: [], + isError: true, + }); + const client = makeMockClient({ callTool }); + const tool = convertMcpToolToAgentTool(makeMcpTool(), "github", client); + + await expect(tool.execute("call-1", {})).rejects.toThrow("Unknown error"); + }); +}); + +// --------------------------------------------------------------------------- +// convertServerTools +// --------------------------------------------------------------------------- + +describe("convertServerTools", () => { + it("lists and converts all tools from a server", async () => { + const listTools = jest.fn().mockResolvedValue({ + tools: [ + makeMcpTool({ name: "list_repos" }), + makeMcpTool({ name: "get_repo", description: "Get a repo" }), + ], + }); + const client = makeMockClient({ listTools }); + + const tools = await convertServerTools("github", client); + + expect(tools).toHaveLength(2); + expect(tools[0].name).toBe("github__list_repos"); + expect(tools[1].name).toBe("github__get_repo"); + expect(listTools).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/pi-mono/src/tools.ts b/packages/pi-mono/src/tools.ts new file mode 100644 index 0000000..b6e6657 --- /dev/null +++ b/packages/pi-mono/src/tools.ts @@ -0,0 +1,152 @@ +/** + * MCP tool → pi-mono AgentTool conversion. + * + * Converts MCP tools (JSON Schema parameters) into pi-mono AgentTool instances + * (TypeBox parameters) that call back to the MCP server via the MCP client. + */ + +import { Type } from "@sinclair/typebox"; +import type { TSchema } from "@sinclair/typebox"; +import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; +import type { TextContent, ImageContent } from "@mariozechner/pi-ai"; +import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import type { Tool, CallToolResult, CompatibilityCallToolResult } from "@modelcontextprotocol/sdk/types.js"; + +/** The union type returned by Client.callTool(). */ +type CallToolResponse = CallToolResult | CompatibilityCallToolResult; + +/** Type guard: does the callTool response have a `content` array? */ +function hasContent(result: CallToolResponse): result is CallToolResult { + return "content" in result && Array.isArray(result.content); +} + +/** + * Convert an MCP JSON Schema into a TypeBox TSchema. + * + * Uses Type.Unsafe() to pass the JSON schema through as-is. + * TypeBox's Unsafe() accepts any valid JSON schema while preserving + * type inference — avoids deep recursive conversion of arbitrary schemas. + */ +export function jsonSchemaToTypeBox(jsonSchema: Tool["inputSchema"] | undefined): TSchema { + if (!jsonSchema) { + return Type.Object({}); + } + return Type.Unsafe(jsonSchema); +} + +/** + * Extract content from an MCP CallToolResult into pi-mono's format. + * + * MCP's TextContent/ImageContent types are structurally compatible with + * pi-mono's — both use { type: "text", text } and { type: "image", data, mimeType }. + */ +function mcpResultToAgentToolResult( + result: CallToolResponse, +): AgentToolResult { + const content: (TextContent | ImageContent)[] = []; + + if (hasContent(result)) { + for (const block of result.content) { + if (block.type === "text") { + content.push({ type: "text", text: block.text }); + } else if (block.type === "image") { + content.push({ + type: "image", + data: block.data, + mimeType: block.mimeType, + }); + } + } + } + + if (content.length === 0) { + content.push({ type: "text", text: "(no output)" }); + } + + return { content, details: undefined }; +} + +/** + * Extract error text from a CallToolResult's content blocks. + */ +function extractErrorText(result: CallToolResponse): string { + if (!hasContent(result)) return "Unknown error"; + return ( + result.content + .filter((c): c is typeof c & { type: "text" } => c.type === "text") + .map((c) => c.text) + .join("\n") || "Unknown error" + ); +} + +/** + * Validate and extract params as a plain object for MCP callTool. + * The pi-mono AgentTool execute() receives `unknown` (Static), + * but MCP callTool expects Record | undefined. + */ +function toCallToolArguments(params: unknown): Record | undefined { + if (params == null) return undefined; + if (typeof params === "object" && !Array.isArray(params)) { + return params as Record; // narrowed via typeof check + } + return undefined; +} + +/** + * Convert a single MCP tool into a pi-mono AgentTool. + * + * @param mcpTool - The MCP tool definition (name, description, inputSchema). + * @param serverName - Name of the MCP server this tool belongs to. + * @param client - The MCP client instance to use for calling the tool. + * @returns A pi-mono AgentTool that proxies execution to the MCP server. + */ +export function convertMcpToolToAgentTool( + mcpTool: Tool, + serverName: string, + client: Client, +): AgentTool { + const toolName = `${serverName}__${mcpTool.name}`; + const description = mcpTool.description ?? `Tool from ${serverName}`; + const parameters = jsonSchemaToTypeBox(mcpTool.inputSchema); + const label = `${serverName}: ${mcpTool.name}`; + + return { + name: toolName, + description, + label, + parameters, + + async execute( + _toolCallId: string, + params: unknown, + signal?: AbortSignal, + ): Promise> { + const result = await client.callTool( + { name: mcpTool.name, arguments: toCallToolArguments(params) }, + undefined, + { signal }, + ); + + if (result.isError) { + throw new Error(extractErrorText(result)); + } + + return mcpResultToAgentToolResult(result); + }, + }; +} + +/** + * Convert all tools from an MCP server into pi-mono AgentTool instances. + * + * @param serverName - Name of the MCP server. + * @param client - Connected MCP client for this server. + * @returns Array of pi-mono AgentTool instances. + */ +export async function convertServerTools( + serverName: string, + client: Client, +): Promise { + const { tools } = await client.listTools(); + return tools.map((tool) => convertMcpToolToAgentTool(tool, serverName, client)); +} diff --git a/packages/pi-mono/src/types.ts b/packages/pi-mono/src/types.ts new file mode 100644 index 0000000..d8392f1 --- /dev/null +++ b/packages/pi-mono/src/types.ts @@ -0,0 +1,69 @@ +/** + * Shared types for the @keycardai/pi-mono integration. + * + * Re-exports the pi-mono AgentTool types and defines Keycard-specific interfaces + * for MCP server configuration and auth handling. + */ + +import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; + +// --------------------------------------------------------------------------- +// Re-export pi-mono types that consumers need +// --------------------------------------------------------------------------- + +export type { + AgentTool, + AgentToolResult, + AgentToolUpdateCallback, +} from "@mariozechner/pi-agent-core"; + +// --------------------------------------------------------------------------- +// MCP server configuration +// --------------------------------------------------------------------------- + +/** Auth status of an MCP server after connection attempt. */ +export type ServerAuthStatus = "authorized" | "unauthorized" | "error"; + +/** Tracked state for a connected (or failed) MCP server. */ +export interface ServerState { + name: string; + status: ServerAuthStatus; + /** The MCP client for this server (set when authorized). */ + client?: Client; + /** Error message if status is "error". */ + error?: string; +} + +// --------------------------------------------------------------------------- +// Auth tool handler +// --------------------------------------------------------------------------- + +/** + * Pluggable handler for delivering OAuth authorization links to users. + * + * Implement this interface to customize how auth links are presented — + * e.g., posting to Slack, rendering in a web UI, or printing to console. + * + * Follows the same pattern as the Python SDK's AuthToolHandler. + */ +export interface AuthToolHandler { + /** + * Called when a server needs OAuth authorization. + * + * @param serverName - The name of the MCP server requiring auth. + * @param authUrl - The full OAuth authorization URL the user should visit. + * @param reason - Optional reason the agent wants access (from the agent's tool call). + * @returns A message string for the agent to display to the user. + */ + handleAuthRequest( + serverName: string, + authUrl: string, + reason?: string, + ): Promise; + + /** + * Called when an error occurs during auth flow setup. + * Optional — defaults to returning an error message string. + */ + handleAuthError?(serverName: string, error: Error): Promise; +} diff --git a/packages/pi-mono/tsconfig.cjs.json b/packages/pi-mono/tsconfig.cjs.json new file mode 100644 index 0000000..058a5d9 --- /dev/null +++ b/packages/pi-mono/tsconfig.cjs.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "outDir": "./dist/cjs" + }, + "exclude": ["**/*.test.ts"] +} diff --git a/packages/pi-mono/tsconfig.json b/packages/pi-mono/tsconfig.json new file mode 100644 index 0000000..1d27cfb --- /dev/null +++ b/packages/pi-mono/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "module": "Node16", + "moduleResolution": "Node16", + "outDir": "./dist", + "baseUrl": "." + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} diff --git a/packages/pi-mono/tsconfig.prod.json b/packages/pi-mono/tsconfig.prod.json new file mode 100644 index 0000000..2c68666 --- /dev/null +++ b/packages/pi-mono/tsconfig.prod.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./dist/esm" + }, + "exclude": ["**/*.test.ts"] +} diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 29c4057..c3b157e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -14,6 +14,11 @@ "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js", "types": "./dist/esm/index.d.ts" + }, + "./pi-mono": { + "import": "./dist/esm/pi-mono.js", + "require": "./dist/cjs/pi-mono.js", + "types": "./dist/esm/pi-mono.d.ts" } }, "files": [ @@ -30,6 +35,9 @@ "@keycardai/oauth": "workspace:*", "@keycardai/mcp": "workspace:*" }, + "optionalDependencies": { + "@keycardai/pi-mono": "workspace:*" + }, "devDependencies": { "typescript": "^5.8.3" } diff --git a/packages/sdk/src/pi-mono.ts b/packages/sdk/src/pi-mono.ts new file mode 100644 index 0000000..fa7e48a --- /dev/null +++ b/packages/sdk/src/pi-mono.ts @@ -0,0 +1,20 @@ +// Pi-mono integration re-exports +// Install @keycardai/pi-mono (and its peer deps) to use these. +export { + PiMonoClient, + DefaultAuthToolHandler, + ConsoleAuthToolHandler, + createAuthRequestTool, + convertMcpToolToAgentTool, + convertServerTools, + jsonSchemaToTypeBox, + buildSystemPromptSection, +} from "@keycardai/pi-mono"; + +export type { + ConnectedServer, + PiMonoClientConfig, + ServerAuthStatus, + ServerState, + AuthToolHandler, +} from "@keycardai/pi-mono"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f2d91a4..6389ad8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,43 @@ importers: specifier: ^5.8.3 version: 5.9.3 + packages/pi-mono: + dependencies: + '@keycardai/oauth': + specifier: workspace:* + version: link:../oauth + devDependencies: + '@jest/globals': + specifier: ^30.0.4 + version: 30.2.0 + '@mariozechner/pi-agent-core': + specifier: '>=0.60.0' + version: 0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + '@mariozechner/pi-ai': + specifier: '>=0.60.0' + version: 0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + '@mariozechner/pi-coding-agent': + specifier: '>=0.60.0' + version: 0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + '@modelcontextprotocol/sdk': + specifier: ^1.15.0 + version: 1.26.0(zod@3.25.76) + '@sinclair/typebox': + specifier: '>=0.30.0' + version: 0.34.48 + jest: + specifier: ^30.0.4 + version: 30.2.0(@types/node@25.2.3) + ts-jest: + specifier: ^29.4.0 + version: 29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.2.3))(typescript@5.9.3) + typescript: + specifier: ^5.8.3 + version: 5.9.3 + zod: + specifier: ^3.25.0 + version: 3.25.76 + packages/sdk: dependencies: '@keycardai/mcp': @@ -79,6 +116,10 @@ importers: '@keycardai/oauth': specifier: workspace:* version: link:../oauth + optionalDependencies: + '@keycardai/pi-mono': + specifier: workspace:* + version: link:../pi-mono devDependencies: typescript: specifier: ^5.8.3 @@ -86,6 +127,152 @@ importers: packages: + '@anthropic-ai/sdk@0.73.0': + resolution: {integrity: sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1024.0': + resolution: {integrity: sha512-nIhsn0/eYrL2fTh4kMO7Hpfmhv+AkkXl0KGNpD6+fdmotGvRBWcDv9/PmP/+sT6gvrKTYyzH3vu4efpTPzzP0Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.973.26': + resolution: {integrity: sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.24': + resolution: {integrity: sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.26': + resolution: {integrity: sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.28': + resolution: {integrity: sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.28': + resolution: {integrity: sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.29': + resolution: {integrity: sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.24': + resolution: {integrity: sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.28': + resolution: {integrity: sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.28': + resolution: {integrity: sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.12': + resolution: {integrity: sha512-ruyc/MNR6e+cUrGCth7fLQ12RXBZDy/bV06tgqB9Z5n/0SN/C0m6bsQEV8FF9zPI6VSAOaRd0rNgmpYVnGawrQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.8': + resolution: {integrity: sha512-r+oP+tbCxgqXVC3pu3MUVePgSY0ILMjA+aEwOosS77m3/DRbtvHrHwqvMcw+cjANMeGzJ+i0ar+n77KXpRA8RQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-host-header@3.972.8': + resolution: {integrity: sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-logger@3.972.8': + resolution: {integrity: sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-recursion-detection@3.972.9': + resolution: {integrity: sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-user-agent@3.972.28': + resolution: {integrity: sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.14': + resolution: {integrity: sha512-qnfDlIHjm6DrTYNvWOUbnZdVKgtoKbO/Qzj+C0Wp5Y7VUrsvBRQtGKxD+hc+mRTS4N0kBJ6iZ3+zxm4N1OSyjg==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.996.18': + resolution: {integrity: sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/region-config-resolver@3.972.10': + resolution: {integrity: sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1021.0': + resolution: {integrity: sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1024.0': + resolution: {integrity: sha512-eoyTMgd6OzoE1dq50um5Y53NrosEkWsjH0W6pswi7vrv1W9hY/7hR43jDcPevqqj+OQksf/5lc++FTqRlb8Y1Q==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.6': + resolution: {integrity: sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-endpoints@3.996.5': + resolution: {integrity: sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-format-url@3.972.8': + resolution: {integrity: sha512-J6DS9oocrgxM8xlUTTmQOuwRF6rnAGEujAN9SAzllcrQmwn5iJ58ogxy3SEhD0Q7JZvlA5jvIXBkpQRqEqlE9A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.5': + resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-user-agent-browser@3.972.8': + resolution: {integrity: sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==} + + '@aws-sdk/util-user-agent-node@3.973.14': + resolution: {integrity: sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw==} + engines: {node: '>=20.0.0'} + peerDependencies: + aws-crt: '>=1.0.0' + peerDependenciesMeta: + aws-crt: + optional: true + + '@aws-sdk/xml-builder@3.972.16': + resolution: {integrity: sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + engines: {node: '>=18.0.0'} + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -236,6 +423,10 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -251,6 +442,9 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + '@emnapi/core@1.8.1': resolution: {integrity: sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==} @@ -260,6 +454,15 @@ packages: '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@google/genai@1.48.0': + resolution: {integrity: sha512-plonYK4ML2PrxsRD9SeqmFt76eREWkQdPCglOA6aYDzL1AAbE+7PUnT54SvpWGfws13L0AZEqGSpL7+1IPnTxQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + '@hono/node-server@1.19.9': resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} engines: {node: '>=18.14.1'} @@ -376,6 +579,94 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@mariozechner/clipboard-darwin-arm64@0.3.2': + resolution: {integrity: sha512-uBf6K7Je1ihsgvmWxA8UCGCeI+nbRVRXoarZdLjl6slz94Zs1tNKFZqx7aCI5O1i3e0B6ja82zZ06BWrl0MCVw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@mariozechner/clipboard-darwin-universal@0.3.2': + resolution: {integrity: sha512-mxSheKTW2U9LsBdXy0SdmdCAE5HqNS9QUmpNHLnfJ+SsbFKALjEZc5oRrVMXxGQSirDvYf5bjmRyT0QYYonnlg==} + engines: {node: '>= 10'} + os: [darwin] + + '@mariozechner/clipboard-darwin-x64@0.3.2': + resolution: {integrity: sha512-U1BcVEoidvwIp95+HJswSW+xr28EQiHR7rZjH6pn8Sja5yO4Yoe3yCN0Zm8Lo72BbSOK/fTSq0je7CJpaPCspg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@mariozechner/clipboard-linux-arm64-gnu@0.3.2': + resolution: {integrity: sha512-BsinwG3yWTIjdgNCxsFlip7LkfwPk+ruw/aFCXHUg/fb5XC/Ksp+YMQ7u0LUtiKzIv/7LMXgZInJQH6gxbAaqQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@mariozechner/clipboard-linux-arm64-musl@0.3.2': + resolution: {integrity: sha512-0/Gi5Xq2V6goXBop19ePoHvXsmJD9SzFlO3S+d6+T2b+BlPcpOu3Oa0wTjl+cZrLAAEzA86aPNBI+VVAFDFPKw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@mariozechner/clipboard-linux-riscv64-gnu@0.3.2': + resolution: {integrity: sha512-2AFFiXB24qf0zOZsxI1GJGb9wQGlOJyN6UwoXqmKS3dpQi/l6ix30IzDDA4c4ZcCcx4D+9HLYXhC1w7Sov8pXA==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@mariozechner/clipboard-linux-x64-gnu@0.3.2': + resolution: {integrity: sha512-v6fVnsn7WMGg73Dab8QMwyFce7tzGfgEixKgzLP8f1GJqkJZi5zO4k4FOHzSgUufgLil63gnxvMpjWkgfeQN7A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@mariozechner/clipboard-linux-x64-musl@0.3.2': + resolution: {integrity: sha512-xVUtnoMQ8v2JVyfJLKKXACA6avdnchdbBkTsZs8BgJQo29qwCp5NIHAUO8gbJ40iaEGToW5RlmVk2M9V0HsHEw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@mariozechner/clipboard-win32-arm64-msvc@0.3.2': + resolution: {integrity: sha512-AEgg95TNi8TGgak2wSXZkXKCvAUTjWoU1Pqb0ON7JHrX78p616XUFNTJohtIon3e0w6k0pYPZeCuqRCza/Tqeg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@mariozechner/clipboard-win32-x64-msvc@0.3.2': + resolution: {integrity: sha512-tGRuYpZwDOD7HBrCpyRuhGnHHSCknELvqwKKUG4JSfSB7JIU7LKRh6zx6fMUOQd8uISK35TjFg5UcNih+vJhFA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@mariozechner/clipboard@0.3.2': + resolution: {integrity: sha512-IHQpksNjo7EAtGuHFU+tbWDp5LarH3HU/8WiB9O70ZEoBPHOg0/6afwSLK0QyNMMmx4Bpi/zl6+DcBXe95nWYA==} + engines: {node: '>= 10'} + + '@mariozechner/jiti@2.6.5': + resolution: {integrity: sha512-faGUlTcXka5l7rv0lP3K3vGW/ejRuOS24RR2aSFWREUQqzjgdsuWNo/IiPqL3kWRGt6Ahl2+qcDAwtdeWeuGUw==} + hasBin: true + + '@mariozechner/pi-agent-core@0.65.2': + resolution: {integrity: sha512-GYOrX5aRUpSDMPtKR174Tv72CWH92anqlRuiGn8PV05OowPAahT99JoxvZEP4fcKANBdHsyDfMMwFYpPhvPBUQ==} + engines: {node: '>=20.0.0'} + + '@mariozechner/pi-ai@0.65.2': + resolution: {integrity: sha512-XCbXncmh10Q89tvS0880Ms6pv3DTxFTEtanfVHEPXKQBi0FBYnrkAlOnP5VRU8vCfe18P1AMNsWCndsCBUqY7g==} + engines: {node: '>=20.0.0'} + hasBin: true + + '@mariozechner/pi-coding-agent@0.65.2': + resolution: {integrity: sha512-/rpFzPQ+CishxrSwJHSSRZBQHHWy2K3Rbu/iV0HcMq/hl9cSI2ygpwjVTRbPW+NuP1tHxVV3AMxz69VLAs5Ztg==} + engines: {node: '>=20.6.0'} + hasBin: true + + '@mariozechner/pi-tui@0.65.2': + resolution: {integrity: sha512-LBPbIBASjCF4QLrc/dwmPdBzVMsbkDhzmBIAFgglX5rZBnGRppB7ekSA+1kb5pdxDpDn8IbxJX+bl7ZaeqZqxw==} + engines: {node: '>=20.0.0'} + + '@mistralai/mistralai@1.14.1': + resolution: {integrity: sha512-IiLmmZFCCTReQgPAT33r7KQ1nYo5JPdvGkrkZqA8qQ2qB1GHgs5LoP5K2ICyrjnpw2n8oSxMM/VP+liiKcGNlQ==} + '@modelcontextprotocol/sdk@1.26.0': resolution: {integrity: sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==} engines: {node: '>=18'} @@ -404,6 +695,39 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@silvia-odwyer/photon-node@0.3.4': + resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + '@sinclair/typebox@0.34.48': resolution: {integrity: sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA==} @@ -413,6 +737,204 @@ packages: '@sinonjs/fake-timers@13.0.5': resolution: {integrity: sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==} + '@smithy/config-resolver@4.4.14': + resolution: {integrity: sha512-N55f8mPEccpzKetUagdvmAy8oohf0J5cuj9jLI1TaSceRlq0pJsIZepY3kmAXAhyxqXPV6hDerDQhqQPKWgAoQ==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.23.14': + resolution: {integrity: sha512-vJ0IhpZxZAkFYOegMKSrxw7ujhhT2pass/1UEcZ4kfl5srTAqtPU5I7MdYQoreVas3204ykCiNhY1o7Xlz6Yyg==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.2.13': + resolution: {integrity: sha512-wboCPijzf6RJKLOvnjDAiBxGSmSnGXj35o5ZAWKDaHa/cvQ5U3ZJ13D4tMCE8JG4dxVAZFy/P0x/V9CwwdfULQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-codec@4.2.13': + resolution: {integrity: sha512-vYahwBAtRaAcFbOmE9aLr12z7RiHYDSLcnogSdxfm7kKfsNa3wH+NU5r7vTeB5rKvLsWyPjVX8iH94brP7umiQ==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-browser@4.2.13': + resolution: {integrity: sha512-wwybfcOX0tLqCcBP378TIU9IqrDuZq/tDV48LlZNydMpCnqnYr+hWBAYbRE+rFFf/p7IkDJySM3bgiMKP2ihPg==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-config-resolver@4.3.13': + resolution: {integrity: sha512-ied1lO559PtAsMJzg2TKRlctLnEi1PfkNeMMpdwXDImk1zV9uvS/Oxoy/vcy9uv1GKZAjDAB5xT6ziE9fzm5wA==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-node@4.2.13': + resolution: {integrity: sha512-hFyK+ORJrxAN3RYoaD6+gsGDQjeix8HOEkosoajvXYZ4VeqonM3G4jd9IIRm/sWGXUKmudkY9KdYjzosUqdM8A==} + engines: {node: '>=18.0.0'} + + '@smithy/eventstream-serde-universal@4.2.13': + resolution: {integrity: sha512-kRrq4EKLGeOxhC2CBEhRNcu1KSzNJzYY7RK3S7CxMPgB5dRrv55WqQOtRwQxQLC04xqORFLUgnDlc6xrNUULaA==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.3.16': + resolution: {integrity: sha512-nYDRUIvNd4mFmuXraRWt6w5UsZTNqtj4hXJA/iiOD4tuseIdLP9Lq38teH/SZTcIFCa2f+27o7hYpIsWktJKEQ==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.2.13': + resolution: {integrity: sha512-4/oy9h0jjmY80a2gOIo75iLl8TOPhmtx4E2Hz+PfMjvx/vLtGY4TMU/35WRyH2JHPfT5CVB38u4JRow7gnmzJA==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.2.13': + resolution: {integrity: sha512-jvC0RB/8BLj2SMIkY0Npl425IdnxZJxInpZJbu563zIRnVjpDMXevU3VMCRSabaLB0kf/eFIOusdGstrLJ8IDg==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.2.2': + resolution: {integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.2.13': + resolution: {integrity: sha512-IPMLm/LE4AZwu6qiE8Rr8vJsWhs9AtOdySRXrOM7xnvclp77Tyh7hMs/FRrMf26kgIe67vFJXXOSmVxS7oKeig==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.4.29': + resolution: {integrity: sha512-R9Q/58U+qBiSARGWbAbFLczECg/RmysRksX6Q8BaQEpt75I7LI6WGDZnjuC9GXSGKljEbA7N118LhGaMbfrTXw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.5.0': + resolution: {integrity: sha512-/NzISn4grj/BRFVua/xnQwF+7fakYZgimpw2dfmlPgcqecBMKxpB9g5mLYRrmBD5OrPoODokw4Vi1hrSR4zRyw==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.17': + resolution: {integrity: sha512-0T2mcaM6v9W1xku86Dk0bEW7aEseG6KenFkPK98XNw0ZhOqOiD1MrMsdnQw9QsL3/Oa85T53iSMlm0SZdSuIEQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.2.13': + resolution: {integrity: sha512-g72jN/sGDLyTanrCLH9fhg3oysO3f7tQa6eWWsMyn2BiYNCgjF24n4/I9wff/5XidFvjj9ilipAoQrurTUrLvw==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.3.13': + resolution: {integrity: sha512-iGxQ04DsKXLckbgnX4ipElrOTk+IHgTyu0q0WssZfYhDm9CQWHmu6cOeI5wmWRxpXbBDhIIfXMWz5tPEtcVqbw==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.5.2': + resolution: {integrity: sha512-/oD7u8M0oj2ZTFw7GkuuHWpIxtWdLlnyNkbrWcyVYhd5RJNDuczdkb0wfnQICyNFrVPlr8YHOhamjNy3zidhmA==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.13': + resolution: {integrity: sha512-bGzUCthxRmezuxkbu9wD33wWg9KX3hJpCXpQ93vVkPrHn9ZW6KNNdY5xAUWNuRCwQ+VyboFuWirG1lZhhkcyRQ==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.3.13': + resolution: {integrity: sha512-+HsmuJUF4u8POo6s8/a2Yb/AQ5t/YgLovCuHF9oxbocqv+SZ6gd8lC2duBFiCA/vFHoHQhoq7QjqJqZC6xOxxg==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.2.13': + resolution: {integrity: sha512-tG4aOYFCZdPMjbgfhnIQ322H//ojujldp1SrHPHpBSb3NqgUp3dwiUGRJzie87hS1DYwWGqDuPaowoDF+rYCbQ==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.2.13': + resolution: {integrity: sha512-hqW3Q4P+CDzUyQ87GrboGMeD7XYNMOF+CuTwu936UQRB/zeYn3jys8C3w+wMkDfY7CyyyVwZQ5cNFoG0x1pYmA==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.2.13': + resolution: {integrity: sha512-a0s8XZMfOC/qpqq7RCPvJlk93rWFrElH6O++8WJKz0FqnA4Y7fkNi/0mnGgSH1C4x6MFsuBA8VKu4zxFrMe5Vw==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.4.8': + resolution: {integrity: sha512-VZCZx2bZasxdqxVgEAhREvDSlkatTPnkdWy1+Kiy8w7kYPBosW0V5IeDwzDUMvWBt56zpK658rx1cOBFOYaPaw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.13': + resolution: {integrity: sha512-YpYSyM0vMDwKbHD/JA7bVOF6kToVRpa+FM5ateEVRpsTNu564g1muBlkTubXhSKKYXInhpADF46FPyrZcTLpXg==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.12.9': + resolution: {integrity: sha512-ovaLEcTU5olSeHcRXcxV6viaKtpkHZumn6Ps0yn7dRf2rRSfy794vpjOtrWDO0d1auDSvAqxO+lyhERSXQ03EQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.14.0': + resolution: {integrity: sha512-OWgntFLW88kx2qvf/c/67Vno1yuXm/f9M7QFAtVkkO29IJXGBIg0ycEaBTH0kvCtwmvZxRujrgP5a86RvsXJAQ==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.13': + resolution: {integrity: sha512-2G03yoboIRZlZze2+PT4GZEjgwQsJjUgn6iTsvxA02bVceHR6vp4Cuk7TUnPFWKF+ffNUk3kj4COwkENS2K3vw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.3.2': + resolution: {integrity: sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.2.2': + resolution: {integrity: sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.2.3': + resolution: {integrity: sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.2': + resolution: {integrity: sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.2.2': + resolution: {integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.3.45': + resolution: {integrity: sha512-ag9sWc6/nWZAuK3Wm9KlFJUnRkXLrXn33RFjIAmCTFThqLHY+7wCst10BGq56FxslsDrjhSie46c8OULS+BiIw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.2.49': + resolution: {integrity: sha512-jlN6vHwE8gY5AfiFBavtD3QtCX2f7lM3BKkz7nFKSNfFR5nXLXLg6sqXTJEEyDwtxbztIDBQCfjsGVXlIru2lQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.3.4': + resolution: {integrity: sha512-BKoR/ubPp9KNKFxPpg1J28N1+bgu8NGAtJblBP7yHy8yQPBWhIAv9+l92SlQLpolGm71CVO+btB60gTgzT0wog==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.2': + resolution: {integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.13': + resolution: {integrity: sha512-GTooyrlmRTqvUen4eK7/K1p6kryF7bnDfq6XsAbIsf2mo51B/utaH+XThY6dKgNCWzMAaH/+OLmqaBuLhLWRow==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.3.0': + resolution: {integrity: sha512-tSOPQNT/4KfbvqeMovWC3g23KSYy8czHd3tlN+tOYVNIDLSfxIsrPJihYi5TpNcoV789KWtgChUVedh2y6dDPg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.22': + resolution: {integrity: sha512-3H8iq/0BfQjUs2/4fbHZ9aG9yNzcuZs24LPkcX1Q7Z+qpqaGM8+qbGmE8zo9m2nCRgamyvS98cHdcWvR6YUsew==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.2.2': + resolution: {integrity: sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.2': + resolution: {integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.1.2': + resolution: {integrity: sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==} + engines: {node: '>=18.0.0'} + + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -455,6 +977,9 @@ packages: '@types/istanbul-reports@3.0.4': resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/mime-types@2.1.4': + resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} + '@types/node@25.2.3': resolution: {integrity: sha512-m0jEgYlYz+mDJZ2+F4v8D1AyQb+QzsNqRuI7xg1VQX/KlKS0qT9r1Mo16yo5F/MtifXFgaofIFsdFMox2SxIbQ==} @@ -464,6 +989,9 @@ packages: '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@types/send@1.2.1': resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} @@ -479,6 +1007,9 @@ packages: '@types/yargs@17.0.35': resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} @@ -581,6 +1112,10 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -616,6 +1151,9 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -626,6 +1164,10 @@ packages: asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -657,20 +1199,41 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + baseline-browser-mapping@2.9.19: resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} hasBin: true + basic-ftp@5.2.0: + resolution: {integrity: sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==} + engines: {node: '>=10.0.0'} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -687,6 +1250,12 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -721,6 +1290,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -732,6 +1305,14 @@ packages: cjs-module-lexer@2.2.0: resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + cli-highlight@2.1.11: + resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} + engines: {node: '>=8.0.0', npm: '>=5.0.0'} + hasBin: true + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -790,6 +1371,14 @@ packages: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -811,6 +1400,10 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -826,6 +1419,10 @@ packages: dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -833,6 +1430,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -853,6 +1453,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} @@ -883,13 +1486,26 @@ packages: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} eventsource-parser@3.0.6: @@ -922,6 +1538,14 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -934,9 +1558,27 @@ packages: fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-xml-builder@1.1.4: + resolution: {integrity: sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==} + + fast-xml-parser@5.5.8: + resolution: {integrity: sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==} + hasBin: true + fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + engines: {node: '>=20'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -957,6 +1599,10 @@ packages: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + formidable@3.5.4: resolution: {integrity: sha512-YikH+7CUTOtP44ZTnUhR7Ic2UASBPOqmaRkRKxRbywPTe5VxF7RRCck4af9wutiZ/QKM5nME9Bie2fFaPz5Gug==} engines: {node: '>=14.0.0'} @@ -980,6 +1626,14 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gaxios@7.1.4: + resolution: {integrity: sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -988,6 +1642,10 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} + engines: {node: '>=18'} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1000,19 +1658,39 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} + get-uri@6.0.5: + resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} + engines: {node: '>= 14'} + glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + google-auth-library@10.6.2: + resolution: {integrity: sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} @@ -1041,10 +1719,17 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + hono@4.11.10: resolution: {integrity: sha512-kyWP5PAiMooEvGrA9jcD3IXF7ATu8+o7B3KCbPXid5se52NPqnOpM/r9qeW2heMnOekF4kqR1fXJqCYeCLKrZg==} engines: {node: '>=16.9.0'} + hosted-git-info@9.0.2: + resolution: {integrity: sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==} + engines: {node: ^20.17.0 || >=22.9.0} + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -1052,6 +1737,14 @@ packages: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -1060,6 +1753,13 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + import-local@3.2.0: resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} engines: {node: '>=8'} @@ -1275,9 +1975,16 @@ packages: engines: {node: '>=6'} hasBin: true + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} @@ -1289,6 +1996,15 @@ packages: engines: {node: '>=6'} hasBin: true + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + koffi@2.15.5: + resolution: {integrity: sha512-4/35/oOpnH9tzrpWAC3ObjAERBSe0Q0Dh2NP1eBBPRGpohEj4vFw2+7tej9W9MTExvk0vtF0PjMqIGG4rf6feQ==} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -1303,12 +2019,23 @@ packages: lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.3.1: + resolution: {integrity: sha512-Y71HWT4hydF1IAG/2OPync4dgQ/J2iWye7eg6CuzJHI+E97tvqFPlADzxiNnjH6WSljg8ecfXMr9k6bfFuqA5w==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} @@ -1319,6 +2046,11 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + marked@15.0.12: + resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} + engines: {node: '>= 18'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -1367,6 +2099,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1381,9 +2117,16 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -1399,6 +2142,19 @@ packages: neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + netmask@2.0.2: + resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} + engines: {node: '>= 0.4.0'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -1432,6 +2188,18 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + openai@6.26.0: + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -1444,10 +2212,22 @@ packages: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pac-proxy-agent@7.2.0: + resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} @@ -1455,14 +2235,30 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse5-htmlparser2-tree-adapter@6.0.1: + resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + + parse5@5.1.1: + resolution: {integrity: sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-expression-matcher@1.2.1: + resolution: {integrity: sha512-d7gQQmLvAKXKXE2GeP9apIGbMYKz88zWdsn/BN2HRWVQsDFdUY36WSLTY0Jvd4HWi7Fb30gQ62oAOzdgJA6fZw==} + engines: {node: '>=14.0.0'} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -1475,9 +2271,16 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -1505,10 +2308,27 @@ packages: resolution: {integrity: sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==} engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-agent@6.5.0: + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + pure-rand@7.0.1: resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} @@ -1543,10 +2363,21 @@ packages: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -1605,6 +2436,18 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + socks-proxy-agent@8.0.5: + resolution: {integrity: sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==} + engines: {node: '>= 14'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + source-map-support@0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} @@ -1623,6 +2466,9 @@ packages: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -1655,6 +2501,13 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strnum@2.2.2: + resolution: {integrity: sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==} + + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + superagent@10.3.0: resolution: {integrity: sha512-B+4Ik7ROgVKrQsXTV0Jwp2u+PXYLSlqtDAhYnkkD+zn3yg8s/zjA2MeGayPoY/KICrbitwneDHrjSotxKL+0XQ==} engines: {node: '>=14.18.0'} @@ -1679,6 +2532,13 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -1690,6 +2550,13 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + ts-jest@29.4.6: resolution: {integrity: sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA==} engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} @@ -1746,9 +2613,17 @@ packages: engines: {node: '>=0.8.0'} hasBin: true + uint8array-extras@1.5.0: + resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} + engines: {node: '>=18'} + undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici@7.24.7: + resolution: {integrity: sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==} + engines: {node: '>=20.18.1'} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -1773,6 +2648,10 @@ packages: walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -1796,6 +2675,18 @@ packages: resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -1803,18 +2694,38 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + zod-to-json-schema@3.25.1: resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: @@ -1825,6 +2736,400 @@ packages: snapshots: + '@anthropic-ai/sdk@0.73.0(zod@3.25.76)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 3.25.76 + + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.6 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-locate-window': 3.965.5 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.6 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.1024.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-node': 3.972.29 + '@aws-sdk/eventstream-handler-node': 3.972.12 + '@aws-sdk/middleware-eventstream': 3.972.8 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/middleware-websocket': 3.972.14 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/token-providers': 3.1024.0 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.14 + '@smithy/core': 3.23.14 + '@smithy/eventstream-serde-browser': 4.2.13 + '@smithy/eventstream-serde-config-resolver': 4.3.13 + '@smithy/eventstream-serde-node': 4.2.13 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/hash-node': 4.2.13 + '@smithy/invalid-dependency': 4.2.13 + '@smithy/middleware-content-length': 4.2.13 + '@smithy/middleware-endpoint': 4.4.29 + '@smithy/middleware-retry': 4.5.0 + '@smithy/middleware-serde': 4.2.17 + '@smithy/middleware-stack': 4.2.13 + '@smithy/node-config-provider': 4.3.13 + '@smithy/node-http-handler': 4.5.2 + '@smithy/protocol-http': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.45 + '@smithy/util-defaults-mode-node': 4.2.49 + '@smithy/util-endpoints': 3.3.4 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-retry': 4.3.0 + '@smithy/util-stream': 4.5.22 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.973.26': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws-sdk/xml-builder': 3.972.16 + '@smithy/core': 3.23.14 + '@smithy/node-config-provider': 4.3.13 + '@smithy/property-provider': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/signature-v4': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.26': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/node-http-handler': 4.5.2 + '@smithy/property-provider': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/util-stream': 4.5.22 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-login': 3.972.28 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.28 + '@aws-sdk/credential-provider-web-identity': 3.972.28 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.13 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-login@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.972.29': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-ini': 3.972.28 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.28 + '@aws-sdk/credential-provider-web-identity': 3.972.28 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.13 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/token-providers': 3.1021.0 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/eventstream-handler-node@3.972.12': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/eventstream-codec': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-host-header@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.972.9': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@smithy/core': 3.23.14 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-retry': 4.3.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.14': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-format-url': 3.972.8 + '@smithy/eventstream-codec': 4.2.13 + '@smithy/eventstream-serde-browser': 4.2.13 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/protocol-http': 5.3.13 + '@smithy/signature-v4': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.996.18': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.14 + '@smithy/core': 3.23.14 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/hash-node': 4.2.13 + '@smithy/invalid-dependency': 4.2.13 + '@smithy/middleware-content-length': 4.2.13 + '@smithy/middleware-endpoint': 4.4.29 + '@smithy/middleware-retry': 4.5.0 + '@smithy/middleware-serde': 4.2.17 + '@smithy/middleware-stack': 4.2.13 + '@smithy/node-config-provider': 4.3.13 + '@smithy/node-http-handler': 4.5.2 + '@smithy/protocol-http': 5.3.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.45 + '@smithy/util-defaults-mode-node': 4.2.49 + '@smithy/util-endpoints': 3.3.4 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-retry': 4.3.0 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.972.10': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/config-resolver': 4.4.14 + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1021.0': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/token-providers@3.1024.0': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.973.6': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.996.5': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-endpoints': 3.3.4 + tslib: 2.8.1 + + '@aws-sdk/util-format-url@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/querystring-builder': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.5': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.14.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.973.14': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/types': 3.973.6 + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-config-provider': 4.2.2 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.16': + dependencies: + '@smithy/types': 4.14.0 + fast-xml-parser: 5.5.8 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -1989,6 +3294,8 @@ snapshots: '@babel/core': 7.29.0 '@babel/helper-plugin-utils': 7.28.6 + '@babel/runtime@7.29.2': {} + '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 @@ -2014,6 +3321,8 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} + '@borewit/text-codec@0.2.2': {} + '@emnapi/core@1.8.1': dependencies: '@emnapi/wasi-threads': 1.1.0 @@ -2030,6 +3339,19 @@ snapshots: tslib: 2.8.1 optional: true + '@google/genai@1.48.0(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))': + dependencies: + google-auth-library: 10.6.2 + p-retry: 4.6.2 + protobufjs: 7.5.4 + ws: 8.20.0 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.26.0(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + '@hono/node-server@1.19.9(hono@4.11.10)': dependencies: hono: 4.11.10 @@ -2251,6 +3573,143 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@mariozechner/clipboard-darwin-arm64@0.3.2': + optional: true + + '@mariozechner/clipboard-darwin-universal@0.3.2': + optional: true + + '@mariozechner/clipboard-darwin-x64@0.3.2': + optional: true + + '@mariozechner/clipboard-linux-arm64-gnu@0.3.2': + optional: true + + '@mariozechner/clipboard-linux-arm64-musl@0.3.2': + optional: true + + '@mariozechner/clipboard-linux-riscv64-gnu@0.3.2': + optional: true + + '@mariozechner/clipboard-linux-x64-gnu@0.3.2': + optional: true + + '@mariozechner/clipboard-linux-x64-musl@0.3.2': + optional: true + + '@mariozechner/clipboard-win32-arm64-msvc@0.3.2': + optional: true + + '@mariozechner/clipboard-win32-x64-msvc@0.3.2': + optional: true + + '@mariozechner/clipboard@0.3.2': + optionalDependencies: + '@mariozechner/clipboard-darwin-arm64': 0.3.2 + '@mariozechner/clipboard-darwin-universal': 0.3.2 + '@mariozechner/clipboard-darwin-x64': 0.3.2 + '@mariozechner/clipboard-linux-arm64-gnu': 0.3.2 + '@mariozechner/clipboard-linux-arm64-musl': 0.3.2 + '@mariozechner/clipboard-linux-riscv64-gnu': 0.3.2 + '@mariozechner/clipboard-linux-x64-gnu': 0.3.2 + '@mariozechner/clipboard-linux-x64-musl': 0.3.2 + '@mariozechner/clipboard-win32-arm64-msvc': 0.3.2 + '@mariozechner/clipboard-win32-x64-msvc': 0.3.2 + optional: true + + '@mariozechner/jiti@2.6.5': + dependencies: + std-env: 3.10.0 + yoctocolors: 2.1.2 + + '@mariozechner/pi-agent-core@0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)': + dependencies: + '@mariozechner/pi-ai': 0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - aws-crt + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@mariozechner/pi-ai@0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)': + dependencies: + '@anthropic-ai/sdk': 0.73.0(zod@3.25.76) + '@aws-sdk/client-bedrock-runtime': 3.1024.0 + '@google/genai': 1.48.0(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76)) + '@mistralai/mistralai': 1.14.1 + '@sinclair/typebox': 0.34.48 + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + chalk: 5.6.2 + openai: 6.26.0(ws@8.20.0)(zod@3.25.76) + partial-json: 0.1.7 + proxy-agent: 6.5.0 + undici: 7.24.7 + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - aws-crt + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@mariozechner/pi-coding-agent@0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76)': + dependencies: + '@mariozechner/jiti': 2.6.5 + '@mariozechner/pi-agent-core': 0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + '@mariozechner/pi-ai': 0.65.2(@modelcontextprotocol/sdk@1.26.0(zod@3.25.76))(ws@8.20.0)(zod@3.25.76) + '@mariozechner/pi-tui': 0.65.2 + '@silvia-odwyer/photon-node': 0.3.4 + ajv: 8.18.0 + chalk: 5.6.2 + cli-highlight: 2.1.11 + diff: 8.0.4 + extract-zip: 2.0.1 + file-type: 21.3.4 + glob: 13.0.6 + hosted-git-info: 9.0.2 + ignore: 7.0.5 + marked: 15.0.12 + minimatch: 10.2.5 + proper-lockfile: 4.1.2 + strip-ansi: 7.1.2 + undici: 7.24.7 + yaml: 2.8.3 + optionalDependencies: + '@mariozechner/clipboard': 0.3.2 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - aws-crt + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@mariozechner/pi-tui@0.65.2': + dependencies: + '@types/mime-types': 2.1.4 + chalk: 5.6.2 + get-east-asian-width: 1.5.0 + marked: 15.0.12 + mime-types: 3.0.2 + optionalDependencies: + koffi: 2.15.5 + + '@mistralai/mistralai@1.14.1': + dependencies: + ws: 8.20.0 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@modelcontextprotocol/sdk@1.26.0(zod@3.25.76)': dependencies: '@hono/node-server': 1.19.9(hono@4.11.10) @@ -2273,33 +3732,369 @@ snapshots: transitivePeerDependencies: - supports-color - '@napi-rs/wasm-runtime@0.2.12': + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.8.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@noble/hashes@1.8.0': {} + + '@paralleldrive/cuid2@2.3.1': + dependencies: + '@noble/hashes': 1.8.0 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.2.9': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.4': {} + + '@protobufjs/eventemitter@1.1.0': {} + + '@protobufjs/fetch@1.1.0': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + + '@silvia-odwyer/photon-node@0.3.4': {} + + '@sinclair/typebox@0.34.48': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@13.0.5': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@smithy/config-resolver@4.4.14': + dependencies: + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-config-provider': 4.2.2 + '@smithy/util-endpoints': 3.3.4 + '@smithy/util-middleware': 4.2.13 + tslib: 2.8.1 + + '@smithy/core@3.23.14': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-stream': 4.5.22 + '@smithy/util-utf8': 4.2.2 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.2.13': + dependencies: + '@smithy/node-config-provider': 4.3.13 + '@smithy/property-provider': 4.2.13 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + tslib: 2.8.1 + + '@smithy/eventstream-codec@4.2.13': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.14.0 + '@smithy/util-hex-encoding': 4.2.2 + tslib: 2.8.1 + + '@smithy/eventstream-serde-browser@4.2.13': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-config-resolver@4.3.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-node@4.2.13': + dependencies: + '@smithy/eventstream-serde-universal': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/eventstream-serde-universal@4.2.13': + dependencies: + '@smithy/eventstream-codec': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.3.16': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/querystring-builder': 4.2.13 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + tslib: 2.8.1 + + '@smithy/hash-node@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + + '@smithy/invalid-dependency@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/is-array-buffer@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.2.13': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.4.29': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/middleware-serde': 4.2.17 + '@smithy/node-config-provider': 4.3.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + '@smithy/url-parser': 4.2.13 + '@smithy/util-middleware': 4.2.13 + tslib: 2.8.1 + + '@smithy/middleware-retry@4.5.0': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/node-config-provider': 4.3.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/service-error-classification': 4.2.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-retry': 4.3.0 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 + + '@smithy/middleware-serde@4.2.17': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/middleware-stack@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/node-config-provider@4.3.13': + dependencies: + '@smithy/property-provider': 4.2.13 + '@smithy/shared-ini-file-loader': 4.4.8 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.5.2': + dependencies: + '@smithy/protocol-http': 5.3.13 + '@smithy/querystring-builder': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/property-provider@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/protocol-http@5.3.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/querystring-builder@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + '@smithy/util-uri-escape': 4.2.2 + tslib: 2.8.1 + + '@smithy/querystring-parser@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/service-error-classification@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + + '@smithy/shared-ini-file-loader@4.4.8': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.3.13': + dependencies: + '@smithy/is-array-buffer': 4.2.2 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-middleware': 4.2.13 + '@smithy/util-uri-escape': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + + '@smithy/smithy-client@4.12.9': + dependencies: + '@smithy/core': 3.23.14 + '@smithy/middleware-endpoint': 4.4.29 + '@smithy/middleware-stack': 4.2.13 + '@smithy/protocol-http': 5.3.13 + '@smithy/types': 4.14.0 + '@smithy/util-stream': 4.5.22 + tslib: 2.8.1 + + '@smithy/types@4.14.0': + dependencies: + tslib: 2.8.1 + + '@smithy/url-parser@4.2.13': + dependencies: + '@smithy/querystring-parser': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 + + '@smithy/util-base64@4.3.2': + dependencies: + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + + '@smithy/util-body-length-browser@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.2.3': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-buffer-from@4.2.2': + dependencies: + '@smithy/is-array-buffer': 4.2.2 + tslib: 2.8.1 + + '@smithy/util-config-provider@4.2.2': dependencies: - '@emnapi/core': 1.8.1 - '@emnapi/runtime': 1.8.1 - '@tybys/wasm-util': 0.10.1 - optional: true + tslib: 2.8.1 - '@noble/hashes@1.8.0': {} + '@smithy/util-defaults-mode-browser@4.3.45': + dependencies: + '@smithy/property-provider': 4.2.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + tslib: 2.8.1 - '@paralleldrive/cuid2@2.3.1': + '@smithy/util-defaults-mode-node@4.2.49': dependencies: - '@noble/hashes': 1.8.0 + '@smithy/config-resolver': 4.4.14 + '@smithy/credential-provider-imds': 4.2.13 + '@smithy/node-config-provider': 4.3.13 + '@smithy/property-provider': 4.2.13 + '@smithy/smithy-client': 4.12.9 + '@smithy/types': 4.14.0 + tslib: 2.8.1 - '@pkgjs/parseargs@0.11.0': - optional: true + '@smithy/util-endpoints@3.3.4': + dependencies: + '@smithy/node-config-provider': 4.3.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 - '@pkgr/core@0.2.9': {} + '@smithy/util-hex-encoding@4.2.2': + dependencies: + tslib: 2.8.1 - '@sinclair/typebox@0.34.48': {} + '@smithy/util-middleware@4.2.13': + dependencies: + '@smithy/types': 4.14.0 + tslib: 2.8.1 - '@sinonjs/commons@3.0.1': + '@smithy/util-retry@4.3.0': dependencies: - type-detect: 4.0.8 + '@smithy/service-error-classification': 4.2.13 + '@smithy/types': 4.14.0 + tslib: 2.8.1 - '@sinonjs/fake-timers@13.0.5': + '@smithy/util-stream@4.5.22': dependencies: - '@sinonjs/commons': 3.0.1 + '@smithy/fetch-http-handler': 5.3.16 + '@smithy/node-http-handler': 4.5.2 + '@smithy/types': 4.14.0 + '@smithy/util-base64': 4.3.2 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + + '@smithy/util-uri-escape@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@4.2.2': + dependencies: + '@smithy/util-buffer-from': 4.2.2 + tslib: 2.8.1 + + '@smithy/uuid@1.1.2': + dependencies: + tslib: 2.8.1 + + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@tootallnate/quickjs-emscripten@0.23.0': {} '@tybys/wasm-util@0.10.1': dependencies: @@ -2365,6 +4160,8 @@ snapshots: dependencies: '@types/istanbul-lib-report': 3.0.3 + '@types/mime-types@2.1.4': {} + '@types/node@25.2.3': dependencies: undici-types: 7.16.0 @@ -2373,6 +4170,8 @@ snapshots: '@types/range-parser@1.2.7': {} + '@types/retry@0.12.0': {} + '@types/send@1.2.1': dependencies: '@types/node': 25.2.3 @@ -2390,6 +4189,11 @@ snapshots: dependencies: '@types/yargs-parser': 21.0.3 + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 25.2.3 + optional: true + '@ungap/structured-clone@1.3.0': {} '@unrs/resolver-binding-android-arm-eabi@1.11.1': @@ -2456,6 +4260,8 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 + agent-base@7.1.4: {} + ajv-formats@3.0.1(ajv@8.18.0): optionalDependencies: ajv: 8.18.0 @@ -2483,6 +4289,8 @@ snapshots: ansi-styles@6.2.3: {} + any-promise@1.3.0: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -2494,6 +4302,10 @@ snapshots: asap@2.0.6: {} + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + asynckit@0.4.0: {} babel-jest@30.2.0(@babel/core@7.29.0): @@ -2550,8 +4362,16 @@ snapshots: balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + baseline-browser-mapping@2.9.19: {} + basic-ftp@5.2.0: {} + + bignumber.js@9.3.1: {} + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -2566,6 +4386,8 @@ snapshots: transitivePeerDependencies: - supports-color + bowser@2.14.1: {} + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -2575,6 +4397,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -2595,6 +4421,10 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-crc32@0.2.13: {} + + buffer-equal-constant-time@1.0.1: {} + buffer-from@1.1.2: {} bytes@3.1.2: {} @@ -2622,12 +4452,29 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.6.2: {} + char-regex@1.0.2: {} ci-info@4.4.0: {} cjs-module-lexer@2.2.0: {} + cli-highlight@2.1.11: + dependencies: + chalk: 4.1.2 + highlight.js: 10.7.3 + mz: 2.7.0 + parse5: 5.1.1 + parse5-htmlparser2-tree-adapter: 6.0.1 + yargs: 16.2.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -2675,6 +4522,10 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + data-uri-to-buffer@4.0.1: {} + + data-uri-to-buffer@6.0.2: {} + debug@4.4.3: dependencies: ms: 2.1.3 @@ -2683,6 +4534,12 @@ snapshots: deepmerge@4.3.1: {} + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + delayed-stream@1.0.0: {} depd@2.0.0: {} @@ -2694,6 +4551,8 @@ snapshots: asap: 2.0.6 wrappy: 1.0.2 + diff@8.0.4: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2702,6 +4561,10 @@ snapshots: eastasianwidth@0.2.0: {} + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + ee-first@1.1.1: {} electron-to-chromium@1.5.286: {} @@ -2714,6 +4577,10 @@ snapshots: encodeurl@2.0.0: {} + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 @@ -2739,8 +4606,20 @@ snapshots: escape-string-regexp@2.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + esprima@4.0.1: {} + estraverse@5.3.0: {} + + esutils@2.0.3: {} + etag@1.8.1: {} eventsource-parser@3.0.6: {} @@ -2810,6 +4689,18 @@ snapshots: transitivePeerDependencies: - supports-color + extend@3.0.2: {} + + extract-zip@2.0.1: + dependencies: + debug: 4.4.3 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + fast-deep-equal@3.1.3: {} fast-json-stable-stringify@2.1.0: {} @@ -2818,10 +4709,38 @@ snapshots: fast-uri@3.1.0: {} + fast-xml-builder@1.1.4: + dependencies: + path-expression-matcher: 1.2.1 + + fast-xml-parser@5.5.8: + dependencies: + fast-xml-builder: 1.1.4 + path-expression-matcher: 1.2.1 + strnum: 2.2.2 + fb-watchman@2.0.2: dependencies: bser: 2.1.1 + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + file-type@21.3.4: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -2855,6 +4774,10 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + formidable@3.5.4: dependencies: '@paralleldrive/cuid2': 2.3.1 @@ -2872,10 +4795,28 @@ snapshots: function-bind@1.1.2: {} + gaxios@7.1.4: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.1.4 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} + get-east-asian-width@1.5.0: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2896,8 +4837,20 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 + get-stream@5.2.0: + dependencies: + pump: 3.0.4 + get-stream@6.0.1: {} + get-uri@6.0.5: + dependencies: + basic-ftp: 5.2.0 + data-uri-to-buffer: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -2907,6 +4860,12 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -2916,6 +4875,19 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + google-auth-library@10.6.2: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.4 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + gopd@1.2.0: {} graceful-fs@4.2.11: {} @@ -2941,8 +4913,14 @@ snapshots: dependencies: function-bind: 1.1.2 + highlight.js@10.7.3: {} + hono@4.11.10: {} + hosted-git-info@9.0.2: + dependencies: + lru-cache: 11.3.1 + html-escaper@2.0.2: {} http-errors@2.0.1: @@ -2953,12 +4931,30 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + human-signals@2.1.0: {} iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 + ieee754@1.2.1: {} + + ignore@7.0.5: {} + import-local@3.2.0: dependencies: pkg-dir: 4.2.0 @@ -3350,14 +5346,37 @@ snapshots: jsesc@3.1.0: {} + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + json-parse-even-better-errors@2.3.1: {} + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.2 + ts-algebra: 2.0.0 + json-schema-traverse@1.0.0: {} json-schema-typed@8.0.2: {} json5@2.2.3: {} + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + koffi@2.15.5: + optional: true + leven@3.1.0: {} lines-and-columns@1.2.4: {} @@ -3368,12 +5387,18 @@ snapshots: lodash.memoize@4.1.2: {} + long@5.3.2: {} + lru-cache@10.4.3: {} + lru-cache@11.3.1: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 + lru-cache@7.18.3: {} + make-dir@4.0.0: dependencies: semver: 7.7.4 @@ -3384,6 +5409,8 @@ snapshots: dependencies: tmpl: 1.0.5 + marked@15.0.12: {} + math-intrinsics@1.1.0: {} media-typer@1.1.0: {} @@ -3415,6 +5442,10 @@ snapshots: mimic-fn@2.1.0: {} + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -3427,8 +5458,16 @@ snapshots: minipass@7.1.2: {} + minipass@7.1.3: {} + ms@2.1.3: {} + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} @@ -3437,6 +5476,16 @@ snapshots: neo-async@2.6.2: {} + netmask@2.0.2: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-int64@0.4.0: {} node-releases@2.0.27: {} @@ -3463,6 +5512,11 @@ snapshots: dependencies: mimic-fn: 2.1.0 + openai@6.26.0(ws@8.20.0)(zod@3.25.76): + optionalDependencies: + ws: 8.20.0 + zod: 3.25.76 + p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -3475,8 +5529,31 @@ snapshots: dependencies: p-limit: 2.3.0 + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + p-try@2.2.0: {} + pac-proxy-agent@7.2.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.4 + debug: 4.4.3 + get-uri: 6.0.5 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.0.2 + package-json-from-dist@1.0.1: {} parse-json@5.2.0: @@ -3486,10 +5563,22 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse5-htmlparser2-tree-adapter@6.0.1: + dependencies: + parse5: 6.0.1 + + parse5@5.1.1: {} + + parse5@6.0.1: {} + parseurl@1.3.3: {} + partial-json@0.1.7: {} + path-exists@4.0.0: {} + path-expression-matcher@1.2.1: {} + path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -3499,8 +5588,15 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.2 + path-scurry@2.0.2: + dependencies: + lru-cache: 11.3.1 + minipass: 7.1.3 + path-to-regexp@8.3.0: {} + pend@1.2.0: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -3521,11 +5617,52 @@ snapshots: ansi-styles: 5.2.0 react-is: 18.3.1 + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + protobufjs@7.5.4: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.4 + '@protobufjs/eventemitter': 1.1.0 + '@protobufjs/fetch': 1.1.0 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.0 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.0 + '@types/node': 25.2.3 + long: 5.3.2 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-agent@6.5.0: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.2.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + proxy-from-env@1.1.0: {} + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + pure-rand@7.0.1: {} qs@6.15.0: @@ -3553,6 +5690,10 @@ snapshots: resolve-from@5.0.0: {} + retry@0.12.0: {} + + retry@0.13.1: {} + router@2.2.0: dependencies: debug: 4.4.3 @@ -3563,6 +5704,8 @@ snapshots: transitivePeerDependencies: - supports-color + safe-buffer@5.2.1: {} + safer-buffer@2.1.2: {} semver@6.3.1: {} @@ -3636,6 +5779,21 @@ snapshots: slash@3.0.0: {} + smart-buffer@4.2.0: {} + + socks-proxy-agent@8.0.5: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.0.1 + smart-buffer: 4.2.0 + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 @@ -3651,6 +5809,8 @@ snapshots: statuses@2.0.2: {} + std-env@3.10.0: {} + string-length@4.0.2: dependencies: char-regex: 1.0.2 @@ -3682,6 +5842,12 @@ snapshots: strip-json-comments@3.1.1: {} + strnum@2.2.2: {} + + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + superagent@10.3.0: dependencies: component-emitter: 1.3.1 @@ -3722,6 +5888,14 @@ snapshots: glob: 7.2.3 minimatch: 3.1.2 + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + tmpl@1.0.5: {} to-regex-range@5.0.1: @@ -3730,6 +5904,14 @@ snapshots: toidentifier@1.0.1: {} + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + + ts-algebra@2.0.0: {} + ts-jest@29.4.6(@babel/core@7.29.0)(@jest/transform@30.2.0)(@jest/types@30.2.0)(babel-jest@30.2.0(@babel/core@7.29.0))(jest-util@30.2.0)(jest@30.2.0(@types/node@25.2.3))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 @@ -3750,8 +5932,7 @@ snapshots: babel-jest: 30.2.0(@babel/core@7.29.0) jest-util: 30.2.0 - tslib@2.8.1: - optional: true + tslib@2.8.1: {} type-detect@4.0.8: {} @@ -3770,8 +5951,12 @@ snapshots: uglify-js@3.19.3: optional: true + uint8array-extras@1.5.0: {} + undici-types@7.16.0: {} + undici@7.24.7: {} + unpipe@1.0.0: {} unrs-resolver@1.11.1: @@ -3816,6 +6001,8 @@ snapshots: dependencies: makeerror: 1.0.12 + web-streams-polyfill@3.3.3: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -3841,12 +6028,28 @@ snapshots: imurmurhash: 0.1.4 signal-exit: 4.1.0 + ws@8.20.0: {} + y18n@5.0.8: {} yallist@3.1.1: {} + yaml@2.8.3: {} + + yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + yargs@17.7.2: dependencies: cliui: 8.0.1 @@ -3857,8 +6060,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + yocto-queue@0.1.0: {} + yoctocolors@2.1.2: {} + zod-to-json-schema@3.25.1(zod@3.25.76): dependencies: zod: 3.25.76 From f0639867f2b55508e1eb05a803475e84fedf94fd Mon Sep 17 00:00:00 2001 From: Larry-Osakwe Date: Mon, 6 Apr 2026 10:57:16 -0700 Subject: [PATCH 2/4] fix(pi-mono): remove dead code flagged in review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove getErrorServers() — "error" status was never set by detectAuthStatus() - Remove "error" from ServerAuthStatus union — no code path produces it - Remove unused AgentToolUpdateCallback re-export from types.ts Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/pi-mono/src/client.ts | 9 --------- packages/pi-mono/src/types.ts | 3 +-- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/packages/pi-mono/src/client.ts b/packages/pi-mono/src/client.ts index 4c7f59a..99171fe 100644 --- a/packages/pi-mono/src/client.ts +++ b/packages/pi-mono/src/client.ts @@ -228,15 +228,6 @@ export class PiMonoClient { return names; } - /** Get names of servers that had connection errors. */ - getErrorServers(): string[] { - const names: string[] = []; - for (const [name, state] of this.#serverStates) { - if (state.status === "error") names.push(name); - } - return names; - } - /** Get the full state map for all servers. */ getServerStates(): ReadonlyMap { return this.#serverStates; diff --git a/packages/pi-mono/src/types.ts b/packages/pi-mono/src/types.ts index d8392f1..16330e9 100644 --- a/packages/pi-mono/src/types.ts +++ b/packages/pi-mono/src/types.ts @@ -14,7 +14,6 @@ import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; export type { AgentTool, AgentToolResult, - AgentToolUpdateCallback, } from "@mariozechner/pi-agent-core"; // --------------------------------------------------------------------------- @@ -22,7 +21,7 @@ export type { // --------------------------------------------------------------------------- /** Auth status of an MCP server after connection attempt. */ -export type ServerAuthStatus = "authorized" | "unauthorized" | "error"; +export type ServerAuthStatus = "authorized" | "unauthorized"; /** Tracked state for a connected (or failed) MCP server. */ export interface ServerState { From 6642ede210afda4e42bc7461b44cf5ef9782a66c Mon Sep 17 00:00:00 2001 From: Larry-Osakwe Date: Mon, 6 Apr 2026 11:03:23 -0700 Subject: [PATCH 3/4] docs(pi-mono): add package README Co-Authored-By: Claude Opus 4.6 (1M context) --- packages/pi-mono/README.md | 151 +++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 packages/pi-mono/README.md diff --git a/packages/pi-mono/README.md b/packages/pi-mono/README.md new file mode 100644 index 0000000..1ab8bed --- /dev/null +++ b/packages/pi-mono/README.md @@ -0,0 +1,151 @@ +# @keycardai/pi-mono + +[Pi-mono](https://github.com/badlogic/pi-mono) agent integration for Keycard — converts MCP tools from Keycard-protected servers into pi-mono `AgentTool` instances with OAuth auth handling and auth-aware system prompts. + +This is a **client-side** integration. If you're building an MCP server, you want [`@keycardai/mcp`](../mcp/) instead. + +## Installation + +```bash +npm install @keycardai/pi-mono @mariozechner/pi-agent-core @mariozechner/pi-ai @modelcontextprotocol/sdk @sinclair/typebox +``` + +## Quick Start + +```typescript +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; +import { PiMonoClient } from "@keycardai/pi-mono"; +import { + createAgentSession, + SessionManager, + AuthStorage, + ModelRegistry, +} from "@mariozechner/pi-coding-agent"; + +// 1. Connect MCP clients to your Keycard-protected servers +const githubClient = new Client({ name: "my-app", version: "1.0" }); +await githubClient.connect( + new StreamableHTTPClientTransport(new URL("https://github-mcp.example.com/mcp")), +); + +// 2. Create the Keycard adapter +const adapter = new PiMonoClient({ + servers: [{ name: "github", client: githubClient }], +}); +await adapter.detectAuthStatus(); + +// 3. Get pi-mono native tools and system prompt +const tools = await adapter.getTools(); +const authTools = await adapter.getAuthTools(); +const systemPrompt = adapter.getSystemPrompt("You are a helpful assistant."); + +// 4. Create a pi-mono agent session +const authStorage = AuthStorage.create(); +const modelRegistry = ModelRegistry.create(authStorage); + +const { session } = await createAgentSession({ + sessionManager: SessionManager.inMemory(), + authStorage, + modelRegistry, + tools: [...tools, ...authTools], + systemPrompt, +}); + +// 5. Use the agent — it can now call Keycard-protected MCP tools +session.subscribe((event) => { + if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") { + process.stdout.write(event.assistantMessageEvent.delta); + } +}); + +await session.prompt("List my open PRs on GitHub"); +``` + +## How It Works + +Pi-mono agents accept tools as `AgentTool[]` arrays. This package bridges Keycard-protected MCP servers into that model: + +1. **Auth detection** — `detectAuthStatus()` probes each MCP server by calling `listTools()`. Servers that respond are marked authorized; servers that reject are marked unauthorized. + +2. **Tool conversion** — `getTools()` converts MCP tools into pi-mono `AgentTool` instances. JSON Schema parameters are bridged to TypeBox via `Type.Unsafe()`. Each tool's `execute()` proxies to `client.callTool()` on the MCP server. + +3. **Auth tools** — `getAuthTools()` returns a `request_authorization` tool the agent can call to trigger OAuth flows for unauthorized servers. Auth link delivery is handled by a pluggable `AuthToolHandler`. + +4. **System prompt** — `getSystemPrompt()` generates a section listing which servers are authorized and which need auth, with instructions for the agent. + +All pi-mono framework features (extensions, skills, AGENTS.md discovery, session management, compaction, thinking levels) work unchanged — Keycard tools are just additional entries in the agent's toolkit. + +## API + +### `PiMonoClient` + +```typescript +import { PiMonoClient } from "@keycardai/pi-mono"; + +const adapter = new PiMonoClient({ + // Connected MCP Client instances + servers: [{ name: "github", client: githubMcpClient }], + + // Optional: custom auth link handler (default: returns URL string) + authHandler: new ConsoleAuthToolHandler(), + + // Optional: generates OAuth URLs when agent requests authorization + generateAuthUrl: async (serverName) => "https://auth.example.com/...", +}); +``` + +| Method | Returns | Description | +|---|---|---| +| `detectAuthStatus()` | `Promise` | Probes servers and sets auth status | +| `getTools()` | `Promise` | MCP tools as pi-mono AgentTools (authorized servers only) | +| `getAuthTools()` | `Promise` | Auth request tool (if servers need authorization) | +| `getSystemPrompt(base?)` | `string` | Auth-aware system prompt section | +| `getAuthorizedServers()` | `string[]` | Names of authorized servers | +| `getUnauthorizedServers()` | `string[]` | Names of servers needing auth | +| `getServerStates()` | `ReadonlyMap` | Full state map for all servers | +| `clearCache()` | `void` | Forces tool re-fetch on next `getTools()` | + +### `AuthToolHandler` + +Pluggable interface for delivering OAuth links to users: + +```typescript +import { DefaultAuthToolHandler, ConsoleAuthToolHandler } from "@keycardai/pi-mono"; + +// Default: returns URL string for the agent to display +const handler = new DefaultAuthToolHandler(); + +// Console: prints URL to stdout (for CLI apps) +const handler = new ConsoleAuthToolHandler(); + +// Custom: implement the interface +const handler: AuthToolHandler = { + async handleAuthRequest(serverName, authUrl, reason?) { + // Post to Slack, render in web UI, etc. + return "Authorization link sent!"; + }, +}; +``` + +### Tool Conversion Utilities + +For advanced use cases, the conversion functions are exported directly: + +```typescript +import { convertMcpToolToAgentTool, convertServerTools, jsonSchemaToTypeBox } from "@keycardai/pi-mono"; + +// Convert a single MCP tool +const agentTool = convertMcpToolToAgentTool(mcpTool, "github", mcpClient); + +// Convert all tools from a server +const tools = await convertServerTools("github", mcpClient); +``` + +## Tool Naming + +Tools are prefixed with the server name to avoid collisions across servers: + +- `github__list_repos` +- `slack__send_message` +- `linear__create_issue` From ec099a800a3a2446c7e2dcf8b86a6a762ce4ac69 Mon Sep 17 00:00:00 2001 From: Larry-Osakwe Date: Mon, 6 Apr 2026 11:31:49 -0700 Subject: [PATCH 4/4] docs(pi-mono): add full example app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runnable pi-mono agent with Keycard MCP tools — connects to Keycard-protected servers, converts tools, streams responses. Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/pi-mono-agent/README.md | 114 +++++++++++++++++++++ examples/pi-mono-agent/package.json | 23 +++++ examples/pi-mono-agent/src/index.ts | 144 +++++++++++++++++++++++++++ examples/pi-mono-agent/tsconfig.json | 12 +++ 4 files changed, 293 insertions(+) create mode 100644 examples/pi-mono-agent/README.md create mode 100644 examples/pi-mono-agent/package.json create mode 100644 examples/pi-mono-agent/src/index.ts create mode 100644 examples/pi-mono-agent/tsconfig.json diff --git a/examples/pi-mono-agent/README.md b/examples/pi-mono-agent/README.md new file mode 100644 index 0000000..2626707 --- /dev/null +++ b/examples/pi-mono-agent/README.md @@ -0,0 +1,114 @@ +# Pi-mono Agent with Keycard MCP Tools + +A CLI coding agent powered by [pi-mono](https://github.com/badlogic/pi-mono) that can access Keycard-protected MCP servers (GitHub, Slack, Linear, etc.) through OAuth-authenticated tools. Demonstrates `@keycardai/pi-mono` — the pi-mono integration for the Keycard TypeScript SDK. + +## What This Example Shows + +- Connecting to Keycard-protected MCP servers via `@modelcontextprotocol/sdk` +- Using `PiMonoClient` to convert MCP tools into pi-mono `AgentTool` instances +- Auth-aware system prompt generation (authorized vs unauthorized servers) +- Console-based OAuth flow for unauthorized servers +- Creating a `createAgentSession()` with Keycard tools + +## Prerequisites + +- **Node.js 18+** +- **Anthropic API key** (or another provider supported by pi-mono) +- **Keycard account** — sign up at [console.keycard.ai](https://console.keycard.ai) +- **Configured zone** with an identity provider (Okta, Auth0, Google, etc.) +- **At least one MCP server** registered as a resource in Keycard Console + +## Keycard Console Setup + +### 1. Register Your MCP Server as a Resource + +If you have a Keycard-protected MCP server running (see the [Cloudflare Worker](../cloudflare-worker/) or [Hello World](../hello-world-server/) examples): + +1. Navigate to **Resources** → **Create Resource** +2. Configure: + - **Resource Name:** `GitHub MCP Server` + - **Resource Identifier:** `https://your-mcp-server.example.com` + - **Credential Provider:** Zone Provider + - **Scopes:** `mcp:tools` + +### 2. Create Application Credentials + +1. Navigate to **Applications** → **Create Application** +2. Note the **Client ID** and **Client Secret** — you'll need these for the OAuth flow + +## Install and Run + +```bash +cd examples/pi-mono-agent +npm install +``` + +Set your API key and MCP server URL: + +```bash +export ANTHROPIC_API_KEY=sk-ant-... +export GITHUB_MCP_URL=https://your-mcp-server.example.com/mcp +``` + +Run the agent: + +```bash +npm start +``` + +Or with a custom prompt: + +```bash +npm start -- "List my open pull requests on GitHub" +``` + +## How It Works + +``` +┌──────────────┐ ┌───────────────┐ ┌──────────────┐ +│ pi-mono │────▶│ PiMonoClient │────▶│ MCP Server │ +│ Agent │ │ (Keycard SDK) │ │ (Keycard │ +│ Session │ │ │ │ protected) │ +│ │◀────│ AgentTool[] │◀────│ │ +└──────────────┘ └───────────────┘ └──────────────┘ + │ │ + │ prompt("List my PRs") │ + │ ──▶ calls github__list_pulls │ + │ ──▶ MCP callTool() ──────────────▶│ + │ ◀── result ◀──────────────│ + │ ◀── "You have 3 open PRs..." │ +``` + +1. **Connect** — MCP clients connect to Keycard-protected servers +2. **Detect auth** — `PiMonoClient` probes each server; authorized ones get their tools converted +3. **Convert tools** — MCP tools become pi-mono `AgentTool` instances (JSON Schema → TypeBox) +4. **Create session** — `createAgentSession()` with the converted tools + auth tools +5. **Prompt** — The LLM sees the tools, calls them as needed, results flow back through MCP + +## Configuration + +Edit the `MCP_SERVERS` array in `src/index.ts` to add your servers: + +```typescript +const MCP_SERVERS = [ + { name: "github", url: process.env.GITHUB_MCP_URL ?? "https://..." }, + { name: "slack", url: process.env.SLACK_MCP_URL ?? "https://..." }, + { name: "linear", url: process.env.LINEAR_MCP_URL ?? "https://..." }, +]; +``` + +## Environment Variables + +| Variable | Description | +|---|---| +| `ANTHROPIC_API_KEY` | Anthropic API key (required) | +| `GITHUB_MCP_URL` | URL of your GitHub MCP server | +| `SLACK_MCP_URL` | URL of your Slack MCP server | +| `LINEAR_MCP_URL` | URL of your Linear MCP server | + +## Related + +- [`@keycardai/pi-mono` docs](https://docs.keycard.ai/sdk/pi-mono/) — full API reference +- [Cloudflare Worker example](../cloudflare-worker/) — build the MCP server this agent connects to +- [Hello World example](../hello-world-server/) — Express-based MCP server +- [pi-mono SDK docs](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/sdk.md) — pi-mono framework reference diff --git a/examples/pi-mono-agent/package.json b/examples/pi-mono-agent/package.json new file mode 100644 index 0000000..58a6c1e --- /dev/null +++ b/examples/pi-mono-agent/package.json @@ -0,0 +1,23 @@ +{ + "name": "pi-mono-agent", + "version": "0.1.0", + "private": true, + "description": "Pi-mono coding agent with Keycard-protected MCP tools — GitHub, Slack, and more", + "type": "module", + "scripts": { + "start": "tsx src/index.ts", + "dev": "tsx watch src/index.ts" + }, + "dependencies": { + "@keycardai/pi-mono": "^0.1.0", + "@mariozechner/pi-agent-core": ">=0.60.0", + "@mariozechner/pi-ai": ">=0.60.0", + "@mariozechner/pi-coding-agent": ">=0.60.0", + "@modelcontextprotocol/sdk": "^1.15.0", + "@sinclair/typebox": ">=0.30.0" + }, + "devDependencies": { + "tsx": "^4.19.0", + "typescript": "^5.8.3" + } +} diff --git a/examples/pi-mono-agent/src/index.ts b/examples/pi-mono-agent/src/index.ts new file mode 100644 index 0000000..b64f4bb --- /dev/null +++ b/examples/pi-mono-agent/src/index.ts @@ -0,0 +1,144 @@ +/** + * Pi-mono Coding Agent with Keycard MCP Tools + * + * A CLI agent powered by pi-mono that can access Keycard-protected MCP + * servers (GitHub, Slack, Linear, etc.) through OAuth-authenticated tools. + * + * Prerequisites: + * 1. A Keycard zone with an identity provider configured + * 2. One or more MCP servers registered as resources in Keycard Console + * 3. An Anthropic API key (or other supported provider) + * + * See README.md for full setup instructions. + */ + +import { Client } from "@modelcontextprotocol/sdk/client/index.js"; +import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"; +import { + createAgentSession, + SessionManager, + AuthStorage, + ModelRegistry, +} from "@mariozechner/pi-coding-agent"; +import { PiMonoClient, ConsoleAuthToolHandler } from "@keycardai/pi-mono"; + +// --------------------------------------------------------------------------- +// Configuration — set these via environment variables +// --------------------------------------------------------------------------- + +const MCP_SERVERS = [ + { + name: "github", + url: process.env.GITHUB_MCP_URL ?? "https://github-mcp.example.com/mcp", + }, + // Add more servers: + // { name: "slack", url: process.env.SLACK_MCP_URL ?? "https://slack-mcp.example.com/mcp" }, + // { name: "linear", url: process.env.LINEAR_MCP_URL ?? "https://linear-mcp.example.com/mcp" }, +]; + +const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY; +if (!ANTHROPIC_API_KEY) { + console.error("Set ANTHROPIC_API_KEY to run this agent."); + process.exit(1); +} + +// --------------------------------------------------------------------------- +// 1. Connect MCP clients to Keycard-protected servers +// --------------------------------------------------------------------------- + +console.log("Connecting to MCP servers..."); + +const connectedServers = await Promise.all( + MCP_SERVERS.map(async (server) => { + const client = new Client({ name: "pi-mono-agent", version: "1.0.0" }); + try { + const transport = new StreamableHTTPClientTransport(new URL(server.url)); + await client.connect(transport); + console.log(` Connected: ${server.name}`); + } catch (error) { + console.warn(` Failed to connect to ${server.name}:`, error instanceof Error ? error.message : error); + } + return { name: server.name, client }; + }), +); + +// --------------------------------------------------------------------------- +// 2. Create Keycard adapter and detect auth status +// --------------------------------------------------------------------------- + +const keycardClient = new PiMonoClient({ + servers: connectedServers, + authHandler: new ConsoleAuthToolHandler(), + generateAuthUrl: async (serverName) => { + // In a real app, you'd discover the authorization endpoint via + // RFC 9728 metadata and build a PKCE auth URL. See the playthis-agent + // example for a full implementation. + return `https://your-zone.keycard.cloud/authorize?server=${serverName}`; + }, +}); + +await keycardClient.detectAuthStatus(); + +const authorized = keycardClient.getAuthorizedServers(); +const unauthorized = keycardClient.getUnauthorizedServers(); + +console.log(`\nAuthorized: ${authorized.length > 0 ? authorized.join(", ") : "(none)"}`); +if (unauthorized.length > 0) { + console.log(`Needs auth: ${unauthorized.join(", ")}`); +} + +// --------------------------------------------------------------------------- +// 3. Get pi-mono tools and system prompt +// --------------------------------------------------------------------------- + +const mcpTools = await keycardClient.getTools(); +const authTools = await keycardClient.getAuthTools(); +const systemPromptSection = keycardClient.getSystemPrompt(); + +console.log(`\nLoaded ${mcpTools.length} MCP tool(s), ${authTools.length} auth tool(s)`); + +// --------------------------------------------------------------------------- +// 4. Create pi-mono agent session +// --------------------------------------------------------------------------- + +const authStorage = AuthStorage.create(); +authStorage.setRuntimeApiKey("anthropic", ANTHROPIC_API_KEY); +const modelRegistry = ModelRegistry.create(authStorage); + +const { session } = await createAgentSession({ + sessionManager: SessionManager.inMemory(), + authStorage, + modelRegistry, + tools: [...mcpTools, ...authTools], + systemPrompt: `You are a helpful coding assistant.\n\n${systemPromptSection}`, +}); + +// --------------------------------------------------------------------------- +// 5. Run a prompt and stream the response +// --------------------------------------------------------------------------- + +console.log("\n--- Agent Response ---\n"); + +session.subscribe((event: Record) => { + if ( + event.type === "message_update" && + typeof event.assistantMessageEvent === "object" && + event.assistantMessageEvent !== null + ) { + const ame = event.assistantMessageEvent as Record; + if (ame.type === "text_delta" && typeof ame.delta === "string") { + process.stdout.write(ame.delta); + } + } +}); + +// Use the first argument as the prompt, or a default +const prompt = process.argv[2] ?? "What tools do you have available? List them briefly."; +await session.prompt(prompt); + +console.log("\n"); + +// Cleanup +for (const server of connectedServers) { + await server.client.close().catch(() => {}); +} diff --git a/examples/pi-mono-agent/tsconfig.json b/examples/pi-mono-agent/tsconfig.json new file mode 100644 index 0000000..27d02ea --- /dev/null +++ b/examples/pi-mono-agent/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2021", + "module": "Node16", + "moduleResolution": "Node16", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "dist" + }, + "include": ["src/**/*"] +}