From ee69d04623a7c820178c76d22535baf9a0942588 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 10:05:47 +0100 Subject: [PATCH 01/19] wip --- apps/web/package-lock.json | 865 +++++++++++++++++- apps/web/package.json | 15 +- apps/web/server.ts | 57 ++ apps/web/src/app/api/mcp/route.ts | 6 + apps/web/src/app/api/ws/route.ts | 56 ++ apps/web/src/app/mcp_client.ts | 242 +++++ apps/web/src/components/tools/auth0/chat.tsx | 113 +++ .../src/components/tools/auth0/dashboard.tsx | 21 + apps/web/src/lib/mcp-client.ts | 174 ++++ apps/web/src/lib/mcp-server.ts | 60 ++ apps/web/tsconfig.server.json | 10 + apps/web/ws-server.ts | 58 ++ 12 files changed, 1636 insertions(+), 41 deletions(-) create mode 100644 apps/web/server.ts create mode 100644 apps/web/src/app/api/mcp/route.ts create mode 100644 apps/web/src/app/api/ws/route.ts create mode 100644 apps/web/src/app/mcp_client.ts create mode 100644 apps/web/src/components/tools/auth0/chat.tsx create mode 100644 apps/web/src/lib/mcp-client.ts create mode 100644 apps/web/src/lib/mcp-server.ts create mode 100644 apps/web/tsconfig.server.json create mode 100644 apps/web/ws-server.ts diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json index 5b76614..f95ffb3 100644 --- a/apps/web/package-lock.json +++ b/apps/web/package-lock.json @@ -8,9 +8,12 @@ "name": "web", "version": "0.1.0", "dependencies": { + "@anthropic-ai/sdk": "^0.33.1", + "@modelcontextprotocol/sdk": "^1.0.4", "@nivo/core": "^0.88.0", "@nivo/treemap": "^0.88.0", "@radix-ui/react-checkbox": "^1.1.3", + "@radix-ui/react-collapsible": "^1.1.2", "@radix-ui/react-label": "^2.1.1", "@radix-ui/react-popover": "^1.1.4", "@radix-ui/react-scroll-area": "^1.2.2", @@ -19,9 +22,12 @@ "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.6", "@shadcn/ui": "^0.0.4", + "@types/ws": "^8.5.13", + "chalk": "^5.4.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", + "dotenv": "^16.4.7", "init": "^0.1.2", "lucide-react": "^0.468.0", "next": "15.1.1", @@ -33,7 +39,9 @@ "recharts": "^2.15.0", "shadcn-ui": "^0.9.4", "tailwind-merge": "^2.6.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.2", + "ws": "^8.18.0" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -41,6 +49,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "concurrently": "^9.1.1", "eslint": "^9", "eslint-config-next": "15.1.1", "postcss": "^8", @@ -89,6 +98,56 @@ "nun": "bin/nun.mjs" } }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.33.1.tgz", + "integrity": "sha512-VrlbxiAdVRGuKP2UQlCnsShDHJKWepzvfRCkZMpU+oaUdKLpOfmylLMRojGrAgebV+kDtPjewCVP0laHXg+vsA==", + "license": "MIT", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { + "version": "18.19.68", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.68.tgz", + "integrity": "sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", @@ -504,6 +563,26 @@ "node": ">=6.9.0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", @@ -839,6 +918,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.0.4.tgz", + "integrity": "sha512-C+jw1lF6HSGzs7EZpzHbXfzz9rj9him4BaoumlTciW/IDDgIpweF/qiCWKlP02QKg5PPcgY6xY2WCt5y2tpYow==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "raw-body": "^3.0.0", + "zod": "^3.23.8" + } + }, "node_modules/@next/env": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.1.tgz", @@ -1206,6 +1296,36 @@ } } }, + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.2.tgz", + "integrity": "sha512-PliMB63vxz7vggcyq0IxNYk8vGDrLXVWw4+W4B8YnwI1s18x7YZYqlG9PLX7XxAJUi0g2DxP4XKJMFHh/iVh9A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.1", + "@radix-ui/react-compose-refs": "1.1.1", + "@radix-ui/react-context": "1.1.1", + "@radix-ui/react-id": "1.1.0", + "@radix-ui/react-presence": "1.1.2", + "@radix-ui/react-primitive": "2.0.1", + "@radix-ui/react-use-controllable-state": "1.1.0", + "@radix-ui/react-use-layout-effect": "1.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-collection": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.1.tgz", @@ -2001,6 +2121,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" + }, "node_modules/@types/d3-array": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", @@ -2140,12 +2280,21 @@ "version": "20.17.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.10.tgz", "integrity": "sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/prop-types": { "version": "15.7.14", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", @@ -2177,6 +2326,14 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.18.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz", @@ -2419,11 +2576,22 @@ "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", "license": "ISC" }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -2442,6 +2610,17 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", @@ -2451,6 +2630,18 @@ "node": ">= 14" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2728,6 +2919,12 @@ "dev": true, "license": "MIT" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -2914,6 +3111,15 @@ "node": ">=10.16.0" } }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -3014,17 +3220,12 @@ } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -3153,6 +3354,78 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -3222,6 +3495,18 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -3249,6 +3534,83 @@ "dev": true, "license": "MIT" }, + "node_modules/concurrently": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.1.tgz", + "integrity": "sha512-6VX8lrBIycgZKTwBsWS+bLrmkGRkDmvtGsYylRN9b93CygN6CbK46HmnQ3rdSOR8HRjdahDrxb5MqD9cEFOg5Q==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -3281,6 +3643,11 @@ } } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3631,6 +3998,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3715,6 +4100,17 @@ "csstype": "^3.0.2" } }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -4359,6 +4755,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/espree": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", @@ -4446,6 +4859,15 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -4667,6 +5089,48 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/formdata-node/node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/formdata-polyfill": { "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", @@ -4758,6 +5222,15 @@ "node": ">=6.9.0" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", @@ -5095,6 +5568,22 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/https-proxy-agent": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-6.2.1.tgz", @@ -5117,6 +5606,27 @@ "node": ">=14.18.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -6006,18 +6516,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -6056,6 +6554,11 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -6689,6 +7192,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -7172,18 +7696,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7622,6 +8134,21 @@ ], "license": "MIT" }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/react": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", @@ -7960,6 +8487,15 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -8079,6 +8615,15 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-array-concat": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", @@ -8137,6 +8682,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/scheduler": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", @@ -8190,6 +8741,12 @@ "node": ">= 0.4" } }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shadcn-ui": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/shadcn-ui/-/shadcn-ui-0.9.4.tgz", @@ -8356,6 +8913,18 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -8496,6 +9065,15 @@ "dev": true, "license": "MIT" }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/stdin-discarder": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", @@ -9025,6 +9603,30 @@ "node": ">=8.0" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", @@ -9075,6 +9677,61 @@ "code-block-writer": "^12.0.0" } }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -9222,7 +9879,6 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, "license": "MIT" }, "node_modules/unified": { @@ -9321,6 +9977,15 @@ "node": ">= 10.0.0" } }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", @@ -9410,6 +10075,11 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", @@ -9478,6 +10148,22 @@ "node": ">= 8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9686,6 +10372,35 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "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 + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -9705,6 +10420,82 @@ "node": ">= 14" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/apps/web/package.json b/apps/web/package.json index 4a26fbd..c545d8f 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,12 +3,13 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev --turbopack", + "dev": "ts-node --project tsconfig.server.json server.ts", "build": "next build", - "start": "next start", - "lint": "next lint" + "start": "NODE_ENV=production ts-node --project tsconfig.server.json server.ts" }, "dependencies": { + "@anthropic-ai/sdk": "^0.33.1", + "@modelcontextprotocol/sdk": "^1.0.4", "@nivo/core": "^0.88.0", "@nivo/treemap": "^0.88.0", "@radix-ui/react-checkbox": "^1.1.3", @@ -21,9 +22,12 @@ "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.6", "@shadcn/ui": "^0.0.4", + "@types/ws": "^8.5.13", + "chalk": "^5.4.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "date-fns": "^4.1.0", + "dotenv": "^16.4.7", "init": "^0.1.2", "lucide-react": "^0.468.0", "next": "15.1.1", @@ -35,7 +39,9 @@ "recharts": "^2.15.0", "shadcn-ui": "^0.9.4", "tailwind-merge": "^2.6.0", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "ts-node": "^10.9.2", + "ws": "^8.18.0" }, "devDependencies": { "@eslint/eslintrc": "^3", @@ -43,6 +49,7 @@ "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "concurrently": "^9.1.1", "eslint": "^9", "eslint-config-next": "15.1.1", "postcss": "^8", diff --git a/apps/web/server.ts b/apps/web/server.ts new file mode 100644 index 0000000..e710e06 --- /dev/null +++ b/apps/web/server.ts @@ -0,0 +1,57 @@ +import { createServer } from 'http' +import { parse } from 'url' +import next from 'next' +import { WebSocketServer } from 'ws' +import { MCPServer } from './src/lib/mcp-server' + +const dev = process.env.NODE_ENV !== 'production' +const hostname = 'localhost' +const port = 3000 +const wsPort = 3001 + +// Initialize Next.js +const app = next({ dev, hostname, port }) +const handle = app.getRequestHandler() + +app.prepare().then(() => { + // Create HTTP server + const server = createServer(async (req, res) => { + try { + const parsedUrl = parse(req.url!, true) + await handle(req, res, parsedUrl) + } catch (err) { + console.error('Error occurred handling', req.url, err) + res.statusCode = 500 + res.end('internal server error') + } + }) + + // Start WebSocket server on different port + const wss = new WebSocketServer({ port: wsPort }) + const mcpServer = new MCPServer() + mcpServer.start().catch(console.error) + + wss.on('connection', (ws) => { + console.log('MCP Client connected') + mcpServer.addClient(ws) + + ws.on('message', async (message) => { + try { + await mcpServer.handleMessage(message.toString(), ws) + } catch (error) { + console.error('Error handling message:', error) + ws.send(JSON.stringify({ error: 'Internal server error' })) + } + }) + + ws.on('close', () => { + console.log('MCP Client disconnected') + mcpServer.removeClient(ws) + }) + }) + + server.listen(port, () => { + console.log(`> Ready on http://${hostname}:${port}`) + console.log(`> WebSocket server running on ws://${hostname}:${wsPort}`) + }) +}) \ No newline at end of file diff --git a/apps/web/src/app/api/mcp/route.ts b/apps/web/src/app/api/mcp/route.ts new file mode 100644 index 0000000..8d87055 --- /dev/null +++ b/apps/web/src/app/api/mcp/route.ts @@ -0,0 +1,6 @@ +import WebSocketSingleton from '@/lib/websocket-server'; + +export async function GET() { + await WebSocketSingleton.getInstance(); + return new Response('WebSocket server is running', { status: 200 }); +} \ No newline at end of file diff --git a/apps/web/src/app/api/ws/route.ts b/apps/web/src/app/api/ws/route.ts new file mode 100644 index 0000000..0a599ba --- /dev/null +++ b/apps/web/src/app/api/ws/route.ts @@ -0,0 +1,56 @@ +import { WebSocketServer } from 'ws'; +import { MCPServer } from '@/lib/mcp-server'; + +const SUBPROTOCOL = "mcp"; +const WS_PORT = 3001; + +let wss: WebSocketServer | null = null; + +if (process.env.NODE_ENV === 'development' && !wss) { + try { + wss = new WebSocketServer({ + port: WS_PORT, + handleProtocols: (protocols: Set) => { + return Array.from(protocols).includes(SUBPROTOCOL) ? SUBPROTOCOL : false; + } + }); + + const mcpServer = new MCPServer(); + mcpServer.start().catch(console.error); + + wss.on('connection', (ws) => { + console.log('MCP Client connected'); + mcpServer.addClient(ws); + + ws.on('message', async (message) => { + try { + await mcpServer.handleMessage(message.toString(), ws); + } catch (error) { + console.error('Error handling message:', error); + ws.send(JSON.stringify({ error: 'Internal server error' })); + } + }); + + ws.on('close', () => { + console.log('MCP Client disconnected'); + mcpServer.removeClient(ws); + }); + + ws.on('error', (error) => { + console.error('WebSocket error:', error); + }); + }); + + wss.on('error', (error) => { + console.error('WebSocket server error:', error); + }); + + console.log(`WebSocket server is running on port ${WS_PORT}`); + } catch (error) { + console.error('Failed to start WebSocket server:', error); + } +} + +export async function GET() { + return new Response('WebSocket server status: ' + (wss ? 'running' : 'not running')); +} \ No newline at end of file diff --git a/apps/web/src/app/mcp_client.ts b/apps/web/src/app/mcp_client.ts new file mode 100644 index 0000000..79432a5 --- /dev/null +++ b/apps/web/src/app/mcp_client.ts @@ -0,0 +1,242 @@ +import { Anthropic } from '@anthropic-ai/sdk'; + +import { + StdioClientTransport, + StdioServerParameters, +} from '@modelcontextprotocol/sdk/client/stdio.js'; +import { + ListToolsResultSchema, + CallToolResultSchema, +} from '@modelcontextprotocol/sdk/types.js'; +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import chalk from 'chalk'; +import readline from 'readline/promises'; +import { Tool } from '@anthropic-ai/sdk/resources/index.mjs'; +import { Stream } from '@anthropic-ai/sdk/streaming.mjs'; + +const EXIT_COMMAND = 'exit'; + +const styles = { + prompt: chalk.green('You: '), + assistant: chalk.blue('Claude: '), + tool: { + name: chalk.cyan.bold, + args: chalk.yellow, + bracket: chalk.dim, + }, + error: chalk.red, + info: chalk.blue, + success: chalk.green, + warning: chalk.yellow, + separator: chalk.gray('─'.repeat(50)), +}; + +interface Message { + role: 'user' | 'assistant'; + content: string; +} + +export class InteractiveCLI { + private anthropicClient: Anthropic; + private messages: Message[] = []; + private mcpClient: Client; + private transport: StdioClientTransport; + private tools: Tool[] = []; + private rl: readline.Interface; + + constructor(serverConfig: StdioServerParameters) { + this.anthropicClient = new Anthropic({ + apiKey: process.env.ANTHROPIC_API_KEY, + }); + + this.mcpClient = new Client( + { name: 'cli-client', version: '1.0.0' }, + { capabilities: {} }, + ); + + this.transport = new StdioClientTransport(serverConfig); + this.rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + }); + } + + async start() { + try { + console.log(styles.separator); + console.log(styles.info('🤖 Interactive Claude CLI')); + console.log( + styles.info(`Type your queries or "${EXIT_COMMAND}" to exit`), + ); + console.log(styles.separator); + + await this.mcpClient.connect(this.transport); + await this.initMCPTools(); + + await this.chat_loop(); + } catch (error) { + console.error(styles.error('Failed to initialize tools:'), error); + process.exit(1); + } finally { + this.rl.close(); + process.exit(0); + } + } + + private async initMCPTools() { + const toolsResults = await this.mcpClient.request( + { method: 'tools/list' }, + ListToolsResultSchema, + ); + this.tools = toolsResults.tools.map(({ inputSchema, ...tool }) => ({ + ...tool, + input_schema: inputSchema, + })); + } + + private formatToolCall(toolName: string, args: any): string { + return ( + '\n' + + styles.tool.bracket('[') + + styles.tool.name(toolName) + + styles.tool.bracket('] ') + + styles.tool.args(JSON.stringify(args, null, 2)) + + '\n' + ); + } + + private formatJSON(json: string): string { + return json + .replace(/"([^"]+)":/g, chalk.blue('"$1":')) + .replace(/: "([^"]+)"/g, ': ' + chalk.green('"$1"')); + } + + private async processStream( + stream: Stream, + ): Promise { + let currentMessage = ''; + let currentToolName = ''; + let currentToolInputString = ''; + + process.stdout.write(styles.assistant); + for await (const chunk of stream) { + switch (chunk.type) { + case 'message_start': + case 'content_block_stop': + continue; + + case 'content_block_start': + if (chunk.content_block?.type === 'tool_use') { + currentToolName = chunk.content_block.name; + } + break; + + case 'content_block_delta': + if (chunk.delta.type === 'text_delta') { + process.stdout.write(chunk.delta.text); + currentMessage += chunk.delta.text; + } else if (chunk.delta.type === 'input_json_delta') { + if (currentToolName && chunk.delta.partial_json) { + currentToolInputString += chunk.delta.partial_json; + } + } + break; + + case 'message_delta': + if (chunk.delta.stop_reason === 'tool_use') { + const toolArgs = currentToolInputString + ? JSON.parse(currentToolInputString) + : {}; + + console.log(this.formatToolCall(currentToolName, toolArgs)); + const toolResult = await this.mcpClient.request( + { + method: 'tools/call', + params: { + name: currentToolName, + arguments: toolArgs, + }, + }, + CallToolResultSchema, + ); + + if (currentMessage) { + this.messages.push({ + role: 'assistant', + content: currentMessage, + }); + } + + const formattedResult = this.formatJSON( + JSON.stringify(toolResult.content.flatMap((c) => c.text)), + ); + + this.messages.push({ + role: 'user', + content: formattedResult, + }); + + const nextStream = await this.anthropicClient.messages.create({ + messages: this.messages, + model: 'claude-3-5-sonnet-20241022', + max_tokens: 8192, + tools: this.tools, + stream: true, + }); + await this.processStream(nextStream); + } + break; + + case 'message_stop': + break; + + default: + console.warn( + styles.warning(`Unknown event type: ${JSON.stringify(chunk)}`), + ); + } + } + } + + private async processQuery(query: string) { + try { + this.messages.push({ role: 'user', content: query }); + + const stream = await this.anthropicClient.messages.create({ + messages: this.messages, + model: 'claude-3-5-sonnet-20241022', + max_tokens: 8192, + tools: this.tools, + stream: true, + }); + await this.processStream(stream); + } catch (error) { + console.error(styles.error('\nError during query processing:'), error); + if (error instanceof Error) { + process.stdout.write( + styles.assistant + + 'I apologize, but I encountered an error: ' + + error.message + + '\n', + ); + } + } + } + + private async chat_loop() { + while (true) { + try { + const query = (await this.rl.question(styles.prompt)).trim(); + if (query.toLowerCase() === EXIT_COMMAND) { + console.log(styles.warning('\nGoodbye! 👋')); + break; + } + + await this.processQuery(query); + console.log('\n' + styles.separator); + } catch (error) { + console.error(styles.error('\nError:'), error); + } + } + } +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/chat.tsx b/apps/web/src/components/tools/auth0/chat.tsx new file mode 100644 index 0000000..ccc1677 --- /dev/null +++ b/apps/web/src/components/tools/auth0/chat.tsx @@ -0,0 +1,113 @@ +'use client' + +import { useState, useEffect, useRef } from "react" +import { MCPClient, MessageCallback } from "@/lib/mcp-client" +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Button } from "@/components/ui/button" +import { ScrollArea } from "@/components/ui/scroll-area" + +export function Chat() { + const [messages, setMessages] = useState>([]) + const [input, setInput] = useState('') + const [isLoading, setIsLoading] = useState(false) + const clientRef = useRef(new MCPClient()) + + useEffect(() => { + let isInitialized = false; + + const initClient = async () => { + if (isInitialized) return; + isInitialized = true; + + try { + await clientRef.current.start() + console.log('MCP client initialized') + } catch (error) { + console.error('Failed to initialize MCP client:', error) + } + } + + initClient() + }, []) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + if (!input.trim() || isLoading) return + + const userMessage = input.trim() + setInput('') + setMessages(prev => [...prev, { role: 'user', content: userMessage }]) + + try { + setIsLoading(true) + let currentMessage = { role: 'assistant', content: '' } + + const onMessage: MessageCallback = (message) => { + if (message.content === '\n\n') { + setMessages(prev => [ + ...prev, message + ]) + currentMessage.content = '' + } else { + currentMessage.content += message.content + setMessages(prev => [ + ...prev.slice(0, -1), // Remove previous assistant message + { ...currentMessage } // Add updated message + ]) + } + } + + await clientRef.current.sendMessage(userMessage, onMessage) + } catch (error) { + console.error('Error sending message:', error) + } finally { + setIsLoading(false) + } + } + + return ( + + + Chat with Claude + + +
+ +
+ {messages.map((message, i) => ( +
+
+ {message.content} +
+
+ ))} +
+
+
+ setInput(e.target.value)} + placeholder="Type a message..." + disabled={isLoading} + /> + +
+
+
+
+ ) +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/dashboard.tsx b/apps/web/src/components/tools/auth0/dashboard.tsx index f32eb4d..0f59d72 100644 --- a/apps/web/src/components/tools/auth0/dashboard.tsx +++ b/apps/web/src/components/tools/auth0/dashboard.tsx @@ -31,6 +31,7 @@ import { CollapsibleTrigger, } from "@/components/ui/collapsible" import { ChevronDown, ChevronUp } from "lucide-react" +import { Chat } from './chat' interface SummaryMetrics { total_users: number @@ -105,6 +106,7 @@ export default function Auth0Dashboard() { unique_emails: number }>>([]) const [isDomainsOpen, setIsDomainsOpen] = useState(false) + const [isOpen, setIsOpen] = useState(false) useEffect(() => { async function fetchInitialData() { @@ -490,6 +492,25 @@ export default function Auth0Dashboard() { /> + + + +
+ Chat Assistant + + + +
+
+ + + + + +
+
) diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts new file mode 100644 index 0000000..74c3af5 --- /dev/null +++ b/apps/web/src/lib/mcp-client.ts @@ -0,0 +1,174 @@ +import { Anthropic } from '@anthropic-ai/sdk'; +import { + ListToolsResultSchema, + CallToolResultSchema, +} from '@modelcontextprotocol/sdk/types.js'; +import { Client } from '@modelcontextprotocol/sdk/client/index.js'; +import { WebSocketClientTransport } from '@modelcontextprotocol/sdk/client/websocket.js'; +import { Tool } from '@anthropic-ai/sdk/resources/index.mjs'; +import { Stream } from '@anthropic-ai/sdk/streaming.mjs'; + +interface Message { + role: 'user' | 'assistant'; + content: string; +} + +export type MessageCallback = (message: Message) => void; + +export class MCPClient { + private anthropicClient: Anthropic; + private messages: Message[] = []; + private mcpClient: Client; + private transport: WebSocketClientTransport; + private tools: Tool[] = []; + + constructor() { + this.anthropicClient = new Anthropic({ + apiKey: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY, + dangerouslyAllowBrowser: true, + }); + + this.mcpClient = new Client( + { name: 'web-client', version: '1.0.0' }, + { capabilities: { + jsonrpc: { + request_response: true, + notifications: true + } + } }, + ); + + // Connect to the local MCP server + this.transport = new WebSocketClientTransport( + new URL('ws://localhost:3001') + ); + } + + async start() { + try { + console.log('Connecting to MCP server...') + await this.mcpClient.connect(this.transport) + console.log('Connected to MCP server') + await this.initMCPTools() + console.log('Initialized MCP tools') + } catch (error) { + console.error('Failed to connect to MCP server:', error) + throw error + } + } + + private async initMCPTools() { + try { + const toolsResults = await this.mcpClient.request( + { method: 'tools/list' }, + ListToolsResultSchema, + ) + this.tools = toolsResults.tools.map(({ inputSchema, ...tool }) => ({ + ...tool, + input_schema: inputSchema, + })) + } catch (error) { + console.error('Failed to initialize tools:', error) + throw error + } + } + + private async processStream( + stream: Stream, + onMessage: MessageCallback + ): Promise { + let currentMessage = ''; + let currentToolName = ''; + let currentToolInputString = ''; + + for await (const chunk of stream) { + switch (chunk.type) { + case 'message_start': + case 'content_block_stop': + // onMessage({ role: 'assistant', content: '\n\n' }); + continue; + + case 'content_block_start': + if (chunk.content_block?.type === 'tool_use') { + currentToolName = chunk.content_block.name; + } + break; + + case 'content_block_delta': + if (chunk.delta.type === 'text_delta') { + currentMessage += chunk.delta.text; + // Send incremental updates + onMessage({ role: 'assistant', content: chunk.delta.text }); + } else if (chunk.delta.type === 'input_json_delta') { + if (currentToolName && chunk.delta.partial_json) { + currentToolInputString += chunk.delta.partial_json; + } + } + break; + + case 'message_delta': + if (chunk.delta.stop_reason === 'tool_use') { + const toolArgs = currentToolInputString + ? JSON.parse(currentToolInputString) + : {}; + + const toolResult = await this.mcpClient.request( + { + method: 'tools/call', + params: { + name: currentToolName, + arguments: toolArgs, + }, + }, + CallToolResultSchema, + ); + + if (currentMessage) { + this.messages.push({ + role: 'assistant', + content: currentMessage, + }); + } + + const formattedResult = JSON.stringify(toolResult.content.flatMap((c) => c.text)); + this.messages.push({ + role: 'user', + content: formattedResult, + }); + + const nextStream = await this.anthropicClient.messages.create({ + messages: this.messages, + model: 'claude-3-5-sonnet-latest', + max_tokens: 8192, + tools: this.tools, + stream: true, + }); + await this.processStream(nextStream, onMessage); + } + break; + + case 'message_stop': + break; + } + } + } + + async sendMessage(message: string, onMessage: MessageCallback) { + try { + this.messages.push({ role: 'user', content: message }); + + const stream = await this.anthropicClient.messages.create({ + messages: this.messages, + model: 'claude-3-5-sonnet-latest', + max_tokens: 8192, + tools: this.tools, + stream: true, + }); + + await this.processStream(stream, onMessage); + } catch (error) { + console.error('Error during message processing:', error); + throw error; + } + } +} \ No newline at end of file diff --git a/apps/web/src/lib/mcp-server.ts b/apps/web/src/lib/mcp-server.ts new file mode 100644 index 0000000..58d5244 --- /dev/null +++ b/apps/web/src/lib/mcp-server.ts @@ -0,0 +1,60 @@ +import { spawn } from 'child_process'; +import { WebSocket } from 'ws'; + +export class MCPServer { + private process: any; + private clients: Set = new Set(); + private isReady: boolean = false; + + async start() { + console.log('Starting MCP server...'); + + if (this.isReady) { + return; + } + + this.process = spawn('uv', [ + '--directory', + '/Users/alrocar/gr/mcp-tinybird', + 'run', + 'mcp-tinybird' + ], { + stdio: ['pipe', 'pipe', 'pipe'], + env: { ...process.env, PYTHONUNBUFFERED: '1' } + }); + + // Log everything immediately + this.process.stdout.on('data', (data: Buffer) => { + console.log('MCP stdout:', data.toString()); + }); + + this.process.stderr.on('data', (data: Buffer) => { + console.log('MCP stderr:', data.toString()); + }); + } + + addClient(ws: WebSocket) { + this.clients.add(ws); + } + + removeClient(ws: WebSocket) { + this.clients.delete(ws); + } + + async handleMessage(message: string, sender: WebSocket) { + // Forward message to MCP server process + this.process.stdin.write(message + '\n'); + + // Handle response from MCP server + this.process.stdout.once('data', (data: Buffer) => { + sender.send(data.toString()); + }); + } + + stop() { + if (this.process) { + this.process.kill(); + } + this.clients.clear(); + } +} \ No newline at end of file diff --git a/apps/web/tsconfig.server.json b/apps/web/tsconfig.server.json new file mode 100644 index 0000000..84c0d06 --- /dev/null +++ b/apps/web/tsconfig.server.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "module": "CommonJS", + "outDir": "dist", + "noEmit": false, + "isolatedModules": false + }, + "include": ["server.ts"] +} \ No newline at end of file diff --git a/apps/web/ws-server.ts b/apps/web/ws-server.ts new file mode 100644 index 0000000..226ae20 --- /dev/null +++ b/apps/web/ws-server.ts @@ -0,0 +1,58 @@ +import { WebSocketServer } from 'ws'; +import { MCPServer } from './src/lib/mcp-server'; +import { fileURLToPath } from 'url'; +import { dirname, join } from 'path'; +import * as dotenv from 'dotenv'; + +// Load environment variables +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); +dotenv.config({ path: join(__dirname, '.env') }); + +const SUBPROTOCOL = "mcp"; +const WS_PORT = 3001; + +async function startWebSocketServer() { + console.log('Starting WebSocket server...'); + + const wss = new WebSocketServer({ + port: WS_PORT, + handleProtocols: (protocols: Set) => { + return Array.from(protocols).includes(SUBPROTOCOL) ? SUBPROTOCOL : false; + } + }); + + const mcpServer = new MCPServer(); + await mcpServer.start(); + + wss.on('connection', (ws) => { + console.log('MCP Client connected'); + mcpServer.addClient(ws); + + ws.on('message', async (message) => { + try { + await mcpServer.handleMessage(message.toString(), ws); + } catch (error) { + console.error('Error handling message:', error); + ws.send(JSON.stringify({ error: 'Internal server error' })); + } + }); + + ws.on('close', () => { + console.log('MCP Client disconnected'); + mcpServer.removeClient(ws); + }); + + ws.on('error', (error) => { + console.error('WebSocket error:', error); + }); + }); + + wss.on('error', (error) => { + console.error('WebSocket server error:', error); + }); + + console.log(`WebSocket server is running on port ${WS_PORT}`); +} + +startWebSocketServer().catch(console.error); \ No newline at end of file From 787d76d5ef80e3f2e021d2388e2d41e1ee8aa0ae Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 11:36:31 +0100 Subject: [PATCH 02/19] format --- apps/web/src/components/tools/auth0/chat.tsx | 36 +++++--- apps/web/src/lib/mcp-client.ts | 94 ++++++++++++++++---- 2 files changed, 98 insertions(+), 32 deletions(-) diff --git a/apps/web/src/components/tools/auth0/chat.tsx b/apps/web/src/components/tools/auth0/chat.tsx index ccc1677..c0a38fc 100644 --- a/apps/web/src/components/tools/auth0/chat.tsx +++ b/apps/web/src/components/tools/auth0/chat.tsx @@ -31,31 +31,39 @@ export function Chat() { initClient() }, []) + const formatToolCall = (toolName: string, args: any): string => { + return `\n[${toolName}] ${JSON.stringify(args, null, 2)}\n`; + } + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!input.trim() || isLoading) return const userMessage = input.trim() setInput('') - setMessages(prev => [...prev, { role: 'user', content: userMessage }]) + + // Create new assistant message + const assistantMessage = { role: 'assistant', content: '' } + setMessages(prev => [...prev, + { role: 'user', content: userMessage }, + assistantMessage + ]) try { setIsLoading(true) - let currentMessage = { role: 'assistant', content: '' } const onMessage: MessageCallback = (message) => { - if (message.content === '\n\n') { - setMessages(prev => [ - ...prev, message - ]) - currentMessage.content = '' + if (message.role === 'tool') { + const toolCall = formatToolCall( + message.toolName || '', + message.toolArgs || {} + ) + assistantMessage.content += toolCall } else { - currentMessage.content += message.content - setMessages(prev => [ - ...prev.slice(0, -1), // Remove previous assistant message - { ...currentMessage } // Add updated message - ]) + assistantMessage.content += message.content } + + setMessages(prev => [...prev.slice(0, -1), { ...assistantMessage }]) } await clientRef.current.sendMessage(userMessage, onMessage) @@ -69,7 +77,7 @@ export function Chat() { return ( - Chat with Claude + {/* Chat with Claude */}
@@ -83,7 +91,7 @@ export function Chat() { }`} >
this.handleDisconnect()); + ws.addEventListener('error', (error) => { + console.error('Transport error:', error); + this.handleDisconnect(); + }); + } + await this.mcpClient.connect(this.transport) + this.isConnected = true; + this.reconnectAttempts = 0; console.log('Connected to MCP server') await this.initMCPTools() console.log('Initialized MCP tools') } catch (error) { console.error('Failed to connect to MCP server:', error) + await this.handleDisconnect(); throw error } } + private async handleDisconnect() { + this.isConnected = false; + if (this.reconnectAttempts < this.maxReconnectAttempts) { + this.reconnectAttempts++; + console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`); + await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second + await this.start(); + } else { + console.error('Max reconnection attempts reached'); + } + } + private async initMCPTools() { try { const toolsResults = await this.mcpClient.request( @@ -85,7 +120,6 @@ export class MCPClient { switch (chunk.type) { case 'message_start': case 'content_block_stop': - // onMessage({ role: 'assistant', content: '\n\n' }); continue; case 'content_block_start': @@ -97,7 +131,6 @@ export class MCPClient { case 'content_block_delta': if (chunk.delta.type === 'text_delta') { currentMessage += chunk.delta.text; - // Send incremental updates onMessage({ role: 'assistant', content: chunk.delta.text }); } else if (chunk.delta.type === 'input_json_delta') { if (currentToolName && chunk.delta.partial_json) { @@ -112,6 +145,14 @@ export class MCPClient { ? JSON.parse(currentToolInputString) : {}; + // Send tool call as a message + onMessage({ + role: 'tool', + content: '', + toolName: currentToolName, + toolArgs: toolArgs + }); + const toolResult = await this.mcpClient.request( { method: 'tools/call', @@ -148,6 +189,12 @@ export class MCPClient { break; case 'message_stop': + if (currentMessage) { + this.messages.push({ + role: 'assistant', + content: currentMessage, + }); + } break; } } @@ -155,10 +202,18 @@ export class MCPClient { async sendMessage(message: string, onMessage: MessageCallback) { try { + if (!this.isConnected) { + await this.start(); + } this.messages.push({ role: 'user', content: message }); + const anthropicMessages: AnthropicMessage[] = this.messages.map(({ role, content }) => ({ + role: role === 'tool' ? 'assistant' : role, + content + })); + const stream = await this.anthropicClient.messages.create({ - messages: this.messages, + messages: anthropicMessages, model: 'claude-3-5-sonnet-latest', max_tokens: 8192, tools: this.tools, @@ -168,6 +223,9 @@ export class MCPClient { await this.processStream(stream, onMessage); } catch (error) { console.error('Error during message processing:', error); + if (error.message?.includes('timeout')) { + await this.handleDisconnect(); + } throw error; } } From 45f6e2bd9ee078e3983868bf608d07d02d94c808 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 11:54:29 +0100 Subject: [PATCH 03/19] wip --- apps/web/src/components/tools/auth0/chat.tsx | 21 ++++++++++---------- apps/web/src/lib/mcp-client.ts | 4 ++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/apps/web/src/components/tools/auth0/chat.tsx b/apps/web/src/components/tools/auth0/chat.tsx index c0a38fc..4a559ef 100644 --- a/apps/web/src/components/tools/auth0/chat.tsx +++ b/apps/web/src/components/tools/auth0/chat.tsx @@ -37,7 +37,7 @@ export function Chat() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() - if (!input.trim() || isLoading) return + if (!input.trim()) return const userMessage = input.trim() setInput('') @@ -50,8 +50,6 @@ export function Chat() { ]) try { - setIsLoading(true) - const onMessage: MessageCallback = (message) => { if (message.role === 'tool') { const toolCall = formatToolCall( @@ -66,11 +64,13 @@ export function Chat() { setMessages(prev => [...prev.slice(0, -1), { ...assistantMessage }]) } - await clientRef.current.sendMessage(userMessage, onMessage) + clientRef.current?.sendMessage(userMessage, onMessage).catch(error => { + console.error('Error sending message:', error) + assistantMessage.content += "\n\nSorry, there was an error. Please try again." + setMessages(prev => [...prev.slice(0, -1), { ...assistantMessage }]) + }) } catch (error) { - console.error('Error sending message:', error) - } finally { - setIsLoading(false) + console.error('Error in handleSubmit:', error) } } @@ -107,11 +107,10 @@ export function Chat() { setInput(e.target.value)} - placeholder="Type a message..." - disabled={isLoading} + placeholder="Type your message..." /> -
diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts index 328ee28..abf03bf 100644 --- a/apps/web/src/lib/mcp-client.ts +++ b/apps/web/src/lib/mcp-client.ts @@ -97,6 +97,7 @@ export class MCPClient { const toolsResults = await this.mcpClient.request( { method: 'tools/list' }, ListToolsResultSchema, + { timeout: 120000 } // 2 minutes timeout ) this.tools = toolsResults.tools.map(({ inputSchema, ...tool }) => ({ ...tool, @@ -162,6 +163,7 @@ export class MCPClient { }, }, CallToolResultSchema, + { timeout: 120000 } // 2 minutes timeout ); if (currentMessage) { @@ -205,6 +207,8 @@ export class MCPClient { if (!this.isConnected) { await this.start(); } + const prompt = "use the auth0 data source, do not use semicolons for queries, do not use JSONExtract instead use dots to access JSON nested attributes" + message = `${prompt}\n${message}` this.messages.push({ role: 'user', content: message }); const anthropicMessages: AnthropicMessage[] = this.messages.map(({ role, content }) => ({ From ad309b9a76d97051194d455b213c3334745c98b0 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 12:36:23 +0100 Subject: [PATCH 04/19] wip --- apps/web/package-lock.json | 469 +++++++++++++++++++ apps/web/package.json | 6 +- apps/web/server.ts | 214 +++++++-- apps/web/src/components/tools/auth0/chat.tsx | 17 +- apps/web/src/lib/mcp-client.ts | 75 +-- 5 files changed, 719 insertions(+), 62 deletions(-) diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json index f95ffb3..95bd3d3 100644 --- a/apps/web/package-lock.json +++ b/apps/web/package-lock.json @@ -54,6 +54,7 @@ "eslint-config-next": "15.1.1", "postcss": "^8", "tailwindcss": "^3.4.1", + "tsx": "^4.19.2", "typescript": "^5" } }, @@ -583,6 +584,414 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", @@ -4341,6 +4750,46 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -9751,6 +10200,26 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/apps/web/package.json b/apps/web/package.json index c545d8f..2ad6301 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -3,9 +3,10 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "ts-node --project tsconfig.server.json server.ts", + "dev": "tsx server.ts", "build": "next build", - "start": "NODE_ENV=production ts-node --project tsconfig.server.json server.ts" + "start": "tsx server.ts", + "lint": "next lint" }, "dependencies": { "@anthropic-ai/sdk": "^0.33.1", @@ -54,6 +55,7 @@ "eslint-config-next": "15.1.1", "postcss": "^8", "tailwindcss": "^3.4.1", + "tsx": "^4.19.2", "typescript": "^5" } } diff --git a/apps/web/server.ts b/apps/web/server.ts index e710e06..c00f16d 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -1,23 +1,207 @@ import { createServer } from 'http' import { parse } from 'url' import next from 'next' -import { WebSocketServer } from 'ws' import { MCPServer } from './src/lib/mcp-server' +import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js' +import cors from 'cors' const dev = process.env.NODE_ENV !== 'production' const hostname = 'localhost' const port = 3000 -const wsPort = 3001 +const sseClients = new Set<{ + send: (data: string) => void; + close: () => void; +}>() // Initialize Next.js const app = next({ dev, hostname, port }) const handle = app.getRequestHandler() app.prepare().then(() => { + const mcpServer = new MCPServer() + mcpServer.start().catch(console.error) + // Create HTTP server const server = createServer(async (req, res) => { try { const parsedUrl = parse(req.url!, true) + + // Handle CORS preflight + if (req.method === 'OPTIONS') { + res.writeHead(200, { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS', + 'Access-Control-Allow-Headers': 'Content-Type', + 'Access-Control-Max-Age': '86400' + }) + res.end() + return + } + + // Handle SSE endpoint + if (parsedUrl.pathname === '/events') { + console.log('New SSE connection request') + + // Set SSE headers + res.writeHead(200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache', + 'Connection': 'keep-alive', + 'Access-Control-Allow-Origin': '*' + }) + + // Force flush headers + res.flushHeaders(); + + // Send the endpoint event first + console.log('Sending endpoint event') + res.write('event: endpoint\n') + res.write(`data: ${req.url}/send\n\n`) + + // Send heartbeat + res.write(':\n\n') + + // Force flush the written data + if (typeof res.flush === 'function') { + res.flush(); + } + + // Create client object + const client = { + send: (data: string) => { + try { + console.log('Sending message to client:', data.substring(0, 100)) + res.write(`data: ${data}\n\n`) + if (typeof res.flush === 'function') { + res.flush(); + } + } catch (error) { + console.error('Error sending message:', error) + } + }, + close: () => { + console.log('Closing client connection') + sseClients.delete(client) + res.end() + } + } + + // Keep connection alive + const keepAlive = setInterval(() => { + try { + res.write(':\n\n') + if (typeof res.flush === 'function') { + res.flush(); + } + } catch (error) { + console.error('Error sending heartbeat:', error) + clearInterval(keepAlive) + client.close() + } + }, 15000) + + // Add client to set + sseClients.add(client) + console.log('Client connected, total clients:', sseClients.size) + + // Handle client disconnect + req.on('close', () => { + console.log('Client disconnected') + clearInterval(keepAlive) + sseClients.delete(client) + }) + + mcpServer.addClient(client) + console.log('Client added to MCP server') + + return + } + + // Handle POST requests for sending messages + if (parsedUrl.pathname === '/events/send') { + console.log('Received POST request to send message') + + let body = ''; + req.on('data', chunk => { + body += chunk.toString(); + }); + + req.on('end', () => { + try { + const message = JSON.parse(body); + console.log('Received message:', message); + + // Handle initialization request + if (message.method === 'initialize') { + // Find the client's SSE connection + for (const client of sseClients) { + // Send initialization response through SSE + client.send(JSON.stringify({ + jsonrpc: '2.0', + id: message.id, + result: { + protocolVersion: '2024-11-05', + serverInfo: { + name: 'tinynest-server', + version: '1.0.0' + }, + capabilities: { + jsonrpc: { + request_response: true, + notifications: true + } + } + } + })); + } + } else { + // Forward all other messages to MCPServer + mcpServer.handleMessage(message); + } + + // Send HTTP response + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ status: 'ok' })); + } catch (error) { + console.error('Error handling message:', error); + res.writeHead(500, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ error: 'Internal server error' })); + } + }); + + return; + } + + // Handle POST requests (messages from client) + if (req.method === 'POST' && parsedUrl.pathname === '/events') { + let body = '' + req.on('data', chunk => { + body += chunk.toString() + }) + + req.on('end', async () => { + try { + const message: JSONRPCMessage = JSON.parse(body) + await mcpServer.handleMessage(JSON.stringify(message), { + send: (response) => { + sseClients.forEach(client => { + client.send(response) + }) + } + }) + res.writeHead(200) + res.end() + } catch (error) { + console.error('Error handling message:', error) + res.writeHead(500) + res.end('Internal Server Error') + } + }) + + return + } + + // Handle Next.js requests await handle(req, res, parsedUrl) } catch (err) { console.error('Error occurred handling', req.url, err) @@ -26,32 +210,8 @@ app.prepare().then(() => { } }) - // Start WebSocket server on different port - const wss = new WebSocketServer({ port: wsPort }) - const mcpServer = new MCPServer() - mcpServer.start().catch(console.error) - - wss.on('connection', (ws) => { - console.log('MCP Client connected') - mcpServer.addClient(ws) - - ws.on('message', async (message) => { - try { - await mcpServer.handleMessage(message.toString(), ws) - } catch (error) { - console.error('Error handling message:', error) - ws.send(JSON.stringify({ error: 'Internal server error' })) - } - }) - - ws.on('close', () => { - console.log('MCP Client disconnected') - mcpServer.removeClient(ws) - }) - }) - server.listen(port, () => { console.log(`> Ready on http://${hostname}:${port}`) - console.log(`> WebSocket server running on ws://${hostname}:${wsPort}`) + console.log(`> SSE endpoint running on http://${hostname}:${port}/events`) }) }) \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/chat.tsx b/apps/web/src/components/tools/auth0/chat.tsx index 4a559ef..0b09b0d 100644 --- a/apps/web/src/components/tools/auth0/chat.tsx +++ b/apps/web/src/components/tools/auth0/chat.tsx @@ -10,26 +10,31 @@ import { ScrollArea } from "@/components/ui/scroll-area" export function Chat() { const [messages, setMessages] = useState>([]) const [input, setInput] = useState('') - const [isLoading, setIsLoading] = useState(false) const clientRef = useRef(new MCPClient()) + const initRef = useRef(false) + // Initialize MCP client useEffect(() => { - let isInitialized = false; - const initClient = async () => { - if (isInitialized) return; - isInitialized = true; + if (initRef.current) return; + initRef.current = true; try { await clientRef.current.start() console.log('MCP client initialized') } catch (error) { console.error('Failed to initialize MCP client:', error) + initRef.current = false; // Allow retry on error } } initClient() - }, []) + + // Cleanup + return () => { + initRef.current = false; + } + }, []) // Empty dependency array const formatToolCall = (toolName: string, args: any): string => { return `\n[${toolName}] ${JSON.stringify(args, null, 2)}\n`; diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts index abf03bf..52f8f23 100644 --- a/apps/web/src/lib/mcp-client.ts +++ b/apps/web/src/lib/mcp-client.ts @@ -4,7 +4,7 @@ import { CallToolResultSchema, } from '@modelcontextprotocol/sdk/types.js'; import { Client } from '@modelcontextprotocol/sdk/client/index.js'; -import { WebSocketClientTransport } from '@modelcontextprotocol/sdk/client/websocket.js'; +import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'; import { Tool } from '@anthropic-ai/sdk/resources/index.mjs'; import { Stream } from '@anthropic-ai/sdk/streaming.mjs'; @@ -23,60 +23,77 @@ type AnthropicMessage = { export type MessageCallback = (message: Message) => void; export class MCPClient { + private static instance: MCPClient | null = null; + private connecting: boolean = false; private anthropicClient: Anthropic; private messages: Message[] = []; private mcpClient: Client; - private transport: WebSocketClientTransport; + private transport: SSEClientTransport; private tools: Tool[] = []; private isConnected = false; private reconnectAttempts = 0; private maxReconnectAttempts = 3; + private eventSource: EventSource | null = null; + private messageHandlers: Set<(data: any) => void> = new Set(); constructor() { + if (MCPClient.instance) { + return MCPClient.instance; + } + this.anthropicClient = new Anthropic({ apiKey: process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY, dangerouslyAllowBrowser: true, }); + + MCPClient.instance = this; } async start() { + if (this.isConnected || this.connecting) { + console.log('Already connected or connecting...'); + return; + } + try { + this.connecting = true; console.log('Connecting to MCP server...') - this.transport = new WebSocketClientTransport( - new URL('ws://localhost:3001') - ) + const sseUrl = 'http://localhost:3000/events' + console.log('Attempting to connect to:', sseUrl) + this.transport = new SSEClientTransport( + new URL(sseUrl) + ) + this.mcpClient = new Client( { name: 'web-client', version: '1.0.0' }, { - capabilities: { - jsonrpc: { - request_response: true, - notifications: true + capabilities: { + jsonrpc: { + request_response: true, + notifications: true + } } } - }) - - // Access underlying WebSocket - const ws = (this.transport as any).ws; - if (ws) { - ws.addEventListener('close', () => this.handleDisconnect()); - ws.addEventListener('error', (error) => { - console.error('Transport error:', error); - this.handleDisconnect(); - }); - } + ) - await this.mcpClient.connect(this.transport) + console.log('Connecting MCP client...') + await this.mcpClient.connect(this.transport); + this.isConnected = true; this.reconnectAttempts = 0; console.log('Connected to MCP server') + + console.log('Starting tools initialization...') await this.initMCPTools() - console.log('Initialized MCP tools') + console.log('Tools initialization complete') } catch (error) { console.error('Failed to connect to MCP server:', error) + this.isConnected = false; await this.handleDisconnect(); - throw error + throw error; + } finally { + this.connecting = false; } } @@ -94,18 +111,22 @@ export class MCPClient { private async initMCPTools() { try { + console.log('Requesting tools list...'); const toolsResults = await this.mcpClient.request( { method: 'tools/list' }, ListToolsResultSchema, { timeout: 120000 } // 2 minutes timeout - ) + ); + console.log('Received tools:', toolsResults); + this.tools = toolsResults.tools.map(({ inputSchema, ...tool }) => ({ ...tool, input_schema: inputSchema, - })) + })); + console.log('Tools initialized:', this.tools.length); } catch (error) { - console.error('Failed to initialize tools:', error) - throw error + console.error('Failed to initialize tools:', error); + throw error; } } From 6d1895f435f3f2b46145fc474668ad4e0122fdbe Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 12:45:52 +0100 Subject: [PATCH 05/19] wip --- apps/web/server.ts | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/apps/web/server.ts b/apps/web/server.ts index c00f16d..93d7744 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -126,7 +126,7 @@ app.prepare().then(() => { body += chunk.toString(); }); - req.on('end', () => { + req.on('end', async () => { try { const message = JSON.parse(body); console.log('Received message:', message); @@ -155,8 +155,36 @@ app.prepare().then(() => { })); } } else { - // Forward all other messages to MCPServer - mcpServer.handleMessage(message); + // Create a promise that will resolve when MCPServer sends a response + const responsePromise = new Promise((resolve) => { + const responseHandler = (response: any) => { + console.log('Got response from MCPServer:', response); + resolve(response); + }; + + // Add the response handler to MCPServer + // mcpServer.once('response', responseHandler); + + // Forward message to MCPServer + mcpServer.handleMessage(message); + }); + + // Wait for response with timeout + const response = await Promise.race([ + responsePromise, + new Promise((_, reject) => + setTimeout(() => reject(new Error('Response timeout')), 5000) + ) + ]); + + console.log('MCPServer response:', response); + + if (response) { + // Send response back through SSE + for (const client of sseClients) { + client.send(JSON.stringify(response)); + } + } } // Send HTTP response @@ -184,11 +212,9 @@ app.prepare().then(() => { const message: JSONRPCMessage = JSON.parse(body) await mcpServer.handleMessage(JSON.stringify(message), { send: (response) => { - sseClients.forEach(client => { - client.send(response) - }) + sseClients.forEach(client => client.send(response)) } - }) + }); res.writeHead(200) res.end() } catch (error) { From f6f95029e2286818500acf00219d4b3b52554a18 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 13:05:54 +0100 Subject: [PATCH 06/19] working sse --- apps/web/server.ts | 37 ++++++------------------------- apps/web/src/lib/mcp-client.ts | 40 +++++++++++++++++++++++++--------- apps/web/src/lib/mcp-server.ts | 19 +++++++++------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/apps/web/server.ts b/apps/web/server.ts index 93d7744..359a47d 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -135,7 +135,6 @@ app.prepare().then(() => { if (message.method === 'initialize') { // Find the client's SSE connection for (const client of sseClients) { - // Send initialization response through SSE client.send(JSON.stringify({ jsonrpc: '2.0', id: message.id, @@ -155,36 +154,14 @@ app.prepare().then(() => { })); } } else { - // Create a promise that will resolve when MCPServer sends a response - const responsePromise = new Promise((resolve) => { - const responseHandler = (response: any) => { - console.log('Got response from MCPServer:', response); - resolve(response); - }; - - // Add the response handler to MCPServer - // mcpServer.once('response', responseHandler); - - // Forward message to MCPServer - mcpServer.handleMessage(message); - }); - - // Wait for response with timeout - const response = await Promise.race([ - responsePromise, - new Promise((_, reject) => - setTimeout(() => reject(new Error('Response timeout')), 5000) - ) - ]); - - console.log('MCPServer response:', response); - - if (response) { - // Send response back through SSE - for (const client of sseClients) { - client.send(JSON.stringify(response)); + // Forward message to MCPServer + await mcpServer.handleMessage(JSON.stringify(message), { + send: (response) => { + for (const client of sseClients) { + client.send(response); + } } - } + }); } // Send HTTP response diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts index 52f8f23..80b9405 100644 --- a/apps/web/src/lib/mcp-client.ts +++ b/apps/web/src/lib/mcp-client.ts @@ -31,6 +31,7 @@ export class MCPClient { private transport: SSEClientTransport; private tools: Tool[] = []; private isConnected = false; + private firstMessage = true; private reconnectAttempts = 0; private maxReconnectAttempts = 3; private eventSource: EventSource | null = null; @@ -80,6 +81,7 @@ export class MCPClient { console.log('Connecting MCP client...') await this.mcpClient.connect(this.transport); + this.firstMessage = true; this.isConnected = true; this.reconnectAttempts = 0; console.log('Connected to MCP server') @@ -163,9 +165,15 @@ export class MCPClient { case 'message_delta': if (chunk.delta.stop_reason === 'tool_use') { - const toolArgs = currentToolInputString - ? JSON.parse(currentToolInputString) - : {}; + let toolArgs = {}; + try { + toolArgs = currentToolInputString + ? JSON.parse(currentToolInputString) + : {}; + } catch (error) { + console.error('Failed to parse tool arguments:', error, currentToolInputString); + toolArgs = {}; + } // Send tool call as a message onMessage({ @@ -194,11 +202,20 @@ export class MCPClient { }); } - const formattedResult = JSON.stringify(toolResult.content.flatMap((c) => c.text)); - this.messages.push({ - role: 'user', - content: formattedResult, - }); + if (toolResult.content.some(c => c.text.includes('[Error]'))) { + this.messages.push({ + role: 'user', + content: `Error executing query. Please fix the query and try again. Error: ${toolResult.content.map(c => c.text).join('\n')}` + }); + } else { + const formattedResult = JSON.stringify(toolResult.content.flatMap((c) => c.text)); + this.messages.push({ + role: 'user', + content: formattedResult, + }); + + } + const nextStream = await this.anthropicClient.messages.create({ messages: this.messages, @@ -228,8 +245,11 @@ export class MCPClient { if (!this.isConnected) { await this.start(); } - const prompt = "use the auth0 data source, do not use semicolons for queries, do not use JSONExtract instead use dots to access JSON nested attributes" - message = `${prompt}\n${message}` + if (this.firstMessage) { + const prompt = "use the auth0 data source, do not use semicolons for queries, do not use JSONExtract instead use dots to access JSON nested attributes. cast JSON nested attributes to its corresponding type this event.data.attribute::String. keep it simple and concise." + message = `${prompt}\n${message}` + this.firstMessage = false; + } this.messages.push({ role: 'user', content: message }); const anthropicMessages: AnthropicMessage[] = this.messages.map(({ role, content }) => ({ diff --git a/apps/web/src/lib/mcp-server.ts b/apps/web/src/lib/mcp-server.ts index 58d5244..c03397f 100644 --- a/apps/web/src/lib/mcp-server.ts +++ b/apps/web/src/lib/mcp-server.ts @@ -1,9 +1,12 @@ import { spawn } from 'child_process'; -import { WebSocket } from 'ws'; + +interface MCPClient { + send: (message: string) => void; +} export class MCPServer { private process: any; - private clients: Set = new Set(); + private clients: Set = new Set(); private isReady: boolean = false; async start() { @@ -33,21 +36,21 @@ export class MCPServer { }); } - addClient(ws: WebSocket) { - this.clients.add(ws); + addClient(client: MCPClient) { + this.clients.add(client); } - removeClient(ws: WebSocket) { - this.clients.delete(ws); + removeClient(client: MCPClient) { + this.clients.delete(client); } - async handleMessage(message: string, sender: WebSocket) { + async handleMessage(message: string, client: MCPClient) { // Forward message to MCP server process this.process.stdin.write(message + '\n'); // Handle response from MCP server this.process.stdout.once('data', (data: Buffer) => { - sender.send(data.toString()); + client.send(data.toString()); }); } From 805671b2534bec0a2e64f452f4628f5e5a2ce7d3 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 13:59:52 +0100 Subject: [PATCH 07/19] full sse --- apps/web/package-lock.json | 30 +++++++++ apps/web/package.json | 2 + apps/web/src/lib/mcp-server.ts | 118 ++++++++++++++++++++++++--------- 3 files changed, 118 insertions(+), 32 deletions(-) diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json index 95bd3d3..7cc01d8 100644 --- a/apps/web/package-lock.json +++ b/apps/web/package-lock.json @@ -28,6 +28,7 @@ "clsx": "^2.1.1", "date-fns": "^4.1.0", "dotenv": "^16.4.7", + "eventsource": "^3.0.2", "init": "^0.1.2", "lucide-react": "^0.468.0", "next": "15.1.1", @@ -46,6 +47,7 @@ "devDependencies": { "@eslint/eslintrc": "^3", "@tailwindcss/typography": "^0.5.15", + "@types/eventsource": "^1.1.15", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", @@ -2647,6 +2649,13 @@ "@types/estree": "*" } }, + "node_modules/@types/eventsource": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@types/eventsource/-/eventsource-1.1.15.tgz", + "integrity": "sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -5323,6 +5332,27 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/eventsource": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.2.tgz", + "integrity": "sha512-YolzkJNxsTL3tCJMWFxpxtG2sCjbZ4LQUBUrkdaJK0ub0p6lmJt+2+1SwhKjLc652lpH9L/79Ptez972H9tphw==", + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.0.tgz", + "integrity": "sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/execa": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", diff --git a/apps/web/package.json b/apps/web/package.json index 2ad6301..6ca44e6 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -29,6 +29,7 @@ "clsx": "^2.1.1", "date-fns": "^4.1.0", "dotenv": "^16.4.7", + "eventsource": "^3.0.2", "init": "^0.1.2", "lucide-react": "^0.468.0", "next": "15.1.1", @@ -47,6 +48,7 @@ "devDependencies": { "@eslint/eslintrc": "^3", "@tailwindcss/typography": "^0.5.15", + "@types/eventsource": "^1.1.15", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", diff --git a/apps/web/src/lib/mcp-server.ts b/apps/web/src/lib/mcp-server.ts index c03397f..ba65737 100644 --- a/apps/web/src/lib/mcp-server.ts +++ b/apps/web/src/lib/mcp-server.ts @@ -1,13 +1,15 @@ -import { spawn } from 'child_process'; +import * as EventSourceImport from 'eventsource'; +const EventSource = EventSourceImport.EventSource; interface MCPClient { send: (message: string) => void; } export class MCPServer { - private process: any; private clients: Set = new Set(); private isReady: boolean = false; + private eventSource: EventSource; + private sessionId: string | null = null; async start() { console.log('Starting MCP server...'); @@ -16,24 +18,83 @@ export class MCPServer { return; } - this.process = spawn('uv', [ - '--directory', - '/Users/alrocar/gr/mcp-tinybird', - 'run', - 'mcp-tinybird' - ], { - stdio: ['pipe', 'pipe', 'pipe'], - env: { ...process.env, PYTHONUNBUFFERED: '1' } - }); - - // Log everything immediately - this.process.stdout.on('data', (data: Buffer) => { - console.log('MCP stdout:', data.toString()); - }); - - this.process.stderr.on('data', (data: Buffer) => { - console.log('MCP stderr:', data.toString()); - }); + try { + // First establish SSE connection + console.log('Establishing SSE connection...'); + this.eventSource = new EventSource('http://localhost:3001/sse'); + + // Get session ID from the endpoint event + await new Promise((resolve, reject) => { + this.eventSource.addEventListener('endpoint', (event: any) => { + console.log('Received endpoint event:', event.data); + const match = event.data.match(/session_id=([^&]+)/); + if (match) { + this.sessionId = match[1]; + console.log('Got session ID:', this.sessionId); + resolve(); + } else { + console.error('No session ID found in endpoint event'); + reject(new Error('No session ID found in endpoint event')); + } + }); + + this.eventSource.onerror = (error) => { + console.error('SSE connection error:', error); + reject(error); + }; + }); + + // Handle incoming messages + this.eventSource.onmessage = (event) => { + console.log('Received SSE message:', event.data); + for (const client of this.clients) { + client.send(event.data); + } + }; + + this.isReady = true; + console.log('MCP server ready'); + } catch (error) { + console.error('Failed to connect to MCP server:', error); + throw error; + } + } + + async handleMessage(message: string, client: MCPClient) { + if (!this.sessionId) { + console.error('No session ID available'); + throw new Error('No session ID available'); + } + + console.log('Sending message with session ID:', this.sessionId); + console.log('Message:', message); + + try { + // Send message with session ID + const response = await fetch(`http://localhost:3001/messages?session_id=${this.sessionId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: message, + // Add these options to handle the connection better + keepalive: true, + signal: AbortSignal.timeout(5000) // 5 second timeout + }); + + // Don't try to read the response body, just check status + if (response.status !== 202) { + throw new Error(`Failed to send message: ${response.status}`); + } + } catch (error) { + if (error instanceof Error && error.name === 'AbortError') { + console.log('Message accepted (timeout is normal)'); + return; + } + console.error('Error sending message:', error); + throw error; + } } addClient(client: MCPClient) { @@ -44,20 +105,13 @@ export class MCPServer { this.clients.delete(client); } - async handleMessage(message: string, client: MCPClient) { - // Forward message to MCP server process - this.process.stdin.write(message + '\n'); - - // Handle response from MCP server - this.process.stdout.once('data', (data: Buffer) => { - client.send(data.toString()); - }); - } - stop() { - if (this.process) { - this.process.kill(); + if (this.eventSource) { + console.log('Closing SSE connection'); + this.eventSource.close(); } this.clients.clear(); + this.isReady = false; + this.sessionId = null; } } \ No newline at end of file From eb235008ba6baf62252931e74a07e1896e83a2d6 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 16:57:56 +0100 Subject: [PATCH 08/19] reduce recursion --- apps/web/src/lib/mcp-client.ts | 304 ++++++++++++++++++++------------- 1 file changed, 190 insertions(+), 114 deletions(-) diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts index 80b9405..e8a15e4 100644 --- a/apps/web/src/lib/mcp-client.ts +++ b/apps/web/src/lib/mcp-client.ts @@ -1,4 +1,4 @@ -import { Anthropic } from '@anthropic-ai/sdk'; +import { Anthropic, APIError } from '@anthropic-ai/sdk'; import { ListToolsResultSchema, CallToolResultSchema, @@ -134,144 +134,220 @@ export class MCPClient { private async processStream( stream: Stream, - onMessage: MessageCallback + onMessage: MessageCallback, + depth: number = 0 // Track recursion depth ): Promise { + // Prevent too deep recursion + if (depth > 4) { + onMessage({ + role: 'assistant', + content: 'Request too complex. Start a new chat with a more specific question.' + }); + return; + } + let currentMessage = ''; let currentToolName = ''; let currentToolInputString = ''; - for await (const chunk of stream) { - switch (chunk.type) { - case 'message_start': - case 'content_block_stop': - continue; + try { + for await (const chunk of stream) { + switch (chunk.type) { + case 'message_start': + case 'content_block_stop': + continue; - case 'content_block_start': - if (chunk.content_block?.type === 'tool_use') { - currentToolName = chunk.content_block.name; - } - break; + case 'content_block_start': + if (chunk.content_block?.type === 'tool_use') { + currentToolName = chunk.content_block.name; + } + break; - case 'content_block_delta': - if (chunk.delta.type === 'text_delta') { - currentMessage += chunk.delta.text; - onMessage({ role: 'assistant', content: chunk.delta.text }); - } else if (chunk.delta.type === 'input_json_delta') { - if (currentToolName && chunk.delta.partial_json) { - currentToolInputString += chunk.delta.partial_json; - } - } - break; + case 'content_block_delta': + if (chunk.delta.type === 'text_delta') { + currentMessage += chunk.delta.text; + onMessage({ role: 'assistant', content: chunk.delta.text }); + } else if (chunk.delta.type === 'input_json_delta') { + if (currentToolName && chunk.delta.partial_json) { + currentToolInputString += chunk.delta.partial_json; + } + } + break; - case 'message_delta': - if (chunk.delta.stop_reason === 'tool_use') { - let toolArgs = {}; - try { - toolArgs = currentToolInputString - ? JSON.parse(currentToolInputString) - : {}; - } catch (error) { - console.error('Failed to parse tool arguments:', error, currentToolInputString); - toolArgs = {}; - } + case 'message_delta': + if (chunk.delta.stop_reason === 'tool_use') { + let toolArgs = {}; + try { + toolArgs = currentToolInputString + ? JSON.parse(currentToolInputString) + : {}; + } catch (error) { + console.error('Failed to parse tool arguments:', error, currentToolInputString); + toolArgs = {}; + } - // Send tool call as a message - onMessage({ - role: 'tool', - content: '', - toolName: currentToolName, - toolArgs: toolArgs - }); + // Send tool call as a message + onMessage({ + role: 'tool', + content: '', + toolName: currentToolName, + toolArgs: toolArgs + }); - const toolResult = await this.mcpClient.request( - { - method: 'tools/call', - params: { - name: currentToolName, - arguments: toolArgs, - }, - }, - CallToolResultSchema, - { timeout: 120000 } // 2 minutes timeout - ); + const toolResult = await this.mcpClient.request( + { + method: 'tools/call', + params: { + name: currentToolName, + arguments: toolArgs, + }, + }, + CallToolResultSchema, + { timeout: 120000 } // 2 minutes timeout + ); - if (currentMessage) { - this.messages.push({ - role: 'assistant', - content: currentMessage, - }); - } + if (currentMessage) { + this.messages.push({ + role: 'assistant', + content: currentMessage, + }); + } - if (toolResult.content.some(c => c.text.includes('[Error]'))) { - this.messages.push({ - role: 'user', - content: `Error executing query. Please fix the query and try again. Error: ${toolResult.content.map(c => c.text).join('\n')}` - }); - } else { - const formattedResult = JSON.stringify(toolResult.content.flatMap((c) => c.text)); - this.messages.push({ - role: 'user', - content: formattedResult, - }); + if (toolResult.content.some(c => c.text.includes('[Error]'))) { + this.messages.push({ + role: 'user', + content: `Error executing query. Please fix the query and try again. Error: ${toolResult.content.map(c => c.text).join('\n')}` + }); + } else { + const formattedResult = JSON.stringify(toolResult.content.flatMap((c) => c.text)); + this.messages.push({ + role: 'user', + content: formattedResult, + }); + } - } - + try { + const nextStream = await this.anthropicClient.messages.create({ + messages: this.messages, + model: 'claude-3-5-sonnet-latest', + max_tokens: 8192, + tools: this.tools, + stream: true, + }).catch(async (err) => { + if (err instanceof Anthropic.APIError) { + console.log('Anthropic API Error in tool use:', err.status, err.name); + if (err.status === 429) { + onMessage({ + role: 'assistant', + content: 'Rate limit exceeded. Please wait a moment before sending more messages.' + }); + return null; + } + } + throw err; + }); - const nextStream = await this.anthropicClient.messages.create({ - messages: this.messages, - model: 'claude-3-5-sonnet-latest', - max_tokens: 8192, - tools: this.tools, - stream: true, - }); - await this.processStream(nextStream, onMessage); - } - break; + if (nextStream) { + await this.processStream(nextStream, onMessage, depth + 1); + } + } catch (error: any) { + // Handle rate limits in nested stream creation + if (error.status === 429 || error.message?.includes('rate limit')) { + onMessage({ + role: 'assistant', + content: 'Rate limit exceeded. Please wait a moment before sending more messages.' + }); + return; + } + throw error; + } + } + break; - case 'message_stop': - if (currentMessage) { - this.messages.push({ - role: 'assistant', - content: currentMessage, + case 'message_stop': + if (currentMessage) { + this.messages.push({ + role: 'assistant', + content: currentMessage, + }); + } + break; + } + } + } catch (error: any) { + // Check for rate limit errors + if (error.status === 429 || error.message?.includes('rate limit')) { + onMessage({ + role: 'assistant', + content: 'Rate limit exceeded. Please wait a moment before sending more messages.' }); - } - break; - } + // Cancel the stream + stream.controller.abort(); + return; + } + + // Handle other errors + console.error('Error in processStream:', error); + onMessage({ + role: 'assistant', + content: 'An error occurred while processing your request. Please try again.' + }); + throw error; } } async sendMessage(message: string, onMessage: MessageCallback) { try { - if (!this.isConnected) { - await this.start(); - } - if (this.firstMessage) { - const prompt = "use the auth0 data source, do not use semicolons for queries, do not use JSONExtract instead use dots to access JSON nested attributes. cast JSON nested attributes to its corresponding type this event.data.attribute::String. keep it simple and concise." - message = `${prompt}\n${message}` - this.firstMessage = false; - } - this.messages.push({ role: 'user', content: message }); + if (!this.isConnected) { + await this.start(); + } + if (this.firstMessage) { + const prompt = "you MUST keep output tokens to minimal but answering the question. use the auth0 data source, do not use semicolons for queries, do not use JSONExtract instead use dots to access JSON nested attributes. cast JSON nested attributes to its corresponding type this event.data.attribute::String. keep it simple and concise. do not append-insights" + message = `${prompt}\n${message}` + this.firstMessage = false; + } + this.messages.push({ role: 'user', content: message }); - const anthropicMessages: AnthropicMessage[] = this.messages.map(({ role, content }) => ({ - role: role === 'tool' ? 'assistant' : role, - content - })); + const anthropicMessages: AnthropicMessage[] = this.messages.map(({ role, content }) => ({ + role: role === 'tool' ? 'assistant' : role, + content + })); - const stream = await this.anthropicClient.messages.create({ - messages: anthropicMessages, - model: 'claude-3-5-sonnet-latest', - max_tokens: 8192, - tools: this.tools, - stream: true, - }); + const stream = await this.anthropicClient.messages.create({ + messages: anthropicMessages, + model: 'claude-3-5-sonnet-latest', + max_tokens: 8192, + tools: this.tools, + stream: true, + }).catch(async (err) => { + if (err instanceof Anthropic.APIError) { + console.log('Anthropic API Error:', err.status, err.name); + if (err.status === 429) { + onMessage({ + role: 'assistant', + content: 'Rate limit exceeded. Please wait a moment before sending more messages.' + }); + return null; + } + } + throw err; + }); - await this.processStream(stream, onMessage); + if (stream) { + await this.processStream(stream, onMessage, 0); + } } catch (error) { - console.error('Error during message processing:', error); - if (error.message?.includes('timeout')) { - await this.handleDisconnect(); - } - throw error; + console.error('Error during message processing:', error); + if (error instanceof Anthropic.APIError) { + if (error.status === 429) { + onMessage({ + role: 'assistant', + content: 'Rate limit exceeded. Please wait a moment before sending more messages.' + }); + return; + } + } + throw error; } } } \ No newline at end of file From d3ae5fd5d28edc93efb9605c64f46526af42b62a Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 17:46:01 +0100 Subject: [PATCH 09/19] fix --- .../src/components/tools/auth0/dashboard.tsx | 42 ++++++++++--------- apps/web/src/lib/mcp-client.ts | 2 +- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/apps/web/src/components/tools/auth0/dashboard.tsx b/apps/web/src/components/tools/auth0/dashboard.tsx index 0f59d72..dc34bbb 100644 --- a/apps/web/src/components/tools/auth0/dashboard.tsx +++ b/apps/web/src/components/tools/auth0/dashboard.tsx @@ -33,6 +33,8 @@ import { import { ChevronDown, ChevronUp } from "lucide-react" import { Chat } from './chat' +const ANTHROPIC_API_KEY = process.env.NEXT_PUBLIC_ANTHROPIC_API_KEY; + interface SummaryMetrics { total_users: number total_applications: number @@ -492,25 +494,27 @@ export default function Auth0Dashboard() { /> - - - -
- Chat Assistant - - - -
-
- - - - - -
-
+ {ANTHROPIC_API_KEY && ( + + + +
+ Chat Assistant + + + +
+
+ + + + + +
+
+ )}
) diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts index e8a15e4..6e8ca1e 100644 --- a/apps/web/src/lib/mcp-client.ts +++ b/apps/web/src/lib/mcp-client.ts @@ -302,7 +302,7 @@ export class MCPClient { await this.start(); } if (this.firstMessage) { - const prompt = "you MUST keep output tokens to minimal but answering the question. use the auth0 data source, do not use semicolons for queries, do not use JSONExtract instead use dots to access JSON nested attributes. cast JSON nested attributes to its corresponding type this event.data.attribute::String. keep it simple and concise. do not append-insights" + const prompt = "you MUST keep output tokens to minimal. Follow this process: 1. get sample data from auth0 data source 2. guess schema looking at the data and remember the nested attributes names 3. build a query to answer the question 4. if the query fails ask for confirmation before run-select-query again. RULES: DO NOT use semicolons for queries, DO NOT use JSONExtract instead use dots to access JSON nested attributes. cast JSON nested attributes to its corresponding type this event.data.attribute::String. keep it simple and concise. do not append-insights. answer the question in a single sentence." message = `${prompt}\n${message}` this.firstMessage = false; } From ec506b060263fccda57babe79f29211796be10a0 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 17:53:07 +0100 Subject: [PATCH 10/19] fix --- apps/web/src/app/api/mcp/route.ts | 6 - apps/web/src/app/api/ws/route.ts | 56 ------- apps/web/src/app/mcp_client.ts | 242 ------------------------------ apps/web/tsconfig.server.json | 10 -- 4 files changed, 314 deletions(-) delete mode 100644 apps/web/src/app/api/mcp/route.ts delete mode 100644 apps/web/src/app/api/ws/route.ts delete mode 100644 apps/web/src/app/mcp_client.ts delete mode 100644 apps/web/tsconfig.server.json diff --git a/apps/web/src/app/api/mcp/route.ts b/apps/web/src/app/api/mcp/route.ts deleted file mode 100644 index 8d87055..0000000 --- a/apps/web/src/app/api/mcp/route.ts +++ /dev/null @@ -1,6 +0,0 @@ -import WebSocketSingleton from '@/lib/websocket-server'; - -export async function GET() { - await WebSocketSingleton.getInstance(); - return new Response('WebSocket server is running', { status: 200 }); -} \ No newline at end of file diff --git a/apps/web/src/app/api/ws/route.ts b/apps/web/src/app/api/ws/route.ts deleted file mode 100644 index 0a599ba..0000000 --- a/apps/web/src/app/api/ws/route.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { WebSocketServer } from 'ws'; -import { MCPServer } from '@/lib/mcp-server'; - -const SUBPROTOCOL = "mcp"; -const WS_PORT = 3001; - -let wss: WebSocketServer | null = null; - -if (process.env.NODE_ENV === 'development' && !wss) { - try { - wss = new WebSocketServer({ - port: WS_PORT, - handleProtocols: (protocols: Set) => { - return Array.from(protocols).includes(SUBPROTOCOL) ? SUBPROTOCOL : false; - } - }); - - const mcpServer = new MCPServer(); - mcpServer.start().catch(console.error); - - wss.on('connection', (ws) => { - console.log('MCP Client connected'); - mcpServer.addClient(ws); - - ws.on('message', async (message) => { - try { - await mcpServer.handleMessage(message.toString(), ws); - } catch (error) { - console.error('Error handling message:', error); - ws.send(JSON.stringify({ error: 'Internal server error' })); - } - }); - - ws.on('close', () => { - console.log('MCP Client disconnected'); - mcpServer.removeClient(ws); - }); - - ws.on('error', (error) => { - console.error('WebSocket error:', error); - }); - }); - - wss.on('error', (error) => { - console.error('WebSocket server error:', error); - }); - - console.log(`WebSocket server is running on port ${WS_PORT}`); - } catch (error) { - console.error('Failed to start WebSocket server:', error); - } -} - -export async function GET() { - return new Response('WebSocket server status: ' + (wss ? 'running' : 'not running')); -} \ No newline at end of file diff --git a/apps/web/src/app/mcp_client.ts b/apps/web/src/app/mcp_client.ts deleted file mode 100644 index 79432a5..0000000 --- a/apps/web/src/app/mcp_client.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { Anthropic } from '@anthropic-ai/sdk'; - -import { - StdioClientTransport, - StdioServerParameters, -} from '@modelcontextprotocol/sdk/client/stdio.js'; -import { - ListToolsResultSchema, - CallToolResultSchema, -} from '@modelcontextprotocol/sdk/types.js'; -import { Client } from '@modelcontextprotocol/sdk/client/index.js'; -import chalk from 'chalk'; -import readline from 'readline/promises'; -import { Tool } from '@anthropic-ai/sdk/resources/index.mjs'; -import { Stream } from '@anthropic-ai/sdk/streaming.mjs'; - -const EXIT_COMMAND = 'exit'; - -const styles = { - prompt: chalk.green('You: '), - assistant: chalk.blue('Claude: '), - tool: { - name: chalk.cyan.bold, - args: chalk.yellow, - bracket: chalk.dim, - }, - error: chalk.red, - info: chalk.blue, - success: chalk.green, - warning: chalk.yellow, - separator: chalk.gray('─'.repeat(50)), -}; - -interface Message { - role: 'user' | 'assistant'; - content: string; -} - -export class InteractiveCLI { - private anthropicClient: Anthropic; - private messages: Message[] = []; - private mcpClient: Client; - private transport: StdioClientTransport; - private tools: Tool[] = []; - private rl: readline.Interface; - - constructor(serverConfig: StdioServerParameters) { - this.anthropicClient = new Anthropic({ - apiKey: process.env.ANTHROPIC_API_KEY, - }); - - this.mcpClient = new Client( - { name: 'cli-client', version: '1.0.0' }, - { capabilities: {} }, - ); - - this.transport = new StdioClientTransport(serverConfig); - this.rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - }); - } - - async start() { - try { - console.log(styles.separator); - console.log(styles.info('🤖 Interactive Claude CLI')); - console.log( - styles.info(`Type your queries or "${EXIT_COMMAND}" to exit`), - ); - console.log(styles.separator); - - await this.mcpClient.connect(this.transport); - await this.initMCPTools(); - - await this.chat_loop(); - } catch (error) { - console.error(styles.error('Failed to initialize tools:'), error); - process.exit(1); - } finally { - this.rl.close(); - process.exit(0); - } - } - - private async initMCPTools() { - const toolsResults = await this.mcpClient.request( - { method: 'tools/list' }, - ListToolsResultSchema, - ); - this.tools = toolsResults.tools.map(({ inputSchema, ...tool }) => ({ - ...tool, - input_schema: inputSchema, - })); - } - - private formatToolCall(toolName: string, args: any): string { - return ( - '\n' + - styles.tool.bracket('[') + - styles.tool.name(toolName) + - styles.tool.bracket('] ') + - styles.tool.args(JSON.stringify(args, null, 2)) + - '\n' - ); - } - - private formatJSON(json: string): string { - return json - .replace(/"([^"]+)":/g, chalk.blue('"$1":')) - .replace(/: "([^"]+)"/g, ': ' + chalk.green('"$1"')); - } - - private async processStream( - stream: Stream, - ): Promise { - let currentMessage = ''; - let currentToolName = ''; - let currentToolInputString = ''; - - process.stdout.write(styles.assistant); - for await (const chunk of stream) { - switch (chunk.type) { - case 'message_start': - case 'content_block_stop': - continue; - - case 'content_block_start': - if (chunk.content_block?.type === 'tool_use') { - currentToolName = chunk.content_block.name; - } - break; - - case 'content_block_delta': - if (chunk.delta.type === 'text_delta') { - process.stdout.write(chunk.delta.text); - currentMessage += chunk.delta.text; - } else if (chunk.delta.type === 'input_json_delta') { - if (currentToolName && chunk.delta.partial_json) { - currentToolInputString += chunk.delta.partial_json; - } - } - break; - - case 'message_delta': - if (chunk.delta.stop_reason === 'tool_use') { - const toolArgs = currentToolInputString - ? JSON.parse(currentToolInputString) - : {}; - - console.log(this.formatToolCall(currentToolName, toolArgs)); - const toolResult = await this.mcpClient.request( - { - method: 'tools/call', - params: { - name: currentToolName, - arguments: toolArgs, - }, - }, - CallToolResultSchema, - ); - - if (currentMessage) { - this.messages.push({ - role: 'assistant', - content: currentMessage, - }); - } - - const formattedResult = this.formatJSON( - JSON.stringify(toolResult.content.flatMap((c) => c.text)), - ); - - this.messages.push({ - role: 'user', - content: formattedResult, - }); - - const nextStream = await this.anthropicClient.messages.create({ - messages: this.messages, - model: 'claude-3-5-sonnet-20241022', - max_tokens: 8192, - tools: this.tools, - stream: true, - }); - await this.processStream(nextStream); - } - break; - - case 'message_stop': - break; - - default: - console.warn( - styles.warning(`Unknown event type: ${JSON.stringify(chunk)}`), - ); - } - } - } - - private async processQuery(query: string) { - try { - this.messages.push({ role: 'user', content: query }); - - const stream = await this.anthropicClient.messages.create({ - messages: this.messages, - model: 'claude-3-5-sonnet-20241022', - max_tokens: 8192, - tools: this.tools, - stream: true, - }); - await this.processStream(stream); - } catch (error) { - console.error(styles.error('\nError during query processing:'), error); - if (error instanceof Error) { - process.stdout.write( - styles.assistant + - 'I apologize, but I encountered an error: ' + - error.message + - '\n', - ); - } - } - } - - private async chat_loop() { - while (true) { - try { - const query = (await this.rl.question(styles.prompt)).trim(); - if (query.toLowerCase() === EXIT_COMMAND) { - console.log(styles.warning('\nGoodbye! 👋')); - break; - } - - await this.processQuery(query); - console.log('\n' + styles.separator); - } catch (error) { - console.error(styles.error('\nError:'), error); - } - } - } -} \ No newline at end of file diff --git a/apps/web/tsconfig.server.json b/apps/web/tsconfig.server.json deleted file mode 100644 index 84c0d06..0000000 --- a/apps/web/tsconfig.server.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "module": "CommonJS", - "outDir": "dist", - "noEmit": false, - "isolatedModules": false - }, - "include": ["server.ts"] -} \ No newline at end of file From 686ad521ff666fffdb6f3bd0caea317c9c9334ab Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 17:54:09 +0100 Subject: [PATCH 11/19] fix --- apps/web/ws-server.ts | 58 ------------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 apps/web/ws-server.ts diff --git a/apps/web/ws-server.ts b/apps/web/ws-server.ts deleted file mode 100644 index 226ae20..0000000 --- a/apps/web/ws-server.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { WebSocketServer } from 'ws'; -import { MCPServer } from './src/lib/mcp-server'; -import { fileURLToPath } from 'url'; -import { dirname, join } from 'path'; -import * as dotenv from 'dotenv'; - -// Load environment variables -const __filename = fileURLToPath(import.meta.url); -const __dirname = dirname(__filename); -dotenv.config({ path: join(__dirname, '.env') }); - -const SUBPROTOCOL = "mcp"; -const WS_PORT = 3001; - -async function startWebSocketServer() { - console.log('Starting WebSocket server...'); - - const wss = new WebSocketServer({ - port: WS_PORT, - handleProtocols: (protocols: Set) => { - return Array.from(protocols).includes(SUBPROTOCOL) ? SUBPROTOCOL : false; - } - }); - - const mcpServer = new MCPServer(); - await mcpServer.start(); - - wss.on('connection', (ws) => { - console.log('MCP Client connected'); - mcpServer.addClient(ws); - - ws.on('message', async (message) => { - try { - await mcpServer.handleMessage(message.toString(), ws); - } catch (error) { - console.error('Error handling message:', error); - ws.send(JSON.stringify({ error: 'Internal server error' })); - } - }); - - ws.on('close', () => { - console.log('MCP Client disconnected'); - mcpServer.removeClient(ws); - }); - - ws.on('error', (error) => { - console.error('WebSocket error:', error); - }); - }); - - wss.on('error', (error) => { - console.error('WebSocket server error:', error); - }); - - console.log(`WebSocket server is running on port ${WS_PORT}`); -} - -startWebSocketServer().catch(console.error); \ No newline at end of file From 9cf2791239cb5b7316d0514efa90e7e34d8b2a6e Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:00:47 +0100 Subject: [PATCH 12/19] fix --- apps/web/pnpm-lock.yaml | 812 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 800 insertions(+), 12 deletions(-) diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml index 854ec3e..8725ad5 100644 --- a/apps/web/pnpm-lock.yaml +++ b/apps/web/pnpm-lock.yaml @@ -8,6 +8,12 @@ importers: .: dependencies: + '@anthropic-ai/sdk': + specifier: ^0.33.1 + version: 0.33.1 + '@modelcontextprotocol/sdk': + specifier: ^1.0.4 + version: 1.0.4 '@nivo/core': specifier: ^0.88.0 version: 0.88.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0) @@ -44,6 +50,12 @@ importers: '@shadcn/ui': specifier: ^0.0.4 version: 0.0.4 + '@types/ws': + specifier: ^8.5.13 + version: 8.5.13 + chalk: + specifier: ^5.4.1 + version: 5.4.1 class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -53,6 +65,12 @@ importers: date-fns: specifier: ^4.1.0 version: 4.1.0 + dotenv: + specifier: ^16.4.7 + version: 16.4.7 + eventsource: + specifier: ^3.0.2 + version: 3.0.2 init: specifier: ^0.1.2 version: 0.1.2 @@ -88,14 +106,23 @@ importers: version: 2.6.0 tailwindcss-animate: specifier: ^1.0.7 - version: 1.0.7(tailwindcss@3.4.17) + version: 1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2))) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.17.10)(typescript@5.7.2) + ws: + specifier: ^8.18.0 + version: 8.18.0 devDependencies: '@eslint/eslintrc': specifier: ^3 version: 3.2.0 '@tailwindcss/typography': specifier: ^0.5.15 - version: 0.5.15(tailwindcss@3.4.17) + version: 0.5.15(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2))) + '@types/eventsource': + specifier: ^1.1.15 + version: 1.1.15 '@types/node': specifier: ^20 version: 20.17.10 @@ -105,6 +132,9 @@ importers: '@types/react-dom': specifier: ^19 version: 19.0.2(@types/react@19.0.1) + concurrently: + specifier: ^9.1.1 + version: 9.1.1 eslint: specifier: ^9 version: 9.17.0(jiti@1.21.7) @@ -116,7 +146,10 @@ importers: version: 8.4.49 tailwindcss: specifier: ^3.4.1 - version: 3.4.17 + version: 3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2)) + tsx: + specifier: ^4.19.2 + version: 4.19.2 typescript: specifier: ^5 version: 5.7.2 @@ -135,6 +168,9 @@ packages: resolution: {integrity: sha512-2aDL3WUv8hMJb2L3r/PIQWsTLyq7RQr3v9xD16fiz6O8ys1xEyLhhTOv8gxtZvJiTzjTF5pHoArvRdesGL1DMQ==} hasBin: true + '@anthropic-ai/sdk@0.33.1': + resolution: {integrity: sha512-VrlbxiAdVRGuKP2UQlCnsShDHJKWepzvfRCkZMpU+oaUdKLpOfmylLMRojGrAgebV+kDtPjewCVP0laHXg+vsA==} + '@babel/code-frame@7.26.2': resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} engines: {node: '>=6.9.0'} @@ -246,9 +282,157 @@ packages: resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} engines: {node: '>=6.9.0'} + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + '@emnapi/runtime@1.3.1': resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==} + '@esbuild/aix-ppc64@0.23.1': + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.23.1': + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.23.1': + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.23.1': + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.23.1': + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.23.1': + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.23.1': + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.23.1': + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.23.1': + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.23.1': + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.23.1': + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.23.1': + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.23.1': + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.23.1': + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.23.1': + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.23.1': + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.23.1': + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.23.1': + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.1': + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.23.1': + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.23.1': + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.23.1': + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.23.1': + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.23.1': + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.4.1': resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -445,6 +629,12 @@ packages: '@jridgewell/trace-mapping@0.3.25': resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@modelcontextprotocol/sdk@1.0.4': + resolution: {integrity: sha512-C+jw1lF6HSGzs7EZpzHbXfzz9rj9him4BaoumlTciW/IDDgIpweF/qiCWKlP02QKg5PPcgY6xY2WCt5y2tpYow==} + '@next/env@15.1.1': resolution: {integrity: sha512-ldU8IpUqxa87LsWyMh8eIqAzejt8+ZuEsdtCV+fpDog++cBO5b/PWaI7wQQwun8LKJeFFpnY4kv/6r+/dCON6A==} @@ -937,6 +1127,18 @@ packages: '@ts-morph/common@0.19.0': resolution: {integrity: sha512-Unz/WHmd4pGax91rdIKWi51wnVUW11QttMEPpBiBgIewnc9UQIX7UDLxr5vRlqeByXCwhkF6VabSsI0raWcyAQ==} + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + '@types/d3-array@3.2.1': resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} @@ -979,6 +1181,9 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/eventsource@1.1.15': + resolution: {integrity: sha512-XQmGcbnxUNa06HR3VBVkc9+A2Vpi9ZyLJcdS5dwaQQ/4ZMWFO+5c90FnMUpbtMZwB/FChoYHwuVg8TvkECacTA==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -994,6 +1199,12 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} + '@types/node-fetch@2.6.12': + resolution: {integrity: sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==} + + '@types/node@18.19.68': + resolution: {integrity: sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==} + '@types/node@20.17.10': resolution: {integrity: sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA==} @@ -1014,6 +1225,9 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + '@types/ws@8.5.13': + resolution: {integrity: sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==} + '@typescript-eslint/eslint-plugin@8.18.1': resolution: {integrity: sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1064,11 +1278,19 @@ packages: '@ungap/structured-clone@1.2.1': resolution: {integrity: sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + acorn@8.14.0: resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} engines: {node: '>=0.4.0'} @@ -1078,6 +1300,10 @@ packages: resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} engines: {node: '>= 14'} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} @@ -1104,6 +1330,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} @@ -1157,6 +1386,9 @@ packages: resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} engines: {node: '>=4'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} @@ -1207,6 +1439,10 @@ packages: resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} engines: {node: '>=10.16.0'} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + call-bind-apply-helpers@1.0.1: resolution: {integrity: sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==} engines: {node: '>= 0.4'} @@ -1241,6 +1477,10 @@ packages: resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} @@ -1271,6 +1511,10 @@ packages: client-only@0.0.1: resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clone@1.0.4: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} @@ -1296,6 +1540,10 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -1310,6 +1558,15 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concurrently@9.1.1: + resolution: {integrity: sha512-6VX8lrBIycgZKTwBsWS+bLrmkGRkDmvtGsYylRN9b93CygN6CbK46HmnQ3rdSOR8HRjdahDrxb5MqD9cEFOg5Q==} + engines: {node: '>=18'} + hasBin: true + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1322,6 +1579,9 @@ packages: typescript: optional: true + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1460,6 +1720,14 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1477,6 +1745,10 @@ packages: didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + diff@5.2.0: resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} engines: {node: '>=0.3.1'} @@ -1491,6 +1763,10 @@ packages: dom-helpers@5.2.1: resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1545,6 +1821,11 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -1677,9 +1958,21 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + eventsource-parser@3.0.0: + resolution: {integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.2: + resolution: {integrity: sha512-YolzkJNxsTL3tCJMWFxpxtG2sCjbZ4LQUBUrkdaJK0ub0p6lmJt+2+1SwhKjLc652lpH9L/79Ptez972H9tphw==} + engines: {node: '>=18.0.0'} + execa@7.2.0: resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} @@ -1741,6 +2034,17 @@ packages: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.1: + resolution: {integrity: sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -1768,6 +2072,10 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.2.6: resolution: {integrity: sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==} engines: {node: '>= 0.4'} @@ -1856,6 +2164,10 @@ packages: html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + https-proxy-agent@6.2.1: resolution: {integrity: sha512-ONsE3+yfZF2caH5+bJlcddtWqNI3Gvs5A38+ngvljxaBiRXRswym2c7yf8UAeFpRFKjFNHIFEHqR/OLAWJzyiA==} engines: {node: '>= 14'} @@ -1864,6 +2176,13 @@ packages: resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} engines: {node: '>=14.18.0'} + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2165,6 +2484,9 @@ packages: peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + math-intrinsics@1.0.0: resolution: {integrity: sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==} engines: {node: '>= 0.4'} @@ -2267,6 +2589,14 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -2340,6 +2670,15 @@ packages: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + node-fetch@3.3.2: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2559,6 +2898,10 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + react-day-picker@8.10.1: resolution: {integrity: sha512-TMx7fNbhLk15eqcMt+7Z7S2KF7mfTId/XJDjKE8f+IUcFn0l08/kI4FiYTL/0yuOLmEcbR4Fwe3GJf/NiiMnPA==} peerDependencies: @@ -2670,6 +3013,10 @@ packages: remark-rehype@11.1.1: resolution: {integrity: sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2696,6 +3043,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -2707,6 +3057,9 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + scheduler@0.25.0: resolution: {integrity: sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==} @@ -2727,6 +3080,9 @@ packages: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + shadcn-ui@0.9.4: resolution: {integrity: sha512-75nqu4+y4mlhNXGfHPoPd1r2fgqGQgSEPzPe8TV39WRinafKHuBX2xkgoQOwu+NhiRPKV5TrRSCZ5ytGrFU1oQ==} hasBin: true @@ -2743,6 +3099,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.2: + resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -2786,6 +3146,10 @@ packages: stable-hash@0.0.4: resolution: {integrity: sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==} + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + stdin-discarder@0.1.0: resolution: {integrity: sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -2876,6 +3240,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -2911,6 +3279,17 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} @@ -2929,6 +3308,20 @@ packages: ts-morph@18.0.0: resolution: {integrity: sha512-Kg5u0mk19PIIe4islUI/HWRvm9bC1lHejK4S0oh1zaZ77TMZAEmQC0sHQYiu2RgCQFZKXz1fMVi/7nOOeirznA==} + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -2939,6 +3332,11 @@ packages: tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsx@4.19.2: + resolution: {integrity: sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==} + engines: {node: '>=18.0.0'} + hasBin: true + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -2968,6 +3366,9 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} @@ -2993,6 +3394,10 @@ packages: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + update-browserslist-db@1.1.1: resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true @@ -3025,6 +3430,9 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + vfile-message@4.0.2: resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} @@ -3041,6 +3449,16 @@ packages: resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} engines: {node: '>= 8'} + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + which-boxed-primitive@1.1.1: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} @@ -3074,6 +3492,22 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + 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'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -3082,6 +3516,18 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -3103,6 +3549,18 @@ snapshots: '@antfu/ni@0.21.12': {} + '@anthropic-ai/sdk@0.33.1': + dependencies: + '@types/node': 18.19.68 + '@types/node-fetch': 2.6.12 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + '@babel/code-frame@7.26.2': dependencies: '@babel/helper-validator-identifier': 7.25.9 @@ -3267,11 +3725,87 @@ snapshots: '@babel/helper-string-parser': 7.25.9 '@babel/helper-validator-identifier': 7.25.9 + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + '@emnapi/runtime@1.3.1': dependencies: tslib: 2.8.1 optional: true + '@esbuild/aix-ppc64@0.23.1': + optional: true + + '@esbuild/android-arm64@0.23.1': + optional: true + + '@esbuild/android-arm@0.23.1': + optional: true + + '@esbuild/android-x64@0.23.1': + optional: true + + '@esbuild/darwin-arm64@0.23.1': + optional: true + + '@esbuild/darwin-x64@0.23.1': + optional: true + + '@esbuild/freebsd-arm64@0.23.1': + optional: true + + '@esbuild/freebsd-x64@0.23.1': + optional: true + + '@esbuild/linux-arm64@0.23.1': + optional: true + + '@esbuild/linux-arm@0.23.1': + optional: true + + '@esbuild/linux-ia32@0.23.1': + optional: true + + '@esbuild/linux-loong64@0.23.1': + optional: true + + '@esbuild/linux-mips64el@0.23.1': + optional: true + + '@esbuild/linux-ppc64@0.23.1': + optional: true + + '@esbuild/linux-riscv64@0.23.1': + optional: true + + '@esbuild/linux-s390x@0.23.1': + optional: true + + '@esbuild/linux-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + + '@esbuild/openbsd-x64@0.23.1': + optional: true + + '@esbuild/sunos-x64@0.23.1': + optional: true + + '@esbuild/win32-arm64@0.23.1': + optional: true + + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-x64@0.23.1': + optional: true + '@eslint-community/eslint-utils@4.4.1(eslint@9.17.0(jiti@1.21.7))': dependencies: eslint: 9.17.0(jiti@1.21.7) @@ -3444,6 +3978,17 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@modelcontextprotocol/sdk@1.0.4': + dependencies: + content-type: 1.0.5 + raw-body: 3.0.0 + zod: 3.24.1 + '@next/env@15.1.1': {} '@next/eslint-plugin-next@15.1.1': @@ -3929,13 +4474,13 @@ snapshots: dependencies: tslib: 2.8.1 - '@tailwindcss/typography@0.5.15(tailwindcss@3.4.17)': + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2)) '@ts-morph/common@0.19.0': dependencies: @@ -3944,6 +4489,14 @@ snapshots: mkdirp: 2.1.6 path-browserify: 1.0.1 + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + '@types/d3-array@3.2.1': {} '@types/d3-color@3.1.3': {} @@ -3982,6 +4535,8 @@ snapshots: '@types/estree@1.0.6': {} + '@types/eventsource@1.1.15': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -3996,6 +4551,15 @@ snapshots: '@types/ms@0.7.34': {} + '@types/node-fetch@2.6.12': + dependencies: + '@types/node': 20.17.10 + form-data: 4.0.1 + + '@types/node@18.19.68': + dependencies: + undici-types: 5.26.5 + '@types/node@20.17.10': dependencies: undici-types: 6.19.8 @@ -4014,6 +4578,10 @@ snapshots: '@types/unist@3.0.3': {} + '@types/ws@8.5.13': + dependencies: + '@types/node': 20.17.10 + '@typescript-eslint/eslint-plugin@8.18.1(@typescript-eslint/parser@8.18.1(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2))(eslint@9.17.0(jiti@1.21.7))(typescript@5.7.2)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -4093,14 +4661,26 @@ snapshots: '@ungap/structured-clone@1.2.1': {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.0 + acorn@8.14.0: {} agent-base@7.1.3: {} + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -4125,6 +4705,8 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + arg@4.1.3: {} + arg@5.0.2: {} argparse@2.0.1: {} @@ -4205,6 +4787,8 @@ snapshots: dependencies: tslib: 2.8.1 + asynckit@0.4.0: {} + available-typed-arrays@1.0.7: dependencies: possible-typed-array-names: 1.0.0 @@ -4256,6 +4840,8 @@ snapshots: dependencies: streamsearch: 1.1.0 + bytes@3.1.2: {} + call-bind-apply-helpers@1.0.1: dependencies: es-errors: 1.3.0 @@ -4288,6 +4874,8 @@ snapshots: chalk@5.2.0: {} + chalk@5.4.1: {} + character-entities-html4@2.1.0: {} character-entities-legacy@3.0.0: {} @@ -4320,6 +4908,12 @@ snapshots: client-only@0.0.1: {} + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clone@1.0.4: {} clsx@2.1.1: {} @@ -4344,6 +4938,10 @@ snapshots: color-string: 1.9.1 optional: true + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + comma-separated-tokens@2.0.3: {} commander@10.0.1: {} @@ -4352,6 +4950,18 @@ snapshots: concat-map@0.0.1: {} + concurrently@9.1.1: + dependencies: + chalk: 4.1.2 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + content-type@1.0.5: {} + convert-source-map@2.0.0: {} cosmiconfig@8.3.6(typescript@5.7.2): @@ -4363,6 +4973,8 @@ snapshots: optionalDependencies: typescript: 5.7.2 + create-require@1.1.1: {} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -4490,6 +5102,10 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + dequal@2.0.3: {} detect-libc@2.0.3: @@ -4503,6 +5119,8 @@ snapshots: didyoumean@1.2.2: {} + diff@4.0.2: {} + diff@5.2.0: {} dlv@1.1.3: {} @@ -4516,6 +5134,8 @@ snapshots: '@babel/runtime': 7.26.0 csstype: 3.1.3 + dotenv@16.4.7: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.1 @@ -4632,6 +5252,33 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} @@ -4837,8 +5484,16 @@ snapshots: esutils@2.0.3: {} + event-target-shim@5.0.1: {} + eventemitter3@4.0.7: {} + eventsource-parser@3.0.0: {} + + eventsource@3.0.2: + dependencies: + eventsource-parser: 3.0.0 + execa@7.2.0: dependencies: cross-spawn: 7.0.6 @@ -4915,6 +5570,19 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + form-data-encoder@1.7.2: {} + + form-data@4.0.1: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -4942,6 +5610,8 @@ snapshots: gensync@1.0.0-beta.2: {} + get-caller-file@2.0.5: {} + get-intrinsic@1.2.6: dependencies: call-bind-apply-helpers: 1.0.1 @@ -5049,6 +5719,14 @@ snapshots: html-url-attributes@3.0.1: {} + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + https-proxy-agent@6.2.1: dependencies: agent-base: 7.1.3 @@ -5058,6 +5736,14 @@ snapshots: human-signals@4.3.1: {} + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} ignore@5.3.2: {} @@ -5312,7 +5998,7 @@ snapshots: log-symbols@5.1.0: dependencies: - chalk: 5.2.0 + chalk: 5.4.1 is-unicode-supported: 1.3.0 longest-streak@3.1.0: {} @@ -5331,6 +6017,8 @@ snapshots: dependencies: react: 19.0.0 + make-error@1.3.6: {} + math-intrinsics@1.0.0: {} mdast-util-from-markdown@2.0.2: @@ -5564,6 +6252,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mimic-fn@2.1.0: {} mimic-fn@4.0.0: {} @@ -5627,6 +6321,10 @@ snapshots: node-domexception@1.0.0: {} + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + node-fetch@3.3.2: dependencies: data-uri-to-buffer: 4.0.1 @@ -5707,7 +6405,7 @@ snapshots: ora@6.3.1: dependencies: - chalk: 5.2.0 + chalk: 5.4.1 cli-cursor: 4.0.0 cli-spinners: 2.9.2 is-interactive: 2.0.0 @@ -5787,12 +6485,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.4.49 - postcss-load-config@4.0.2(postcss@8.4.49): + postcss-load-config@4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2)): dependencies: lilconfig: 3.1.3 yaml: 2.6.1 optionalDependencies: postcss: 8.4.49 + ts-node: 10.9.2(@types/node@20.17.10)(typescript@5.7.2) postcss-nested@6.2.0(postcss@8.4.49): dependencies: @@ -5842,6 +6541,13 @@ snapshots: queue-microtask@1.2.3: {} + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + react-day-picker@8.10.1(date-fns@4.1.0)(react@19.0.0): dependencies: date-fns: 4.1.0 @@ -5995,6 +6701,8 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 + require-directory@2.1.1: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -6022,6 +6730,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.1: + dependencies: + tslib: 2.8.1 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -6038,6 +6750,8 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 + safer-buffer@2.1.2: {} + scheduler@0.25.0: {} semver@6.3.1: {} @@ -6060,6 +6774,8 @@ snapshots: functions-have-names: 1.2.3 has-property-descriptors: 1.0.2 + setprototypeof@1.2.0: {} + shadcn-ui@0.9.4(typescript@5.7.2): dependencies: '@antfu/ni': 0.21.12 @@ -6119,6 +6835,8 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.8.2: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -6166,6 +6884,8 @@ snapshots: stable-hash@0.0.4: {} + statuses@2.0.1: {} + stdin-discarder@0.1.0: dependencies: bl: 5.1.0 @@ -6281,15 +7001,19 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} tailwind-merge@2.6.0: {} - tailwindcss-animate@1.0.7(tailwindcss@3.4.17): + tailwindcss-animate@1.0.7(tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2))): dependencies: - tailwindcss: 3.4.17 + tailwindcss: 3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2)) - tailwindcss@3.4.17: + tailwindcss@3.4.17(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -6308,7 +7032,7 @@ snapshots: postcss: 8.4.49 postcss-import: 15.1.0(postcss@8.4.49) postcss-js: 4.0.1(postcss@8.4.49) - postcss-load-config: 4.0.2(postcss@8.4.49) + postcss-load-config: 4.0.2(postcss@8.4.49)(ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2)) postcss-nested: 6.2.0(postcss@8.4.49) postcss-selector-parser: 6.1.2 resolve: 1.22.9 @@ -6332,6 +7056,12 @@ snapshots: dependencies: is-number: 7.0.0 + toidentifier@1.0.1: {} + + tr46@0.0.3: {} + + tree-kill@1.2.2: {} + trim-lines@3.0.1: {} trough@2.2.0: {} @@ -6347,6 +7077,24 @@ snapshots: '@ts-morph/common': 0.19.0 code-block-writer: 12.0.0 + ts-node@10.9.2(@types/node@20.17.10)(typescript@5.7.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.17.10 + acorn: 8.14.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.7.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -6362,6 +7110,13 @@ snapshots: tslib@2.8.1: {} + tsx@4.19.2: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 @@ -6408,6 +7163,8 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 + undici-types@5.26.5: {} + undici-types@6.19.8: {} unified@11.0.5: @@ -6445,6 +7202,8 @@ snapshots: universalify@2.0.1: {} + unpipe@1.0.0: {} + update-browserslist-db@1.1.1(browserslist@4.24.3): dependencies: browserslist: 4.24.3 @@ -6472,6 +7231,8 @@ snapshots: util-deprecate@1.0.2: {} + v8-compile-cache-lib@3.0.1: {} + vfile-message@4.0.2: dependencies: '@types/unist': 3.0.3 @@ -6505,6 +7266,15 @@ snapshots: web-streams-polyfill@3.3.3: {} + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + which-boxed-primitive@1.1.1: dependencies: is-bigint: 1.1.0 @@ -6562,10 +7332,28 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + ws@8.18.0: {} + + y18n@5.0.8: {} + yallist@3.1.1: {} yaml@2.6.1: {} + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + 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: 21.1.1 + + yn@3.1.1: {} + yocto-queue@0.1.0: {} zod@3.24.1: {} From e5fcca5d3f15ec9b9f5c9fd1730e76e18e841511 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:04:55 +0100 Subject: [PATCH 13/19] linter --- apps/web/src/components/tools/auth0/chat.tsx | 2 +- apps/web/src/components/tools/auth0/dashboard.tsx | 1 - apps/web/src/lib/mcp-client.ts | 6 +++++- apps/web/src/lib/mcp-server.ts | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/tools/auth0/chat.tsx b/apps/web/src/components/tools/auth0/chat.tsx index 0b09b0d..856b132 100644 --- a/apps/web/src/components/tools/auth0/chat.tsx +++ b/apps/web/src/components/tools/auth0/chat.tsx @@ -2,7 +2,7 @@ import { useState, useEffect, useRef } from "react" import { MCPClient, MessageCallback } from "@/lib/mcp-client" -import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card" +import { Card, CardHeader, CardContent } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Button } from "@/components/ui/button" import { ScrollArea } from "@/components/ui/scroll-area" diff --git a/apps/web/src/components/tools/auth0/dashboard.tsx b/apps/web/src/components/tools/auth0/dashboard.tsx index dc34bbb..819e152 100644 --- a/apps/web/src/components/tools/auth0/dashboard.tsx +++ b/apps/web/src/components/tools/auth0/dashboard.tsx @@ -108,7 +108,6 @@ export default function Auth0Dashboard() { unique_emails: number }>>([]) const [isDomainsOpen, setIsDomainsOpen] = useState(false) - const [isOpen, setIsOpen] = useState(false) useEffect(() => { async function fetchInitialData() { diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts index 6e8ca1e..0298d95 100644 --- a/apps/web/src/lib/mcp-client.ts +++ b/apps/web/src/lib/mcp-client.ts @@ -1,4 +1,4 @@ -import { Anthropic, APIError } from '@anthropic-ai/sdk'; +import { Anthropic } from '@anthropic-ai/sdk'; import { ListToolsResultSchema, CallToolResultSchema, @@ -12,6 +12,7 @@ interface Message { role: 'user' | 'assistant' | 'tool'; content: string; toolName?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any toolArgs?: any; } @@ -35,6 +36,7 @@ export class MCPClient { private reconnectAttempts = 0; private maxReconnectAttempts = 3; private eventSource: EventSource | null = null; + // eslint-disable-next-line @typescript-eslint/no-explicit-any private messageHandlers: Set<(data: any) => void> = new Set(); constructor() { @@ -250,6 +252,7 @@ export class MCPClient { if (nextStream) { await this.processStream(nextStream, onMessage, depth + 1); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { // Handle rate limits in nested stream creation if (error.status === 429 || error.message?.includes('rate limit')) { @@ -274,6 +277,7 @@ export class MCPClient { break; } } + // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { // Check for rate limit errors if (error.status === 429 || error.message?.includes('rate limit')) { diff --git a/apps/web/src/lib/mcp-server.ts b/apps/web/src/lib/mcp-server.ts index ba65737..1471f74 100644 --- a/apps/web/src/lib/mcp-server.ts +++ b/apps/web/src/lib/mcp-server.ts @@ -25,6 +25,7 @@ export class MCPServer { // Get session ID from the endpoint event await new Promise((resolve, reject) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any this.eventSource.addEventListener('endpoint', (event: any) => { console.log('Received endpoint event:', event.data); const match = event.data.match(/session_id=([^&]+)/); @@ -60,7 +61,7 @@ export class MCPServer { } } - async handleMessage(message: string, client: MCPClient) { + async handleMessage(message: string) { if (!this.sessionId) { console.error('No session ID available'); throw new Error('No session ID available'); From 595648ea720c7c057e28fffce3de9edfe220460b Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:06:26 +0100 Subject: [PATCH 14/19] linter --- apps/web/src/components/tools/auth0/chat.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/components/tools/auth0/chat.tsx b/apps/web/src/components/tools/auth0/chat.tsx index 856b132..b2c26f6 100644 --- a/apps/web/src/components/tools/auth0/chat.tsx +++ b/apps/web/src/components/tools/auth0/chat.tsx @@ -36,6 +36,7 @@ export function Chat() { } }, []) // Empty dependency array + // eslint-disable-next-line @typescript-eslint/no-explicit- const formatToolCall = (toolName: string, args: any): string => { return `\n[${toolName}] ${JSON.stringify(args, null, 2)}\n`; } From c3719eac6bdcd727d637f49f1bc0be1afd456ff4 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:08:54 +0100 Subject: [PATCH 15/19] linter --- apps/web/src/components/tools/auth0/chat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/components/tools/auth0/chat.tsx b/apps/web/src/components/tools/auth0/chat.tsx index b2c26f6..797dda9 100644 --- a/apps/web/src/components/tools/auth0/chat.tsx +++ b/apps/web/src/components/tools/auth0/chat.tsx @@ -36,7 +36,7 @@ export function Chat() { } }, []) // Empty dependency array - // eslint-disable-next-line @typescript-eslint/no-explicit- + // eslint-disable-next-line @typescript-eslint/no-explicit-any const formatToolCall = (toolName: string, args: any): string => { return `\n[${toolName}] ${JSON.stringify(args, null, 2)}\n`; } From 8f91c72956acfb6514bb469dff1689753eb3e76e Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:11:03 +0100 Subject: [PATCH 16/19] linter --- apps/web/server.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/web/server.ts b/apps/web/server.ts index 359a47d..03a196a 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -3,7 +3,6 @@ import { parse } from 'url' import next from 'next' import { MCPServer } from './src/lib/mcp-server' import { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js' -import cors from 'cors' const dev = process.env.NODE_ENV !== 'production' const hostname = 'localhost' From 620e367de58fa6e86dfd69bc1a12111bd1984711 Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:16:40 +0100 Subject: [PATCH 17/19] linter --- apps/web/server.ts | 29 +++++++------------ .../src/components/tools/auth0/dashboard.tsx | 2 +- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/apps/web/server.ts b/apps/web/server.ts index 03a196a..63332ef 100644 --- a/apps/web/server.ts +++ b/apps/web/server.ts @@ -61,8 +61,9 @@ app.prepare().then(() => { res.write(':\n\n') // Force flush the written data - if (typeof res.flush === 'function') { - res.flush(); + const response = res as unknown as { flush?: () => void }; + if (typeof response.flush === 'function') { + response.flush(); } // Create client object @@ -71,8 +72,9 @@ app.prepare().then(() => { try { console.log('Sending message to client:', data.substring(0, 100)) res.write(`data: ${data}\n\n`) - if (typeof res.flush === 'function') { - res.flush(); + const response = res as unknown as { flush?: () => void }; + if (typeof response.flush === 'function') { + response.flush(); } } catch (error) { console.error('Error sending message:', error) @@ -89,8 +91,9 @@ app.prepare().then(() => { const keepAlive = setInterval(() => { try { res.write(':\n\n') - if (typeof res.flush === 'function') { - res.flush(); + const response = res as unknown as { flush?: () => void }; + if (typeof response.flush === 'function') { + response.flush(); } } catch (error) { console.error('Error sending heartbeat:', error) @@ -154,13 +157,7 @@ app.prepare().then(() => { } } else { // Forward message to MCPServer - await mcpServer.handleMessage(JSON.stringify(message), { - send: (response) => { - for (const client of sseClients) { - client.send(response); - } - } - }); + await mcpServer.handleMessage(JSON.stringify(message)); } // Send HTTP response @@ -186,11 +183,7 @@ app.prepare().then(() => { req.on('end', async () => { try { const message: JSONRPCMessage = JSON.parse(body) - await mcpServer.handleMessage(JSON.stringify(message), { - send: (response) => { - sseClients.forEach(client => client.send(response)) - } - }); + await mcpServer.handleMessage(JSON.stringify(message)); res.writeHead(200) res.end() } catch (error) { diff --git a/apps/web/src/components/tools/auth0/dashboard.tsx b/apps/web/src/components/tools/auth0/dashboard.tsx index 819e152..334cd0f 100644 --- a/apps/web/src/components/tools/auth0/dashboard.tsx +++ b/apps/web/src/components/tools/auth0/dashboard.tsx @@ -501,7 +501,7 @@ export default function Auth0Dashboard() { Chat Assistant From 3b13d1ca33c30383d44f9301b1a205d85cb28a1b Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:28:15 +0100 Subject: [PATCH 18/19] linter --- apps/web/src/lib/mcp-client.ts | 30 ++++++++++++++++++------------ apps/web/src/lib/mcp-server.ts | 2 +- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/apps/web/src/lib/mcp-client.ts b/apps/web/src/lib/mcp-client.ts index 0298d95..b43c5e8 100644 --- a/apps/web/src/lib/mcp-client.ts +++ b/apps/web/src/lib/mcp-client.ts @@ -16,20 +16,15 @@ interface Message { toolArgs?: any; } -type AnthropicMessage = { - role: 'user' | 'assistant'; - content: string; -} - export type MessageCallback = (message: Message) => void; export class MCPClient { private static instance: MCPClient | null = null; private connecting: boolean = false; - private anthropicClient: Anthropic; + private anthropicClient!: Anthropic; private messages: Message[] = []; - private mcpClient: Client; - private transport: SSEClientTransport; + private mcpClient!: Client; + private transport!: SSEClientTransport; private tools: Tool[] = []; private isConnected = false; private firstMessage = true; @@ -215,10 +210,16 @@ export class MCPClient { }); } - if (toolResult.content.some(c => c.text.includes('[Error]'))) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if (toolResult.content.some((c: any) => c.type === 'text' && c.text?.includes('[Error]'))) { this.messages.push({ role: 'user', - content: `Error executing query. Please fix the query and try again. Error: ${toolResult.content.map(c => c.text).join('\n')}` + content: `Error executing query. Please fix the query and try again. Error: ${toolResult.content + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .filter((c: any) => c.type === 'text') + // eslint-disable-next-line @typescript-eslint/no-explicit-any + .map((c: any) => c.text) + .join('\n')}` }); } else { const formattedResult = JSON.stringify(toolResult.content.flatMap((c) => c.text)); @@ -229,8 +230,13 @@ export class MCPClient { } try { + const anthropicMessages = this.messages.map(({ role, content }) => ({ + role: role === 'tool' ? 'assistant' : role, + content + })); + const nextStream = await this.anthropicClient.messages.create({ - messages: this.messages, + messages: anthropicMessages, model: 'claude-3-5-sonnet-latest', max_tokens: 8192, tools: this.tools, @@ -312,7 +318,7 @@ export class MCPClient { } this.messages.push({ role: 'user', content: message }); - const anthropicMessages: AnthropicMessage[] = this.messages.map(({ role, content }) => ({ + const anthropicMessages = this.messages.map(({ role, content }) => ({ role: role === 'tool' ? 'assistant' : role, content })); diff --git a/apps/web/src/lib/mcp-server.ts b/apps/web/src/lib/mcp-server.ts index 1471f74..7baa975 100644 --- a/apps/web/src/lib/mcp-server.ts +++ b/apps/web/src/lib/mcp-server.ts @@ -8,7 +8,7 @@ interface MCPClient { export class MCPServer { private clients: Set = new Set(); private isReady: boolean = false; - private eventSource: EventSource; + private eventSource!: EventSource; private sessionId: string | null = null; async start() { From 215b267f58170ddb7721af8f1b087fcd3aeab8da Mon Sep 17 00:00:00 2001 From: alrocar Date: Mon, 30 Dec 2024 18:32:32 +0100 Subject: [PATCH 19/19] remove filter --- tinybird/pipes/auth0_connections.pipe | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tinybird/pipes/auth0_connections.pipe b/tinybird/pipes/auth0_connections.pipe index 56217fa..13e7dc5 100644 --- a/tinybird/pipes/auth0_connections.pipe +++ b/tinybird/pipes/auth0_connections.pipe @@ -18,7 +18,7 @@ SQL > max(event_time) as last_seen FROM auth0 WHERE - event.data.connection::String != '' and event.data.connection::String not like '%saml%' + event.data.connection::String != '' --and event.data.connection::String not like '%saml%' AND event.data.strategy::String != '' {% if defined(client_id) and client_id != 'all' %} AND event.data.client_id::String = {{String(client_id)}}