diff --git a/.gitignore b/.gitignore index 97513a0..796e278 100644 --- a/.gitignore +++ b/.gitignore @@ -206,4 +206,6 @@ state.txt **/orginal-sdk/ **/fixtures -/store \ No newline at end of file +/store + +.claude/settings.local.json \ No newline at end of file diff --git a/package.json b/package.json index 2328584..b630ad5 100644 --- a/package.json +++ b/package.json @@ -14,20 +14,37 @@ "db:push": "drizzle-kit push", "db:studio": "drizzle-kit studio", "script": "tsx server/script.ts", + "mcp": "tsx server/mcp-server.ts", "new-plugin": "tsx scripts/new-plugin.ts", "format": "biome format . --write", "lint": "biome check .", "lint:fix": "biome check . --fix --unsafe", "test": "vitest run", "test:watch": "vitest", - "available-plugins": "tsx scripts/available-plugins.ts" + "available-plugins": "tsx scripts/available-plugins.ts", + "test:mcp": "tsx scripts/test-mcp.ts", + "test:mcp:base": "tsx scripts/test-base-mcp.ts", + "test:mcp:claude": "tsx scripts/test-claude-tools.ts", + "test:mcp:http": "tsx scripts/test-mcp-http.ts", + "test:openai": "tsx scripts/test-openai.ts", + "test:claude-sdk": "tsx scripts/test-claude-sdk.ts", + "test:webhook": "tsx scripts/test-webhook.ts", + "test:cron": "tsx scripts/test-cron.ts", + "test:claude-api": "tsx scripts/test-claude-api.ts" }, "dependencies": { + "@ai-sdk/anthropic": "^3.0.58", "@anthropic-ai/claude-agent-sdk": "^0.2.52", + "@anthropic-ai/sdk": "^0.78.0", + "@corsair-dev/mcp": "^0.1.7", + "@corsair/ui": "@corsair-dev/ui", + "@modelcontextprotocol/sdk": "^1.27.1", + "@openai/agents": "^0.5.4", "@trpc/server": "^11.10.0", "@whiskeysockets/baileys": "^7.0.0-rc.9", + "ai": "6.0.37", "chokidar": "^4.0.3", - "corsair": "0.1.13", + "corsair": "0.1.26", "dotenv": "^16.4.0", "drizzle-orm": "^0.44.5", "express": "^4.21.0", @@ -37,7 +54,8 @@ "pg": "^8.13.0", "pino": "^9.6.0", "tsx": "^4.19.0", - "zod": "^3.25.0" + "zod": "^3.25.0", + "zod-to-json-schema": "^3.25.0" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 10c4f27..2d68964 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,15 @@ importers: '@anthropic-ai/claude-agent-sdk': specifier: ^0.2.52 version: 0.2.52(zod@3.25.76) + '@anthropic-ai/sdk': + specifier: ^0.78.0 + version: 0.78.0(zod@3.25.76) + '@modelcontextprotocol/sdk': + specifier: ^1.27.1 + version: 1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76) + '@openai/agents': + specifier: ^0.5.4 + version: 0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76) '@trpc/server': specifier: ^11.10.0 version: 11.10.0(typescript@5.9.3) @@ -21,8 +30,8 @@ importers: specifier: ^4.0.3 version: 4.0.3 corsair: - specifier: 0.1.13 - version: 0.1.13 + specifier: 0.1.26 + version: 0.1.26 dotenv: specifier: ^16.4.0 version: 16.6.1 @@ -37,7 +46,7 @@ importers: version: 1.40.0(encoding@0.1.13) mem0ai: specifier: ^2.2.3 - version: 2.2.3(@anthropic-ai/sdk@0.55.1)(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260302.0)(@google/genai@1.42.0)(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.14.0)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.97.0)(@types/jest@29.5.14)(@types/pg@8.16.0)(@types/sqlite3@3.1.11)(cloudflare@4.5.0(encoding@0.1.13))(encoding@0.1.13)(groq-sdk@0.3.0(encoding@0.1.13))(neo4j-driver@5.28.3)(ollama@0.5.18)(pg@8.18.0)(redis@4.7.1)(sqlite3@5.1.7)(ws@8.19.0) + version: 2.2.3(@anthropic-ai/sdk@0.78.0(zod@3.25.76))(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260302.0)(@google/genai@1.42.0(@modelcontextprotocol/sdk@1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76)))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@6.27.0(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.14.0)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.97.0)(@types/jest@29.5.14)(@types/pg@8.16.0)(@types/sqlite3@3.1.11)(cloudflare@4.5.0(encoding@0.1.13))(encoding@0.1.13)(groq-sdk@0.3.0(encoding@0.1.13))(neo4j-driver@5.28.3)(ollama@0.5.18)(pg@8.18.0)(redis@4.7.1)(sqlite3@5.1.7)(ws@8.19.0) node-cron: specifier: ^4.2.1 version: 4.2.1 @@ -84,9 +93,14 @@ packages: peerDependencies: zod: ^4.0.0 - '@anthropic-ai/sdk@0.55.1': - resolution: {integrity: sha512-gjOMS4chmm8BxClKmCjNHmvf1FrO1Cn++CSX6K3YCZjz5JG4I9ZttQ/xEH4FBsz6HQyZvnUpiKlOAkmxaGmEaQ==} + '@anthropic-ai/sdk@0.78.0': + resolution: {integrity: sha512-PzQhR715td/m1UaaN5hHXjYB8Gl2lF9UVhrrGrZeysiF6Rb74Wc9GCB8hzLdzmQtBd1qe89F9OptgB9Za1Ib5w==} hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true '@azure/abort-controller@2.1.2': resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} @@ -155,6 +169,10 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + '@biomejs/biome@2.3.5': resolution: {integrity: sha512-HvLhNlIlBIbAV77VysRIBEwp55oM/QAjQEin74QQX9Xb259/XP/D5AGGnZMOyF1el4zcvlNYYR3AyTMUV3ILhg==} engines: {node: '>=14.21.3'} @@ -710,6 +728,12 @@ packages: '@hapi/hoek@9.3.0': resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + '@hono/node-server@1.19.11': + resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -882,6 +906,16 @@ packages: '@mistralai/mistralai@1.14.0': resolution: {integrity: sha512-6zaj2f2LCd37cRpBvCgctkDbXtYBlAC85p+u4uU/726zjtsI+sdVH34qRzkm9iE3tRb8BoaiI0/P7TD+uMvLLQ==} + '@modelcontextprotocol/sdk@1.27.1': + resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + '@npmcli/fs@1.1.1': resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} @@ -890,6 +924,29 @@ packages: engines: {node: '>=10'} deprecated: This functionality has been moved to @npmcli/fs + '@openai/agents-core@0.5.4': + resolution: {integrity: sha512-qAT9zGIIM7GT5/WGkLpp8Fuar7NL5qu30b5+o2jP3mE6aMfx9OZjdj0za/iYLeV5kzQ5pOcbvRXenfzHrhvd/A==} + peerDependencies: + zod: ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + '@openai/agents-openai@0.5.4': + resolution: {integrity: sha512-1uDEu9iwM7oB3oWNxvT/yzkcr7WtjHe1ekbQOAsasEv9S0MKTT8uP2kknRVgxzgw+awTZBrhO2vfGhD1iKinuQ==} + peerDependencies: + zod: ^4.0.0 + + '@openai/agents-realtime@0.5.4': + resolution: {integrity: sha512-qlrhMWD3Xpzfrxplt/jvc1nlGtjNnRmyzgRAj6J5HX/bcnP0W4UdYHEJOreiIC8inj27kcVjQslyu0DAjVuXsA==} + peerDependencies: + zod: ^4.0.0 + + '@openai/agents@0.5.4': + resolution: {integrity: sha512-INstpf2vZ0rV6Zq9jcSzqq/oL2/D84YGGKCXnU2otAcQ0ji/VZm+zplDow/+oENnvKiXKdVtOrGMsXqNFL7W+Q==} + peerDependencies: + zod: ^4.0.0 + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} @@ -1301,6 +1358,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -1317,6 +1378,17 @@ packages: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1391,6 +1463,10 @@ packages: resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1514,6 +1590,10 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -1521,12 +1601,20 @@ packages: cookie-signature@1.0.7: resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.2: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - corsair@0.1.13: - resolution: {integrity: sha512-BcTK4DuPzNXbhYZ3Qu6b1BIH0dO1+VTScz2m/1BQs3Et35IIQv9uMJhI24Ij07kN4IPJ7YDnS37kFkET4fry9Q==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + corsair@0.1.26: + resolution: {integrity: sha512-ZuXfNgEfAl3luToN22OATIfL1OQ+ZTAmTK1eLi9tACLR0Xol3fd4OuXWhlMzQ6vsxE9zTVMQjjob6vZjOlv7og==} cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} @@ -1816,6 +1904,14 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -1828,13 +1924,29 @@ packages: resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + express-rate-limit@8.2.1: + resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + express@4.22.1: resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} engines: {node: '>= 0.10.0'} + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -1863,6 +1975,10 @@ packages: resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} engines: {node: '>= 0.8'} + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + follow-redirects@1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} @@ -1899,6 +2015,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -2006,6 +2126,10 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hono@4.12.5: + resolution: {integrity: sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==} + engines: {node: '>=16.9.0'} + hookified@1.15.1: resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} @@ -2047,6 +2171,10 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} @@ -2071,6 +2199,10 @@ packages: ini@1.3.8: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ip-address@10.0.1: + resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} + engines: {node: '>= 12'} + ip-address@10.1.0: resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} engines: {node: '>= 12'} @@ -2103,6 +2235,9 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-wsl@3.1.1: resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} engines: {node: '>=16'} @@ -2133,6 +2268,9 @@ packages: resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + js-tiktoken@1.0.21: resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} @@ -2145,6 +2283,16 @@ packages: json-bigint@1.0.0: resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + jsonwebtoken@9.0.3: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} @@ -2269,6 +2417,10 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} @@ -2281,10 +2433,18 @@ packages: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -2378,6 +2538,10 @@ packages: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + neo4j-driver-bolt-connection@5.28.3: resolution: {integrity: sha512-wqHBYcU0FVRDmdsoZ+Fk0S/InYmu9/4BT6fPYh45Jimg/J7vQBUcdkiHGU7nop7HRb1ZgJmL305mJb6g5Bv35Q==} @@ -2431,6 +2595,10 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} deprecated: This package is no longer supported. + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + object-inspect@1.13.4: resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} @@ -2465,6 +2633,18 @@ packages: zod: optional: true + openai@6.27.0: + resolution: {integrity: sha512-osTKySlrdYrLYTt0zjhY8yp0JUBmWDCN+Q+QxsV4xMQnnoVFpylgKGgxwN8sSdTNw0G4y+WUXs4eCMWpyDNWZQ==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -2515,6 +2695,9 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -2577,6 +2760,10 @@ packages: resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} hasBin: true + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + postcss@8.5.6: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} @@ -2659,6 +2846,10 @@ packages: resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} engines: {node: '>= 0.8'} + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -2681,6 +2872,10 @@ packages: redis@4.7.1: resolution: {integrity: sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} @@ -2706,6 +2901,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-applescript@7.1.0: resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} engines: {node: '>=18'} @@ -2732,10 +2931,18 @@ packages: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + serve-static@1.16.3: resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} @@ -2930,6 +3137,9 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2945,6 +3155,10 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -3165,7 +3379,11 @@ snapshots: '@img/sharp-win32-arm64': 0.34.5 '@img/sharp-win32-x64': 0.34.5 - '@anthropic-ai/sdk@0.55.1': {} + '@anthropic-ai/sdk@0.78.0(zod@3.25.76)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 3.25.76 '@azure/abort-controller@2.1.2': dependencies: @@ -3283,6 +3501,8 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} + '@babel/runtime@7.28.6': {} + '@biomejs/biome@2.3.5': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.3.5 @@ -3586,12 +3806,14 @@ snapshots: '@gar/promisify@1.1.3': optional: true - '@google/genai@1.42.0': + '@google/genai@1.42.0(@modelcontextprotocol/sdk@1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76))': dependencies: google-auth-library: 10.5.0 p-retry: 4.6.2 protobufjs: 7.5.4 ws: 8.19.0 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76) transitivePeerDependencies: - bufferutil - supports-color @@ -3605,6 +3827,10 @@ snapshots: '@hapi/hoek@9.3.0': {} + '@hono/node-server@1.19.11(hono@4.12.5)': + dependencies: + hono: 4.12.5 + '@img/colour@1.0.0': {} '@img/sharp-darwin-arm64@0.34.5': @@ -3737,14 +3963,14 @@ snapshots: '@keyv/serialize@1.1.1': {} - '@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76))': + '@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@6.27.0(ws@8.19.0)(zod@3.25.76))': dependencies: '@cfworker/json-schema': 4.1.1 ansi-styles: 5.2.0 camelcase: 6.3.0 decamelize: 1.2.0 js-tiktoken: 1.0.21 - langsmith: 0.3.87(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76)) + langsmith: 0.3.87(@opentelemetry/api@1.9.0)(openai@6.27.0(ws@8.19.0)(zod@3.25.76)) mustache: 4.2.0 p-queue: 6.6.2 p-retry: 4.6.2 @@ -3766,6 +3992,30 @@ snapshots: - bufferutil - utf-8-validate + '@modelcontextprotocol/sdk@1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76)': + dependencies: + '@hono/node-server': 1.19.11(hono@4.12.5) + ajv: 8.18.0 + ajv-formats: 3.0.1(ajv@8.18.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 8.2.1(express@5.2.1) + hono: 4.12.5 + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.1(zod@3.25.76) + optionalDependencies: + '@cfworker/json-schema': 4.1.1 + transitivePeerDependencies: + - supports-color + '@npmcli/fs@1.1.1': dependencies: '@gar/promisify': 1.1.3 @@ -3778,6 +4028,57 @@ snapshots: rimraf: 3.0.2 optional: true + '@openai/agents-core@0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76)': + dependencies: + debug: 4.4.3 + openai: 6.27.0(ws@8.19.0)(zod@3.25.76) + optionalDependencies: + '@modelcontextprotocol/sdk': 1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + - ws + + '@openai/agents-openai@0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76)': + dependencies: + '@openai/agents-core': 0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76) + debug: 4.4.3 + openai: 6.27.0(ws@8.19.0)(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - '@cfworker/json-schema' + - supports-color + - ws + + '@openai/agents-realtime@0.5.4(@cfworker/json-schema@4.1.1)(zod@3.25.76)': + dependencies: + '@openai/agents-core': 0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76) + '@types/ws': 8.18.1 + debug: 4.4.3 + ws: 8.19.0 + zod: 3.25.76 + transitivePeerDependencies: + - '@cfworker/json-schema' + - bufferutil + - supports-color + - utf-8-validate + + '@openai/agents@0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76)': + dependencies: + '@openai/agents-core': 0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76) + '@openai/agents-openai': 0.5.4(@cfworker/json-schema@4.1.1)(ws@8.19.0)(zod@3.25.76) + '@openai/agents-realtime': 0.5.4(@cfworker/json-schema@4.1.1)(zod@3.25.76) + debug: 4.4.3 + openai: 6.27.0(ws@8.19.0)(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - '@cfworker/json-schema' + - bufferutil + - supports-color + - utf-8-validate + - ws + '@opentelemetry/api@1.9.0': optional: true @@ -4177,6 +4478,11 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + agent-base@6.0.2: dependencies: debug: 4.4.3 @@ -4196,6 +4502,17 @@ snapshots: indent-string: 4.0.0 optional: true + ajv-formats@3.0.1(ajv@8.18.0): + optionalDependencies: + ajv: 8.18.0 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -4275,6 +4592,20 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.14.2 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -4426,13 +4757,22 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-disposition@1.0.1: {} + content-type@1.0.5: {} cookie-signature@1.0.7: {} + cookie-signature@1.2.2: {} + cookie@0.7.2: {} - corsair@0.1.13: + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + corsair@0.1.26: dependencies: kysely: 0.28.11 uuid: 13.0.0 @@ -4675,6 +5015,12 @@ snapshots: events@3.3.0: {} + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + expand-template@2.0.3: {} expect-type@1.3.0: {} @@ -4687,6 +5033,11 @@ snapshots: jest-message-util: 29.7.0 jest-util: 29.7.0 + express-rate-limit@8.2.1(express@5.2.1): + dependencies: + express: 5.2.1 + ip-address: 10.0.1 + express@4.22.1: dependencies: accepts: 1.3.8 @@ -4723,8 +5074,45 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.2 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extend@3.0.2: {} + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.0: {} + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -4761,6 +5149,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + follow-redirects@1.15.11: {} foreground-child@3.3.1: @@ -4791,6 +5190,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + fs-constants@1.0.0: {} fs-minipass@2.1.0: @@ -4947,6 +5348,8 @@ snapshots: dependencies: function-bind: 1.1.2 + hono@4.12.5: {} + hookified@1.15.1: {} http-cache-semantics@4.2.0: @@ -5006,6 +5409,10 @@ snapshots: safer-buffer: 2.1.2 optional: true + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + ieee754@1.2.1: {} imurmurhash@0.1.4: @@ -5027,6 +5434,8 @@ snapshots: ini@1.3.8: {} + ip-address@10.0.1: {} + ip-address@10.1.0: optional: true @@ -5047,6 +5456,8 @@ snapshots: is-number@7.0.0: {} + is-promise@4.0.0: {} + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 @@ -5096,6 +5507,8 @@ snapshots: graceful-fs: 4.2.11 picomatch: 2.3.1 + jose@6.1.3: {} + js-tiktoken@1.0.21: dependencies: base64-js: 1.5.1 @@ -5108,6 +5521,15 @@ snapshots: dependencies: bignumber.js: 9.3.1 + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.28.6 + ts-algebra: 2.0.0 + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + jsonwebtoken@9.0.3: dependencies: jws: 4.0.1 @@ -5138,7 +5560,7 @@ snapshots: kysely@0.28.11: {} - langsmith@0.3.87(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76)): + langsmith@0.3.87(@opentelemetry/api@1.9.0)(openai@6.27.0(ws@8.19.0)(zod@3.25.76)): dependencies: '@types/uuid': 10.0.0 chalk: 4.1.2 @@ -5148,7 +5570,7 @@ snapshots: uuid: 10.0.0 optionalDependencies: '@opentelemetry/api': 1.9.0 - openai: 4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76) + openai: 6.27.0(ws@8.19.0)(zod@3.25.76) lodash.includes@4.3.0: {} @@ -5218,14 +5640,14 @@ snapshots: media-typer@1.1.0: {} - mem0ai@2.2.3(@anthropic-ai/sdk@0.55.1)(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260302.0)(@google/genai@1.42.0)(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.14.0)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.97.0)(@types/jest@29.5.14)(@types/pg@8.16.0)(@types/sqlite3@3.1.11)(cloudflare@4.5.0(encoding@0.1.13))(encoding@0.1.13)(groq-sdk@0.3.0(encoding@0.1.13))(neo4j-driver@5.28.3)(ollama@0.5.18)(pg@8.18.0)(redis@4.7.1)(sqlite3@5.1.7)(ws@8.19.0): + mem0ai@2.2.3(@anthropic-ai/sdk@0.78.0(zod@3.25.76))(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260302.0)(@google/genai@1.42.0(@modelcontextprotocol/sdk@1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76)))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@6.27.0(ws@8.19.0)(zod@3.25.76)))(@mistralai/mistralai@1.14.0)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.97.0)(@types/jest@29.5.14)(@types/pg@8.16.0)(@types/sqlite3@3.1.11)(cloudflare@4.5.0(encoding@0.1.13))(encoding@0.1.13)(groq-sdk@0.3.0(encoding@0.1.13))(neo4j-driver@5.28.3)(ollama@0.5.18)(pg@8.18.0)(redis@4.7.1)(sqlite3@5.1.7)(ws@8.19.0): dependencies: - '@anthropic-ai/sdk': 0.55.1 + '@anthropic-ai/sdk': 0.78.0(zod@3.25.76) '@azure/identity': 4.13.0 '@azure/search-documents': 12.2.0 '@cloudflare/workers-types': 4.20260302.0 - '@google/genai': 1.42.0 - '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@3.25.76)) + '@google/genai': 1.42.0(@modelcontextprotocol/sdk@1.27.1(@cfworker/json-schema@4.1.1)(zod@3.25.76)) + '@langchain/core': 0.3.80(@opentelemetry/api@1.9.0)(openai@6.27.0(ws@8.19.0)(zod@3.25.76)) '@mistralai/mistralai': 1.14.0 '@qdrant/js-client-rest': 1.13.0(typescript@5.9.3) '@supabase/supabase-js': 2.97.0 @@ -5250,6 +5672,8 @@ snapshots: merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + methods@1.1.2: {} micromatch@4.0.8: @@ -5259,10 +5683,16 @@ snapshots: mime-db@1.52.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mimic-response@3.1.0: {} @@ -5354,6 +5784,8 @@ snapshots: negotiator@0.6.4: optional: true + negotiator@1.0.0: {} + neo4j-driver-bolt-connection@5.28.3: dependencies: buffer: 6.0.3 @@ -5420,6 +5852,8 @@ snapshots: set-blocking: 2.0.0 optional: true + object-assign@4.1.1: {} + object-inspect@1.13.4: {} ollama@0.5.18: @@ -5458,6 +5892,11 @@ snapshots: transitivePeerDependencies: - encoding + openai@6.27.0(ws@8.19.0)(zod@3.25.76): + optionalDependencies: + ws: 8.19.0 + zod: 3.25.76 + p-finally@1.0.0: {} p-map@4.0.0: @@ -5502,6 +5941,8 @@ snapshots: path-to-regexp@0.1.12: {} + path-to-regexp@8.3.0: {} + pathe@2.0.3: {} pathval@2.0.1: {} @@ -5567,6 +6008,8 @@ snapshots: sonic-boom: 4.2.1 thread-stream: 3.1.0 + pkce-challenge@5.0.1: {} + postcss@8.5.6: dependencies: nanoid: 3.3.11 @@ -5677,6 +6120,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -5705,6 +6155,8 @@ snapshots: '@redis/search': 1.2.0(@redis/client@1.6.1) '@redis/time-series': 1.1.0(@redis/client@1.6.1) + require-from-string@2.0.2: {} + resolve-pkg-maps@1.0.0: {} retry@0.12.0: @@ -5752,6 +6204,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + run-applescript@7.1.0: {} rxjs@7.8.2: @@ -5784,6 +6246,22 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + serve-static@1.16.3: dependencies: encodeurl: 2.0.0 @@ -5793,6 +6271,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + set-blocking@2.0.0: optional: true @@ -6037,6 +6524,8 @@ snapshots: tr46@0.0.3: {} + ts-algebra@2.0.0: {} + tslib@2.8.1: {} tsx@4.21.0: @@ -6055,6 +6544,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + typescript@5.9.3: {} uint8array-extras@1.5.0: {} diff --git a/scripts/test-claude-api.ts b/scripts/test-claude-api.ts new file mode 100644 index 0000000..2ee910b --- /dev/null +++ b/scripts/test-claude-api.ts @@ -0,0 +1,24 @@ +import 'dotenv/config'; +import Anthropic from '@anthropic-ai/sdk'; +import { AnthropicProvider } from '@corsair-dev/mcp'; +import { corsair } from '../server/corsair'; + +// Initialize Corsair tools +const provider = new AnthropicProvider(); +const tools = provider.build({ corsair }); + +const client = new Anthropic(); + +// Run with automatic tool loop +const message = await client.beta.messages.toolRunner({ + model: 'claude-opus-4-6', + max_tokens: 4096, + tools, + messages: [ + { role: 'user', content: 'list all slack channels, send test message to sdk-test channel' }, + ], +}); + +for (const block of message.content) { + if (block.type === 'text') process.stdout.write(block.text); +} \ No newline at end of file diff --git a/scripts/test-claude-sdk.ts b/scripts/test-claude-sdk.ts new file mode 100644 index 0000000..25f3f47 --- /dev/null +++ b/scripts/test-claude-sdk.ts @@ -0,0 +1,31 @@ +import 'dotenv/config'; +import { createSdkMcpServer, query } from '@anthropic-ai/claude-agent-sdk'; +import { ClaudeProvider } from '@corsair-dev/mcp'; +import { corsair } from '../server/corsair'; + +// Initialize Corsair MCP tools +const provider = new ClaudeProvider(); +const tools = await provider.build({ corsair }); + +// Create in-process MCP server +const server = createSdkMcpServer({ name: 'corsair', tools }); + +// Query Claude with MCP tools +const stream = query({ + prompt: 'list all slack channels, send test message to sdk-test channel', + options: { + model: 'claude-opus-4-6', + permissionMode: 'bypassPermissions', + allowDangerouslySkipPermissions: true, + mcpServers: { + corsair: server, + }, + }, +}); + +// Stream the response +for await (const event of stream) { + if ('result' in event) { + process.stdout.write(event.result); + } +} diff --git a/scripts/test-cron.ts b/scripts/test-cron.ts new file mode 100644 index 0000000..ecf41da --- /dev/null +++ b/scripts/test-cron.ts @@ -0,0 +1,18 @@ +import 'dotenv/config'; +import { corsair } from '../server/corsair'; // imported for type safety — injected at runtime +import { workflow } from '../server/sdk'; + +await workflow.cron({ + id: 'morningSlackReport', + description: 'Posts a morning message to #sdk-test every weekday at 9am', + schedule: '0 9 * * 1-5', + handler: async () => { + await corsair.slack.api.messages.post({ + channel: 'C0A3ZTB9X7X', + text: 'Good morning! Your daily report is ready.', + }); + }, +}); + +const workflows = await workflow.list('cron'); +console.table(workflows.map((w) => ({ name: w.name, schedule: (w.triggerConfig as any)?.cron, status: w.status }))); diff --git a/scripts/test-mcp.ts b/scripts/test-mcp.ts new file mode 100644 index 0000000..d159b3a --- /dev/null +++ b/scripts/test-mcp.ts @@ -0,0 +1,16 @@ +import 'dotenv/config'; +import Anthropic from '@anthropic-ai/sdk'; +import { getCorsairMcp } from '../server/sdk'; + +const anthropic = new Anthropic(); +const mcp = getCorsairMcp(); + +const response = await anthropic.beta.messages.create({ + model: 'claude-sonnet-4-6', + max_tokens: 4096, + mcp_servers: [{ type: 'url', name: 'corsair', url: mcp.url }], + messages: [{ role: 'user', content: 'List all available operations' }], + betas: ['mcp-client-2025-04-04'], +}); + +console.log(response.content); diff --git a/scripts/test-openai-agents.ts b/scripts/test-openai-agents.ts new file mode 100644 index 0000000..64ef276 --- /dev/null +++ b/scripts/test-openai-agents.ts @@ -0,0 +1,20 @@ +import 'dotenv/config'; +import { Agent, run, tool } from '@openai/agents'; +import { OpenAIAgentsProvider } from '@corsair-dev/mcp'; +import { corsair } from '../server/corsair'; + +// Initialize Corsair tools for OpenAI Agents SDK +const provider = new OpenAIAgentsProvider(); +const tools = provider.build({ corsair, tool }); + +// Create an agent with Corsair tools +const agent = new Agent({ + name: 'corsair-agent', + model: 'gpt-4.1', + instructions: 'You are a helpful assistant with access to Corsair tools. Use list_operations to discover available APIs, get_schema to understand required arguments, and corsair_run to execute them. When referencing resources (like channels), always use their ID, not their name. If a tool call fails, use get_schema to check the expected arguments and retry.', + tools, +}); + +// Run the agent +const result = await run(agent, 'list all slack channels and send test message to sdk-test channel'); +console.log(result.finalOutput); diff --git a/scripts/test-webhook.ts b/scripts/test-webhook.ts new file mode 100644 index 0000000..df188da --- /dev/null +++ b/scripts/test-webhook.ts @@ -0,0 +1,19 @@ +import 'dotenv/config'; +import { corsair } from '../server/corsair'; // imported for type safety — injected at runtime +import { workflow } from '../server/sdk'; + +await workflow.webhook({ + id: 'forwardSlackMessageToSdkTest', + description: 'Forwards every Slack message to #sdk-test', + trigger: { plugin: 'slack', action: 'messages.message' }, + handler: async (event: any) => { + if (!event?.text || event?.channel === 'C0A3ZTB9X7X') return; + await corsair.slack.api.messages.post({ + channel: 'C0A3ZTB9X7X', + text: `[forwarded] <@${event.user}>: ${event.text}`, + }); + }, +}); + +const workflows = await workflow.list('webhook'); +console.table(workflows.map((w) => ({ name: w.name, trigger: JSON.stringify(w.triggerConfig), status: w.status }))); diff --git a/server/agent.ts b/server/agent.ts index b7f475b..be72f5d 100644 --- a/server/agent.ts +++ b/server/agent.ts @@ -3,19 +3,16 @@ import { query, tool, } from '@anthropic-ai/claude-agent-sdk'; +import { createClaudeTools } from '@corsair/mcp'; import { desc, eq } from 'drizzle-orm'; import { z } from 'zod'; -import { db, permissions, whatsappMessages } from './db'; +import { db, whatsappMessages } from './db'; import { - archiveWorkflow, - listWorkflows, - storeWorkflow, - updateWorkflowRecord, -} from './executor'; -import { - registerCronWorkflow, - unregisterCronWorkflow, -} from './workflow-scheduler'; + cronAdapter, + permissionAdapter, + workflowAdapter, +} from './mcp-adapters'; +import { corsair } from './corsair'; // ───────────────────────────────────────────────────────────────────────────── // Types @@ -164,11 +161,23 @@ function buildSystemPromptWithHistory( // In-process MCP server // ───────────────────────────────────────────────────────────────────────────── -export function buildMcpServer(context?: { +export async function buildMcpServer(context?: { jid?: string; onMessage?: (text: string) => Promise; onAskHuman?: (question: string) => void; }) { + const basePermissionUrl = + process.env.BASE_PERMISSION_URL ?? + process.env.BASE_URL ?? + `http://localhost:${process.env.PORT ?? 3000}`; + const corsairTools = await createClaudeTools({ + corsair, + workflows: workflowAdapter, + cron: cronAdapter, + permissions: permissionAdapter, + basePermissionUrl, + context, + }); const sendMessageTool = tool( 'send_message', 'Send a message to the user without pausing. Use for acknowledgments ("On it!"), progress updates, and final answers. You can call it multiple times.', @@ -197,228 +206,6 @@ export function buildMcpServer(context?: { }, ); - const requestPermissionTool = tool( - 'request_permission', - 'Request permission from the user to execute a protected endpoint. Call this when a script returns a [PERMISSION_REQUIRED] message. Returns an approval URL. After calling this, call ask_human with the approval URL so the user can review and approve.', - { - endpoint: z - .string() - .describe( - 'Full endpoint path from the PERMISSION_REQUIRED message, e.g. "slack.messages.post"', - ), - args: z - .record(z.unknown()) - .describe('The arguments object from the PERMISSION_REQUIRED message'), - description: z - .string() - .describe( - 'Short human-readable summary of what this action will do, e.g. "Post a message to #general in Slack"', - ), - }, - async ({ endpoint, args, description }) => { - const [plugin, ...rest] = endpoint.split('.'); - const operation = rest.join('.'); - - const [perm] = await db - .insert(permissions) - .values({ - endpoint, - plugin: plugin!, - operation, - args, - description, - status: 'pending', - jid: context?.jid, - }) - .returning({ id: permissions.id }); - - const baseUrl = process.env.BASE_PERMISSION_URL; - const approvalUrl = `${baseUrl}/permissions/${perm!.id}`; - - const result = { - permissionId: perm!.id, - approvalUrl, - message: `Permission request created. Ask the user to approve at: ${approvalUrl}`, - }; - return { - content: [{ type: 'text' as const, text: JSON.stringify(result) }], - }; - }, - ); - - const manageWorkflowsTool = tool( - 'manage_workflows', - 'List (optional triggerType filter), create (store a new workflow), update (workflowId + fields), or archive (workflowId) workflows.', - { - action: z - .enum(['list', 'create', 'update', 'delete']) - .describe('The action to perform'), - triggerType: z - .enum(['cron', 'webhook', 'manual', 'all']) - .optional() - .describe('Filter workflows by trigger type (for list)'), - workflowId: z - .string() - .optional() - .describe('Workflow ID (function name) for create/update/delete'), - code: z.string().optional().describe('Workflow code for create/update'), - description: z.string().optional().describe('Human-readable description'), - cronSchedule: z - .string() - .optional() - .describe('Cron schedule for create/update'), - webhookTrigger: z - .object({ plugin: z.string(), action: z.string() }) - .optional() - .describe('Webhook trigger for create/update'), - status: z - .enum(['active', 'paused', 'archived']) - .optional() - .describe('Workflow status for update'), - }, - async ({ - action, - triggerType, - workflowId, - code, - description, - cronSchedule, - webhookTrigger, - status, - }) => { - console.log( - `[manage_workflows] action=${action} workflowId=${workflowId ?? 'N/A'} cronSchedule=${cronSchedule ?? 'N/A'} codeLen=${code?.length ?? 0}`, - ); - let result: unknown; - - if (action === 'list') { - result = { workflows: await listWorkflows(triggerType) }; - } else if (action === 'create') { - if (!workflowId || !code) { - result = { - success: false, - error: 'workflowId and code are required for create', - }; - } else { - const stored = await storeWorkflow({ - type: 'workflow', - workflowId, - code, - description: description?.trim() || undefined, - cronSchedule: cronSchedule?.trim() || undefined, - webhookTrigger, - notifyJid: context?.jid, - }); - console.log( - `[manage_workflows] storeWorkflow → id=${stored?.id} name=${stored?.name} triggerType=${stored?.triggerType}`, - ); - // Register with the cron scheduler immediately if it's a cron workflow - if (stored && cronSchedule?.trim()) { - const ok = registerCronWorkflow( - stored.id, - workflowId, - code, - cronSchedule.trim(), - context?.jid, - ); - console.log(`[manage_workflows] registerCronWorkflow → ok=${ok}`); - if (!ok) { - result = { - success: false, - error: `Invalid cron expression: "${cronSchedule}"`, - }; - return { - content: [ - { type: 'text' as const, text: JSON.stringify(result) }, - ], - }; - } - } - result = { - success: true, - workflow: { - id: stored!.id, - name: stored!.name, - triggerType: stored!.triggerType, - status: stored!.status, - }, - }; - } - } else if (action === 'delete') { - if (!workflowId) { - result = { - success: false, - error: 'workflowId is required for delete', - }; - } else { - const archived = await archiveWorkflow(workflowId); - if (!archived) { - result = { - success: false, - error: `Workflow "${workflowId}" not found`, - }; - } else { - unregisterCronWorkflow(archived.id); - result = { - success: true, - message: `Workflow "${archived.name}" archived`, - }; - } - } - } else { - // action === 'update' - if (!workflowId) { - result = { - success: false, - error: 'workflowId is required for update', - }; - } else { - const updated = await updateWorkflowRecord(workflowId, { - code, - description, - cronSchedule, - webhookTrigger, - status, - }); - if (!updated) { - result = { - success: false, - error: `Workflow "${workflowId}" not found`, - }; - } else { - // Sync the in-memory scheduler with the new DB state - if (updated.status === 'archived' || updated.status === 'paused') { - unregisterCronWorkflow(updated.id); - } else if (updated.triggerType === 'cron') { - const cfg = updated.triggerConfig as { cron?: string }; - if (cfg.cron) { - registerCronWorkflow( - updated.id, - updated.name, - updated.code, - cfg.cron, - ); - } - } - result = { - success: true, - workflow: { - id: updated.id, - name: updated.name, - triggerType: updated.triggerType, - status: updated.status, - }, - }; - } - } - } - - return { - content: [{ type: 'text' as const, text: JSON.stringify(result) }], - }; - }, - ); - const getConversationHistoryTool = tool( 'get_conversation_history', 'Fetch past messages from the current WhatsApp chat. Use when you need more context about what the user said earlier. Start with a small limit and call again with a larger one if needed.', @@ -475,10 +262,9 @@ export function buildMcpServer(context?: { name: 'corsair', version: '1.0.0', tools: [ + ...corsairTools, sendMessageTool, askHumanTool, - requestPermissionTool, - manageWorkflowsTool, getConversationHistoryTool, ], }); @@ -510,12 +296,11 @@ export async function runAgent( ); const abortController = new AbortController(); let askHumanQuestion: string | null = null; - const mcpServer = buildMcpServer({ + const mcpServer = await buildMcpServer({ jid: opts.jid, onMessage, onAskHuman: (question) => { askHumanQuestion = question; - // Defer abort so the tool handler returns cleanly before the SDK is stopped process.nextTick(() => abortController.abort()); }, }); @@ -602,13 +387,12 @@ export async function* createAgentStream( const systemPrompt = buildSystemPromptWithHistory(opts.history); const abortController = new AbortController(); let askHumanQuestion: string | null = null; - const mcpServer = buildMcpServer({ + const mcpServer = await buildMcpServer({ onAskHuman: (question) => { askHumanQuestion = question; process.nextTick(() => abortController.abort()); }, }); - // Map from toolCallId → toolName so we can emit tool-result with name const pendingToolCalls = new Map(); try { @@ -658,14 +442,14 @@ export async function* createAgentStream( typeof block === 'object' && block !== null && 'type' in block && - (block satisfies { type: string }).type === 'tool_result' + block.type === 'tool_result' && + 'tool_use_id' in block ) { - const toolResult = block satisfies { tool_use_id: string }; const toolName = - pendingToolCalls.get(toolResult.tool_use_id) ?? 'unknown'; + pendingToolCalls.get(block.tool_use_id) ?? 'unknown'; yield { type: 'tool-result', - toolCallId: toolResult.tool_use_id, + toolCallId: block.tool_use_id, toolName, }; } diff --git a/server/corsair.ts b/server/corsair.ts index d91acf4..d909f7c 100644 --- a/server/corsair.ts +++ b/server/corsair.ts @@ -1,8 +1,8 @@ -import { createCorsair, slack } from 'corsair'; +import { createCorsair, linear, slack } from 'corsair'; import { pool } from './db'; export const corsair = createCorsair({ - plugins: [slack()], + plugins: [slack(), linear()], database: pool, kek: process.env.CORSAIR_KEK!, multiTenancy: false, diff --git a/server/db/index.ts b/server/db/index.ts index 7e6c66d..028054c 100644 --- a/server/db/index.ts +++ b/server/db/index.ts @@ -1,11 +1,14 @@ import { config } from 'dotenv'; import { drizzle } from 'drizzle-orm/node-postgres'; import { Pool } from 'pg'; +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; import * as schema from './schema'; // Load env as early as possible (import order matters with ESM). -config({ path: '.env' }); +// Use an absolute path so this works regardless of cwd (e.g. when spawned by Claude Desktop MCP). +config({ path: resolve(dirname(fileURLToPath(import.meta.url)), '../../.env') }); // ───────────────────────────────────────────────────────────────────────────── // Connection (shared with Corsair) diff --git a/server/executor.ts b/server/executor.ts index 3b59801..3cc73a5 100644 --- a/server/executor.ts +++ b/server/executor.ts @@ -38,11 +38,13 @@ export async function executeWorkflow( const wrappedCode = ` import { corsair } from './server/corsair'; const __event: unknown = ${JSON.stringify(eventPayload ?? null)}; +const ctx = { sdk: corsair }; ${code} -// Execute the workflow -${workflowId}().catch(console.error); +// Execute the workflow — pass ctx and the event payload so workflow functions +// can use either ctx.sdk. or the top-level corsair import directly. +${workflowId}(ctx, __event).catch(console.error); `; try { @@ -327,6 +329,8 @@ export async function listWorkflows( })); } +const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + export async function findWorkflowByNameOrId(nameOrId: string) { const byName = await db .select() @@ -335,6 +339,8 @@ export async function findWorkflowByNameOrId(nameOrId: string) { .limit(1); if (byName[0]) return byName[0]; + if (!UUID_RE.test(nameOrId)) return null; + const byId = await db .select() .from(workflows) diff --git a/server/index.ts b/server/index.ts index bdf33cf..f182aed 100644 --- a/server/index.ts +++ b/server/index.ts @@ -3,9 +3,16 @@ import { createExpressMiddleware } from '@trpc/server/adapters/express'; import { processWebhook } from 'corsair'; import { asc, eq } from 'drizzle-orm'; import express from 'express'; +import { corsairPermissions, type PermissionLike } from '@corsair/ui'; import type { SimpleMessage } from './agent'; import { runAgent, WORKFLOW_FAILURE_PROMPT } from './agent'; +import { createBaseMcpServer, createMcpRouter } from '@corsair/mcp'; import { corsair } from './corsair'; +import { + cronAdapter, + permissionAdapter, + workflowAdapter, +} from './mcp-adapters'; import { db, permissions, @@ -320,6 +327,24 @@ async function main() { } }); + // ── MCP HTTP server (OpenAI / Anthropic agent integration) ─────────────── + const basePermissionUrl = + process.env.BASE_PERMISSION_URL ?? + process.env.BASE_URL ?? + `http://localhost:${process.env.PORT ?? 3000}`; + app.use( + '/mcp', + createMcpRouter(() => + createBaseMcpServer({ + corsair, + workflows: workflowAdapter, + cron: cronAdapter, + permissions: permissionAdapter, + basePermissionUrl, + }), + ), + ); + // ── tRPC router ─────────────────────────────────────────────────────────── app.use( '/trpc', @@ -376,161 +401,34 @@ async function main() { return; } - const FIELD_LABELS: Record> = { - 'messages.post': { - channel: 'Channel', - text: 'Message', - thread_ts: 'Thread', - reply_broadcast: 'Also send to channel', - }, - 'emails.send': { - to: 'To', - from: 'From', - subject: 'Subject', - html: 'Body', - text: 'Body', - cc: 'CC', - bcc: 'BCC', - }, - 'issues.create': { - title: 'Title', - description: 'Description', - teamId: 'Team', - assigneeId: 'Assignee', - priority: 'Priority', - stateId: 'Status', - }, - }; - const PLUGIN_COLORS: Record = { - slack: '#4a154b', - linear: '#5e6ad2', - discord: '#5865f2', - github: '#333', - resend: '#000', - gmail: '#ea4335', + const permissionLike: PermissionLike = { + id: perm.id, + plugin: perm.plugin, + endpoint: perm.operation ?? perm.endpoint, + operation: perm.operation, + description: perm.description, + status: perm.status, + args: + perm.args && typeof perm.args === 'object' + ? (perm.args as Record) + : {}, + createdAt: perm.createdAt, }; - function esc(s: unknown) { - return String(s ?? '') - .replace(/&/g, '&') - .replace(//g, '>'); - } - function getLabel(op: string, key: string) { - return FIELD_LABELS[op]?.[key] ?? key; - } - function renderArgVal(val: unknown): string { - if (val === null || val === undefined) - return ``; - if (typeof val === 'boolean') return val ? 'Yes' : 'No'; - if (typeof val === 'string') { - if (val.length > 120 || val.includes('\n')) - return `
${esc(val)}
`; - return esc(val); - } - if (Array.isArray(val)) return esc(val.join(', ')); - return `
${esc(JSON.stringify(val, null, 2))}
`; - } - - const isPending = perm.status === 'pending'; - const statusColor = - perm.status === 'granted' || perm.status === 'completed' - ? '#22c55e' - : perm.status === 'declined' - ? '#ef4444' - : '#f59e0b'; - const badgeBg = PLUGIN_COLORS[perm.plugin] ?? '#141414'; - const args = - perm.args && typeof perm.args === 'object' - ? (perm.args as Record) - : {}; - const argEntries = Object.entries(args); - const ts = new Date(perm.createdAt).toLocaleString('en-US', { - dateStyle: 'medium', - timeStyle: 'short', + const onApproval = () => ({ + method: 'POST' as const, + url: `/api/permissions/${id}/resolve`, }); - let statusBar = ''; - if (!isPending) { - const bg = - perm.status === 'granted' || perm.status === 'completed' - ? '#14532d' - : '#7f1d1d'; - statusBar = `
This permission has been ${esc(perm.status)}.
`; - } - - let argsHtml = ''; - if (argEntries.length > 0) { - const rows = argEntries - .map( - ([k, v]) => - `
${esc(getLabel(perm.operation, k))}
${renderArgVal(v)}
`, - ) - .join(''); - argsHtml = `
Request details
${rows}
`; - } + const onDenial = () => ({ + method: 'POST' as const, + url: `/api/permissions/${id}/resolve`, + }); - const actions = isPending - ? `
- - -
- -