diff --git a/apps/desktop/package-lock.json b/apps/desktop/package-lock.json index b9e2a6ab6..211494c36 100644 --- a/apps/desktop/package-lock.json +++ b/apps/desktop/package-lock.json @@ -8,16 +8,12 @@ "name": "ade-desktop", "version": "0.0.0", "dependencies": { - "@anthropic-ai/claude-agent-sdk": "^0.2.49", - "@openai/codex-sdk": "^0.104.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-tabs": "^1.1.13", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", "@xyflow/react": "^12.5.0", - "ai": "^6.0.94", - "ai-sdk-provider-claude-code": "^3.4.2", "chokidar": "^4.0.3", "clsx": "^2.1.1", "lucide-react": "^0.563.0", @@ -27,10 +23,8 @@ "node-pty": "^1.1.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-markdown": "^10.1.0", "react-resizable-panels": "^4.6.2", "react-router-dom": "^7.13.0", - "remark-gfm": "^4.0.1", "sql.js": "^1.13.0", "tailwind-merge": "^3.4.0", "yaml": "^2.8.2", @@ -38,8 +32,6 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4.1.18", - "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", "@types/node": "^20.11.30", "@types/node-cron": "^3.0.11", "@types/react": "^18.2.74", @@ -51,7 +43,6 @@ "cross-env": "^7.0.3", "electron": "^40.2.1", "electron-rebuild": "^3.2.9", - "jsdom": "^22.1.0", "postcss": "^8.5.6", "tailwindcss": "^4.1.18", "tsup": "^8.3.5", @@ -61,49 +52,6 @@ "wait-on": "^7.2.0" } }, - "node_modules/@ai-sdk/gateway": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.52.tgz", - "integrity": "sha512-lYCXP8T3YnIDiz8DP7loAMT27wnblc3IAYzQ7igg89RCRyTUjk6ffbxHXXQ5Pmv8jrdLF0ZIJnH54Dsr1OCKHg==", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.15", - "@vercel/oidc": "3.1.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/@ai-sdk/provider": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", - "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", - "dependencies": { - "json-schema": "^0.4.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@ai-sdk/provider-utils": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz", - "integrity": "sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w==", - "dependencies": { - "@ai-sdk/provider": "3.0.8", - "@standard-schema/spec": "^1.1.0", - "eventsource-parser": "^3.0.6" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", @@ -116,28 +64,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@anthropic-ai/claude-agent-sdk": { - "version": "0.2.49", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.2.49.tgz", - "integrity": "sha512-3avi409dwuGkPEETpWa0gyJvRMr3b6LxeuW5/sAPCOtLD9WxH9fYltbA5wZoazxTw5mlbXmjDp7JqO1rlmpaIQ==", - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "^0.34.2", - "@img/sharp-darwin-x64": "^0.34.2", - "@img/sharp-linux-arm": "^0.34.2", - "@img/sharp-linux-arm64": "^0.34.2", - "@img/sharp-linux-x64": "^0.34.2", - "@img/sharp-linuxmusl-arm64": "^0.34.2", - "@img/sharp-linuxmusl-x64": "^0.34.2", - "@img/sharp-win32-arm64": "^0.34.2", - "@img/sharp-win32-x64": "^0.34.2" - }, - "peerDependencies": { - "zod": "^4.0.0" - } - }, "node_modules/@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -356,15 +282,6 @@ "@babel/core": "^7.0.0-0" } }, - "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", @@ -834,294 +751,6 @@ "@hapi/hoek": "^9.0.0" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -1236,157 +865,23 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@openai/codex": { - "version": "0.104.0", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0.tgz", - "integrity": "sha512-pPa2VGHozwjPsPOYAEXcH7nNt1QH7AZR8zV8jYx6BFi1LJlmJkan2rvIS4MYbPdi2O6cd5kWfPCAHE0fEV2ifA==", - "bin": { - "codex": "bin/codex.js" + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" + }, + "node_modules/@radix-ui/react-arrow": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" }, - "engines": { - "node": ">=16" - }, - "optionalDependencies": { - "@openai/codex-darwin-arm64": "npm:@openai/codex@0.104.0-darwin-arm64", - "@openai/codex-darwin-x64": "npm:@openai/codex@0.104.0-darwin-x64", - "@openai/codex-linux-arm64": "npm:@openai/codex@0.104.0-linux-arm64", - "@openai/codex-linux-x64": "npm:@openai/codex@0.104.0-linux-x64", - "@openai/codex-win32-arm64": "npm:@openai/codex@0.104.0-win32-arm64", - "@openai/codex-win32-x64": "npm:@openai/codex@0.104.0-win32-x64" - } - }, - "node_modules/@openai/codex-darwin-arm64": { - "name": "@openai/codex", - "version": "0.104.0-darwin-arm64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-darwin-arm64.tgz", - "integrity": "sha512-Y+lifRKAgNSBcaIM5UXXYnGWAJrPORPXABZBCxxiwwB8/XzZRDwp3K+X5i7dT0GfKScGFXuul6sJ2sVSPL4w4A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@openai/codex-darwin-x64": { - "name": "@openai/codex", - "version": "0.104.0-darwin-x64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-darwin-x64.tgz", - "integrity": "sha512-TwQ9zj0XbSrtCxFWKnnSQfmWmKhNMx1rSpSaSrLNSFVohxRwOWUZ2GBciO6jCLEiJvswR6nTMy1mA0n7MyVJiw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@openai/codex-linux-arm64": { - "name": "@openai/codex", - "version": "0.104.0-linux-arm64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-linux-arm64.tgz", - "integrity": "sha512-3oBBjMaCnhGfijsklOzVqG0LH/IFWoDnRJkvFl1utMI+GJECUr37uL/KsSFTuC2kIjham6U57dAK6xQnQxqxPQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@openai/codex-linux-x64": { - "name": "@openai/codex", - "version": "0.104.0-linux-x64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-linux-x64.tgz", - "integrity": "sha512-vhYaWsEwZmxZbeu5u9/k3VO1F4aTMYaTCebRgdzux7bfeDw2nms1SAcP+AkfCStqVSz26yaPGbwcUMqaknW4gQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@openai/codex-sdk": { - "version": "0.104.0", - "resolved": "https://registry.npmjs.org/@openai/codex-sdk/-/codex-sdk-0.104.0.tgz", - "integrity": "sha512-eXnGqFUh4BRASRK4f8IyLHQG7b4DUjfM7GaasLUNggneUEUVmBgEP24mTo6Qu53oIuA1t+j1QxdCQbxAlWZKPA==", - "dependencies": { - "@openai/codex": "0.104.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@openai/codex-win32-arm64": { - "name": "@openai/codex", - "version": "0.104.0-win32-arm64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-win32-arm64.tgz", - "integrity": "sha512-2ypuM6yWcjAtq7DmEgFBsmtw7rWLcoy6Cxaq+Hn8dZfEdijASyc59AzyWhWLKYLuOxcprFn/oQitElrpPD9JOA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@openai/codex-win32-x64": { - "name": "@openai/codex", - "version": "0.104.0-win32-x64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-win32-x64.tgz", - "integrity": "sha512-awyNLtfbTbj+2JzgsAIm+KFrxeAmxe/Fuqw/ZwBj8ljtO7SQWTT3kxDbf7iuA7E7IErGlQw/plgFgq/LJdsacg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=16" - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==" - }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "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" + "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": { @@ -1994,11 +1489,6 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==" - }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "dev": true, @@ -2266,101 +1756,6 @@ "tailwindcss": "4.1.18" } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dev": true, - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/dom/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@testing-library/dom/node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@testing-library/dom/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "peer": true - }, - "node_modules/@testing-library/react": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", - "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0 || ^19.0.0", - "@types/react-dom": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", - "dev": true, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -2370,13 +1765,6 @@ "node": ">= 10" } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "peer": true - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -2487,14 +1875,6 @@ "@types/d3-selection": "*" } }, - "node_modules/@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dependencies": { - "@types/ms": "*" - } - }, "node_modules/@types/emscripten": { "version": "1.41.5", "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.5.tgz", @@ -2503,24 +1883,9 @@ }, "node_modules/@types/estree": { "version": "1.0.8", + "dev": true, "license": "MIT" }, - "node_modules/@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", - "dependencies": { - "@types/estree": "*" - } - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dependencies": { - "@types/unist": "*" - } - }, "node_modules/@types/http-cache-semantics": { "version": "4.2.0", "dev": true, @@ -2534,19 +1899,6 @@ "@types/node": "*" } }, - "node_modules/@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" - }, "node_modules/@types/node": { "version": "20.19.33", "dev": true, @@ -2563,10 +1915,12 @@ }, "node_modules/@types/prop-types": { "version": "15.7.15", + "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.28", + "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -2605,11 +1959,6 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "optional": true }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "node_modules/@types/yauzl": { "version": "2.10.3", "dev": true, @@ -2619,19 +1968,6 @@ "@types/node": "*" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==" - }, - "node_modules/@vercel/oidc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", - "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==", - "engines": { - "node": ">= 20" - } - }, "node_modules/@vitejs/plugin-react": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", @@ -2797,13 +2133,6 @@ "d3-zoom": "^3.0.0" } }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "deprecated": "Use your platform's native atob() and btoa() methods instead", - "dev": true - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -2870,39 +2199,6 @@ "node": ">=8" } }, - "node_modules/ai": { - "version": "6.0.94", - "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.94.tgz", - "integrity": "sha512-/F9wh262HbK05b/5vILh38JvPiheonT+kBj1L97712E7VPchqmcx7aJuZN3QSk5Pj6knxUJLm2FFpYJI1pHXUA==", - "dependencies": { - "@ai-sdk/gateway": "3.0.52", - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.15", - "@opentelemetry/api": "1.9.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^3.25.76 || ^4.1.8" - } - }, - "node_modules/ai-sdk-provider-claude-code": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/ai-sdk-provider-claude-code/-/ai-sdk-provider-claude-code-3.4.2.tgz", - "integrity": "sha512-Gej+/7PnteCSEmxG1WnIRGBS9wLCI8pu7GmsEHh4z9oFHP+sBwep4koRaGbbLfIXk8SXqvC6vWiWJkFDSwaMvA==", - "dependencies": { - "@ai-sdk/provider": "^3.0.0", - "@ai-sdk/provider-utils": "^4.0.1", - "@anthropic-ai/claude-agent-sdk": "^0.2.33" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "zod": "^4.0.0" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "dev": true, @@ -2961,16 +2257,6 @@ "node": ">=10" } }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "peer": true, - "dependencies": { - "dequal": "^2.0.3" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -3031,15 +2317,6 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3325,15 +2602,6 @@ } ] }, - "node_modules/ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/chai": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", @@ -3378,42 +2646,6 @@ "node": ">=8" } }, - "node_modules/character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -3564,15 +2796,6 @@ "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", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/commander": { "version": "4.1.1", "dev": true, @@ -3677,20 +2900,9 @@ "node": ">= 8" } }, - "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dev": true, - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/csstype": { "version": "3.2.3", + "devOptional": true, "license": "MIT" }, "node_modules/d3-color": { @@ -3789,22 +3001,9 @@ "node": ">=12" } }, - "node_modules/data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/debug": { "version": "4.4.3", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3818,24 +3017,6 @@ } } }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true - }, - "node_modules/decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "dependencies": { - "character-entities": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/decompress-response": { "version": "6.0.0", "dev": true, @@ -3941,14 +3122,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, - "node_modules/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "engines": { - "node": ">=6" - } - }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -3969,18 +3142,6 @@ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, - "node_modules/devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "dependencies": { - "dequal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -3990,26 +3151,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "peer": true - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/dompurify": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", @@ -4182,18 +3323,6 @@ "node": ">=10.13.0" } }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/env-paths": { "version": "2.2.1", "dev": true, @@ -4715,34 +3844,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "dev": true }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, "node_modules/extract-zip": { "version": "2.0.1", "dev": true, @@ -5191,65 +4298,6 @@ "node": ">= 0.4" } }, - "node_modules/hast-util-to-jsx-runtime": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", - "dependencies": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "dependencies": { - "@types/hast": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-url-attributes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/http-cache-semantics": { "version": "4.2.0", "dev": true, @@ -5308,6 +4356,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -5376,11 +4425,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/inline-style-parser": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==" - }, "node_modules/ip-address": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", @@ -5390,37 +4434,6 @@ "node": ">= 12" } }, - "node_modules/is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "dev": true, @@ -5429,15 +4442,6 @@ "node": ">=8" } }, - "node_modules/is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -5453,23 +4457,6 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -5520,48 +4507,6 @@ "version": "4.0.0", "license": "MIT" }, - "node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", - "decimal.js": "^10.4.3", - "domexception": "^4.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -5579,11 +4524,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, "node_modules/json-stringify-safe": { "version": "5.0.1", "dev": true, @@ -5924,15 +4864,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/loose-envify": { "version": "1.4.0", "license": "MIT", @@ -5977,16 +4908,6 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, "node_modules/lzma-native": { "version": "8.0.6", "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-8.0.6.tgz", @@ -6049,15 +4970,6 @@ "node": ">=12" } }, - "node_modules/markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/marked": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", @@ -6089,938 +5001,137 @@ "node": ">= 0.4" } }, - "node_modules/mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", "dependencies": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" + "mime-db": "1.52.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 0.6" } }, - "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/mdast-util-from-markdown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", - "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "node_modules/mimic-response": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, - "node_modules/mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "brace-expansion": "^1.1.7" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "*" } }, - "node_modules/mdast-util-gfm-autolink-literal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "dependencies": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/mdast-util-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" + "yallist": "^4.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "minipass": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 8" } }, - "node_modules/mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, "dependencies": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "minipass": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">= 8" } }, - "node_modules/mdast-util-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" + "minipass": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "engines": { + "node": ">=8" } }, - "node_modules/mdast-util-mdx-jsx": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", - "dependencies": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "dependencies": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "dependencies": { - "@types/mdast": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "dependencies": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "dependencies": { - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "dependencies": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "node_modules/micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ], - "dependencies": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "node_modules/micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", - "funding": [ - { - "type": "GitHub Sponsors", - "url": "https://github.com/sponsors/unifiedjs" - }, - { - "type": "OpenCollective", - "url": "https://opencollective.com/unified" - } - ] - }, - "node_modules/mime-db": { - "version": "1.52.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" + "engines": { + "node": ">=8" } }, "node_modules/minipass/node_modules/yallist": { @@ -7120,6 +5231,7 @@ }, "node_modules/ms": { "version": "2.1.3", + "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -7330,12 +5442,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", - "dev": true - }, "node_modules/object-assign": { "version": "4.1.1", "dev": true, @@ -7437,41 +5543,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "dependencies": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" - }, - "node_modules/parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -7670,32 +5741,11 @@ "node": ">=10" } }, - "node_modules/property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/proxy-from-env": { "version": "1.1.0", "dev": true, "license": "MIT" }, - "node_modules/psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", - "dev": true, - "dependencies": { - "punycode": "^2.3.1" - }, - "funding": { - "url": "https://github.com/sponsors/lupomontero" - } - }, "node_modules/pump": { "version": "3.0.3", "dev": true, @@ -7705,21 +5755,6 @@ "once": "^1.3.1" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "node_modules/quick-lru": { "version": "5.1.1", "dev": true, @@ -7758,32 +5793,6 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "node_modules/react-markdown": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", - "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "html-url-attributes": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=18", - "react": ">=18" - } - }, "node_modules/react-refresh": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", @@ -7929,68 +5938,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/remark-gfm": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-rehype": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", - "dependencies": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "dependencies": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/require-directory": { "version": "2.1.1", "dev": true, @@ -7999,12 +5946,6 @@ "node": ">=0.10.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, "node_modules/resolve-alpn": { "version": "1.2.1", "dev": true, @@ -8439,12 +6380,6 @@ "win32" ] }, - "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", - "dev": true - }, "node_modules/rxjs": { "version": "7.8.2", "dev": true, @@ -8477,19 +6412,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } + "optional": true }, "node_modules/scheduler": { "version": "0.23.2", @@ -8634,15 +6558,6 @@ "node": ">=0.10.0" } }, - "node_modules/space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/sprintf-js": { "version": "1.1.3", "dev": true, @@ -8700,19 +6615,6 @@ "node": ">=8" } }, - "node_modules/stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "dependencies": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "dev": true, @@ -8736,22 +6638,6 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/style-to-js": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", - "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", - "dependencies": { - "style-to-object": "1.0.14" - } - }, - "node_modules/style-to-object": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", - "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", - "dependencies": { - "inline-style-parser": "0.2.7" - } - }, "node_modules/sucrase": { "version": "3.35.1", "dev": true, @@ -8798,12 +6684,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, "node_modules/tailwind-merge": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", @@ -8928,42 +6808,6 @@ "node": ">=14.0.0" } }, - "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/tree-kill": { "version": "1.2.2", "dev": true, @@ -8972,24 +6816,6 @@ "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", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/ts-interface-checker": { "version": "0.1.13", "dev": true, @@ -9093,24 +6919,6 @@ "dev": true, "license": "MIT" }, - "node_modules/unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "dependencies": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/unique-filename": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", @@ -9135,69 +6943,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/unist-util-is": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "dependencies": { - "@types/unist": "^3.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", - "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/unist-util-visit-parents": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/universalify": { "version": "0.1.2", "dev": true, @@ -9236,16 +6981,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -9309,32 +7044,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", - "dependencies": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, - "node_modules/vfile-message": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", - "dependencies": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" - } - }, "node_modules/vite": { "version": "4.5.14", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", @@ -9571,18 +7280,6 @@ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", "dev": true }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/wait-on": { "version": "7.2.0", "dev": true, @@ -9604,54 +7301,10 @@ "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=14" + "defaults": "^1.0.3" } }, "node_modules/which": { @@ -9714,42 +7367,6 @@ "dev": true, "license": "ISC" }, - "node_modules/ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "dev": true, - "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/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, "node_modules/y18n": { "version": "5.0.8", "dev": true, @@ -9824,15 +7441,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "peer": true, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/zustand": { "version": "5.0.11", "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz", @@ -9860,68 +7468,15 @@ "optional": true } } - }, - "node_modules/zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } } }, "dependencies": { - "@ai-sdk/gateway": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.52.tgz", - "integrity": "sha512-lYCXP8T3YnIDiz8DP7loAMT27wnblc3IAYzQ7igg89RCRyTUjk6ffbxHXXQ5Pmv8jrdLF0ZIJnH54Dsr1OCKHg==", - "requires": { - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.15", - "@vercel/oidc": "3.1.0" - } - }, - "@ai-sdk/provider": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.8.tgz", - "integrity": "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==", - "requires": { - "json-schema": "^0.4.0" - } - }, - "@ai-sdk/provider-utils": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.15.tgz", - "integrity": "sha512-8XiKWbemmCbvNN0CLR9u3PQiet4gtEVIrX4zzLxnCj06AwsEDJwJVBbKrEI4t6qE8XRSIvU2irka0dcpziKW6w==", - "requires": { - "@ai-sdk/provider": "3.0.8", - "@standard-schema/spec": "^1.1.0", - "eventsource-parser": "^3.0.6" - } - }, "@alloc/quick-lru": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", "dev": true }, - "@anthropic-ai/claude-agent-sdk": { - "version": "0.2.49", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.2.49.tgz", - "integrity": "sha512-3avi409dwuGkPEETpWa0gyJvRMr3b6LxeuW5/sAPCOtLD9WxH9fYltbA5wZoazxTw5mlbXmjDp7JqO1rlmpaIQ==", - "requires": { - "@img/sharp-darwin-arm64": "^0.34.2", - "@img/sharp-darwin-x64": "^0.34.2", - "@img/sharp-linux-arm": "^0.34.2", - "@img/sharp-linux-arm64": "^0.34.2", - "@img/sharp-linux-x64": "^0.34.2", - "@img/sharp-linuxmusl-arm64": "^0.34.2", - "@img/sharp-linuxmusl-x64": "^0.34.2", - "@img/sharp-win32-arm64": "^0.34.2", - "@img/sharp-win32-x64": "^0.34.2" - } - }, "@babel/code-frame": { "version": "7.29.0", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", @@ -10076,12 +7631,6 @@ "@babel/helper-plugin-utils": "^7.27.1" } }, - "@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", - "dev": true - }, "@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", @@ -10331,123 +7880,6 @@ "@hapi/hoek": "^9.0.0" } }, - "@img/sharp-darwin-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", - "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", - "optional": true, - "requires": { - "@img/sharp-libvips-darwin-arm64": "1.2.4" - } - }, - "@img/sharp-darwin-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", - "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", - "optional": true, - "requires": { - "@img/sharp-libvips-darwin-x64": "1.2.4" - } - }, - "@img/sharp-libvips-darwin-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", - "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", - "optional": true - }, - "@img/sharp-libvips-darwin-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", - "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", - "optional": true - }, - "@img/sharp-libvips-linux-arm": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", - "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", - "optional": true - }, - "@img/sharp-libvips-linux-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", - "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", - "optional": true - }, - "@img/sharp-libvips-linux-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", - "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", - "optional": true - }, - "@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", - "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", - "optional": true - }, - "@img/sharp-libvips-linuxmusl-x64": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", - "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", - "optional": true - }, - "@img/sharp-linux-arm": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", - "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", - "optional": true, - "requires": { - "@img/sharp-libvips-linux-arm": "1.2.4" - } - }, - "@img/sharp-linux-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", - "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", - "optional": true, - "requires": { - "@img/sharp-libvips-linux-arm64": "1.2.4" - } - }, - "@img/sharp-linux-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", - "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", - "optional": true, - "requires": { - "@img/sharp-libvips-linux-x64": "1.2.4" - } - }, - "@img/sharp-linuxmusl-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", - "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", - "optional": true, - "requires": { - "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" - } - }, - "@img/sharp-linuxmusl-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", - "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", - "optional": true, - "requires": { - "@img/sharp-libvips-linuxmusl-x64": "1.2.4" - } - }, - "@img/sharp-win32-arm64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", - "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", - "optional": true - }, - "@img/sharp-win32-x64": { - "version": "0.34.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", - "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", - "optional": true - }, "@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", @@ -10528,68 +7960,6 @@ "rimraf": "^3.0.2" } }, - "@openai/codex": { - "version": "0.104.0", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0.tgz", - "integrity": "sha512-pPa2VGHozwjPsPOYAEXcH7nNt1QH7AZR8zV8jYx6BFi1LJlmJkan2rvIS4MYbPdi2O6cd5kWfPCAHE0fEV2ifA==", - "requires": { - "@openai/codex-darwin-arm64": "npm:@openai/codex@0.104.0-darwin-arm64", - "@openai/codex-darwin-x64": "npm:@openai/codex@0.104.0-darwin-x64", - "@openai/codex-linux-arm64": "npm:@openai/codex@0.104.0-linux-arm64", - "@openai/codex-linux-x64": "npm:@openai/codex@0.104.0-linux-x64", - "@openai/codex-win32-arm64": "npm:@openai/codex@0.104.0-win32-arm64", - "@openai/codex-win32-x64": "npm:@openai/codex@0.104.0-win32-x64" - } - }, - "@openai/codex-darwin-arm64": { - "version": "npm:@openai/codex@0.104.0-darwin-arm64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-darwin-arm64.tgz", - "integrity": "sha512-Y+lifRKAgNSBcaIM5UXXYnGWAJrPORPXABZBCxxiwwB8/XzZRDwp3K+X5i7dT0GfKScGFXuul6sJ2sVSPL4w4A==", - "optional": true - }, - "@openai/codex-darwin-x64": { - "version": "npm:@openai/codex@0.104.0-darwin-x64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-darwin-x64.tgz", - "integrity": "sha512-TwQ9zj0XbSrtCxFWKnnSQfmWmKhNMx1rSpSaSrLNSFVohxRwOWUZ2GBciO6jCLEiJvswR6nTMy1mA0n7MyVJiw==", - "optional": true - }, - "@openai/codex-linux-arm64": { - "version": "npm:@openai/codex@0.104.0-linux-arm64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-linux-arm64.tgz", - "integrity": "sha512-3oBBjMaCnhGfijsklOzVqG0LH/IFWoDnRJkvFl1utMI+GJECUr37uL/KsSFTuC2kIjham6U57dAK6xQnQxqxPQ==", - "optional": true - }, - "@openai/codex-linux-x64": { - "version": "npm:@openai/codex@0.104.0-linux-x64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-linux-x64.tgz", - "integrity": "sha512-vhYaWsEwZmxZbeu5u9/k3VO1F4aTMYaTCebRgdzux7bfeDw2nms1SAcP+AkfCStqVSz26yaPGbwcUMqaknW4gQ==", - "optional": true - }, - "@openai/codex-sdk": { - "version": "0.104.0", - "resolved": "https://registry.npmjs.org/@openai/codex-sdk/-/codex-sdk-0.104.0.tgz", - "integrity": "sha512-eXnGqFUh4BRASRK4f8IyLHQG7b4DUjfM7GaasLUNggneUEUVmBgEP24mTo6Qu53oIuA1t+j1QxdCQbxAlWZKPA==", - "requires": { - "@openai/codex": "0.104.0" - } - }, - "@openai/codex-win32-arm64": { - "version": "npm:@openai/codex@0.104.0-win32-arm64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-win32-arm64.tgz", - "integrity": "sha512-2ypuM6yWcjAtq7DmEgFBsmtw7rWLcoy6Cxaq+Hn8dZfEdijASyc59AzyWhWLKYLuOxcprFn/oQitElrpPD9JOA==", - "optional": true - }, - "@openai/codex-win32-x64": { - "version": "npm:@openai/codex@0.104.0-win32-x64", - "resolved": "https://registry.npmjs.org/@openai/codex/-/codex-0.104.0-win32-x64.tgz", - "integrity": "sha512-awyNLtfbTbj+2JzgsAIm+KFrxeAmxe/Fuqw/ZwBj8ljtO7SQWTT3kxDbf7iuA7E7IErGlQw/plgFgq/LJdsacg==", - "optional": true - }, - "@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==" - }, "@radix-ui/primitive": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", @@ -10904,11 +8274,6 @@ "version": "4.6.0", "dev": true }, - "@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==" - }, "@szmarczak/http-timer": { "version": "4.0.6", "dev": true, @@ -11056,80 +8421,12 @@ "tailwindcss": "4.1.18" } }, - "@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dev": true, - "peer": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "peer": true - }, - "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "peer": true, - "requires": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - } - }, - "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true, - "peer": true - } - } - }, - "@testing-library/react": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", - "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", - "dev": true, - "requires": { - "@babel/runtime": "^7.12.5" - } - }, - "@testing-library/user-event": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", - "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", - "dev": true, - "requires": {} - }, "@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true }, - "@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true, - "peer": true - }, "@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -11237,14 +8534,6 @@ "@types/d3-selection": "*" } }, - "@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "requires": { - "@types/ms": "*" - } - }, "@types/emscripten": { "version": "1.41.5", "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.41.5.tgz", @@ -11252,23 +8541,8 @@ "dev": true }, "@types/estree": { - "version": "1.0.8" - }, - "@types/estree-jsx": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", - "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", - "requires": { - "@types/estree": "*" - } - }, - "@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "requires": { - "@types/unist": "*" - } + "version": "1.0.8", + "dev": true }, "@types/http-cache-semantics": { "version": "4.2.0", @@ -11281,19 +8555,6 @@ "@types/node": "*" } }, - "@types/mdast": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", - "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", - "requires": { - "@types/unist": "*" - } - }, - "@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" - }, "@types/node": { "version": "20.19.33", "dev": true, @@ -11308,10 +8569,12 @@ "dev": true }, "@types/prop-types": { - "version": "15.7.15" + "version": "15.7.15", + "devOptional": true }, "@types/react": { "version": "18.3.28", + "devOptional": true, "requires": { "@types/prop-types": "*", "csstype": "^3.2.2" @@ -11345,11 +8608,6 @@ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", "optional": true }, - "@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==" - }, "@types/yauzl": { "version": "2.10.3", "dev": true, @@ -11358,16 +8616,6 @@ "@types/node": "*" } }, - "@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==" - }, - "@vercel/oidc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", - "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==" - }, "@vitejs/plugin-react": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.4.tgz", @@ -11495,12 +8743,6 @@ "d3-zoom": "^3.0.0" } }, - "abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -11548,27 +8790,6 @@ "indent-string": "^4.0.0" } }, - "ai": { - "version": "6.0.94", - "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.94.tgz", - "integrity": "sha512-/F9wh262HbK05b/5vILh38JvPiheonT+kBj1L97712E7VPchqmcx7aJuZN3QSk5Pj6knxUJLm2FFpYJI1pHXUA==", - "requires": { - "@ai-sdk/gateway": "3.0.52", - "@ai-sdk/provider": "3.0.8", - "@ai-sdk/provider-utils": "4.0.15", - "@opentelemetry/api": "1.9.0" - } - }, - "ai-sdk-provider-claude-code": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/ai-sdk-provider-claude-code/-/ai-sdk-provider-claude-code-3.4.2.tgz", - "integrity": "sha512-Gej+/7PnteCSEmxG1WnIRGBS9wLCI8pu7GmsEHh4z9oFHP+sBwep4koRaGbbLfIXk8SXqvC6vWiWJkFDSwaMvA==", - "requires": { - "@ai-sdk/provider": "^3.0.0", - "@ai-sdk/provider-utils": "^4.0.1", - "@anthropic-ai/claude-agent-sdk": "^0.2.33" - } - }, "ansi-regex": { "version": "5.0.1", "dev": true @@ -11608,16 +8829,6 @@ "tslib": "^2.0.0" } }, - "aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, - "peer": true, - "requires": { - "dequal": "^2.0.3" - } - }, "assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -11650,11 +8861,6 @@ "proxy-from-env": "^1.1.0" } }, - "bail": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", - "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==" - }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -11833,11 +9039,6 @@ "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", "dev": true }, - "ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==" - }, "chai": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", @@ -11870,26 +9071,6 @@ } } }, - "character-entities": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", - "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==" - }, - "character-entities-html4": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", - "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==" - }, - "character-entities-legacy": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", - "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==" - }, - "character-reference-invalid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", - "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==" - }, "check-error": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", @@ -11990,11 +9171,6 @@ "delayed-stream": "~1.0.0" } }, - "comma-separated-tokens": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", - "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==" - }, "commander": { "version": "4.1.1", "dev": true @@ -12058,17 +9234,9 @@ "which": "^2.0.1" } }, - "cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dev": true, - "requires": { - "rrweb-cssom": "^0.6.0" - } - }, "csstype": { - "version": "3.2.3" + "version": "3.2.3", + "devOptional": true }, "d3-color": { "version": "3.1.0", @@ -12136,37 +9304,13 @@ "d3-transition": "2 - 3" } }, - "data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" - } - }, "debug": { "version": "4.4.3", + "dev": true, "requires": { "ms": "^2.1.3" } }, - "decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "dev": true - }, - "decode-named-character-reference": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", - "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", - "requires": { - "character-entities": "^2.0.0" - } - }, "decompress-response": { "version": "6.0.0", "dev": true, @@ -12232,11 +9376,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, - "dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==" - }, "detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -12253,36 +9392,12 @@ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==" }, - "devlop": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", - "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", - "requires": { - "dequal": "^2.0.0" - } - }, "diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true }, - "dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "peer": true - }, - "domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "requires": { - "webidl-conversions": "^7.0.0" - } - }, "dompurify": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", @@ -12422,12 +9537,6 @@ "tapable": "^2.3.0" } }, - "entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true - }, "env-paths": { "version": "2.2.1", "dev": true @@ -12686,27 +9795,12 @@ "dev": true, "optional": true }, - "estree-util-is-identifier-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", - "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==" - }, - "eventsource-parser": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", - "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==" - }, "exponential-backoff": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "dev": true }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" - }, "extract-zip": { "version": "2.0.1", "dev": true, @@ -12971,53 +10065,9 @@ "version": "2.0.2", "dev": true, "requires": { - "function-bind": "^1.1.2" - } - }, - "hast-util-to-jsx-runtime": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", - "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", - "requires": { - "@types/estree": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/unist": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "devlop": "^1.0.0", - "estree-util-is-identifier-name": "^3.0.0", - "hast-util-whitespace": "^3.0.0", - "mdast-util-mdx-expression": "^2.0.0", - "mdast-util-mdx-jsx": "^3.0.0", - "mdast-util-mdxjs-esm": "^2.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0", - "style-to-js": "^1.0.0", - "unist-util-position": "^5.0.0", - "vfile-message": "^4.0.0" - } - }, - "hast-util-whitespace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", - "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", - "requires": { - "@types/hast": "^3.0.0" - } - }, - "html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "requires": { - "whatwg-encoding": "^2.0.0" + "function-bind": "^1.1.2" } }, - "html-url-attributes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", - "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==" - }, "http-cache-semantics": { "version": "4.2.0", "dev": true @@ -13065,6 +10115,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -13109,45 +10160,16 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "inline-style-parser": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", - "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==" - }, "ip-address": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true }, - "is-alphabetical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", - "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==" - }, - "is-alphanumerical": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", - "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", - "requires": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - } - }, - "is-decimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", - "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==" - }, "is-fullwidth-code-point": { "version": "3.0.0", "dev": true }, - "is-hexadecimal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", - "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==" - }, "is-interactive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", @@ -13160,17 +10182,6 @@ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", "dev": true }, - "is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==" - }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -13205,37 +10216,6 @@ "js-tokens": { "version": "4.0.0" }, - "jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", - "dev": true, - "requires": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", - "decimal.js": "^10.4.3", - "domexception": "^4.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" - } - }, "jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -13246,11 +10226,6 @@ "version": "3.0.1", "dev": true }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" - }, "json-stringify-safe": { "version": "5.0.1", "dev": true, @@ -13389,638 +10364,122 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", - "dev": true - }, - "lodash": { - "version": "4.17.23", - "dev": true - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "longest-streak": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", - "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==" - }, - "loose-envify": { - "version": "1.4.0", - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "requires": { - "get-func-name": "^2.0.1" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "dev": true - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "lucide-react": { - "version": "0.563.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.563.0.tgz", - "integrity": "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==", - "requires": {} - }, - "lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "peer": true - }, - "lzma-native": { - "version": "8.0.6", - "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-8.0.6.tgz", - "integrity": "sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==", - "dev": true, - "requires": { - "node-addon-api": "^3.1.0", - "node-gyp-build": "^4.2.1", - "readable-stream": "^3.6.0" - } - }, - "magic-string": { - "version": "0.30.21", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - } - } - }, - "markdown-table": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", - "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==" - }, - "marked": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==" - }, - "matcher": { - "version": "3.0.0", - "dev": true, - "optional": true, - "requires": { - "escape-string-regexp": "^4.0.0" - } - }, - "math-intrinsics": { - "version": "1.1.0", - "dev": true - }, - "mdast-util-find-and-replace": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", - "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", - "requires": { - "@types/mdast": "^4.0.0", - "escape-string-regexp": "^5.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==" - } - } - }, - "mdast-util-from-markdown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", - "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", - "requires": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark": "^4.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unist-util-stringify-position": "^4.0.0" - } - }, - "mdast-util-gfm": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", - "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", - "requires": { - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-gfm-autolink-literal": "^2.0.0", - "mdast-util-gfm-footnote": "^2.0.0", - "mdast-util-gfm-strikethrough": "^2.0.0", - "mdast-util-gfm-table": "^2.0.0", - "mdast-util-gfm-task-list-item": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - } - }, - "mdast-util-gfm-autolink-literal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", - "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", - "requires": { - "@types/mdast": "^4.0.0", - "ccount": "^2.0.0", - "devlop": "^1.0.0", - "mdast-util-find-and-replace": "^3.0.0", - "micromark-util-character": "^2.0.0" - } - }, - "mdast-util-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", - "requires": { - "@types/mdast": "^4.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0" - } - }, - "mdast-util-gfm-strikethrough": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", - "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", - "requires": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - } - }, - "mdast-util-gfm-table": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", - "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", - "requires": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "markdown-table": "^3.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - } - }, - "mdast-util-gfm-task-list-item": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", - "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", - "requires": { - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - } - }, - "mdast-util-mdx-expression": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", - "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - } - }, - "mdast-util-mdx-jsx": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", - "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "ccount": "^2.0.0", - "devlop": "^1.1.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0", - "parse-entities": "^4.0.0", - "stringify-entities": "^4.0.0", - "unist-util-stringify-position": "^4.0.0", - "vfile-message": "^4.0.0" - } - }, - "mdast-util-mdxjs-esm": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", - "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", - "requires": { - "@types/estree-jsx": "^1.0.0", - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-to-markdown": "^2.0.0" - } - }, - "mdast-util-phrasing": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", - "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", - "requires": { - "@types/mdast": "^4.0.0", - "unist-util-is": "^6.0.0" - } - }, - "mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", - "requires": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "@ungap/structured-clone": "^1.0.0", - "devlop": "^1.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "trim-lines": "^3.0.0", - "unist-util-position": "^5.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - } - }, - "mdast-util-to-markdown": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", - "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", - "requires": { - "@types/mdast": "^4.0.0", - "@types/unist": "^3.0.0", - "longest-streak": "^3.0.0", - "mdast-util-phrasing": "^4.0.0", - "mdast-util-to-string": "^4.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-decode-string": "^2.0.0", - "unist-util-visit": "^5.0.0", - "zwitch": "^2.0.0" - } - }, - "mdast-util-to-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", - "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", - "requires": { - "@types/mdast": "^4.0.0" - } - }, - "micromark": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", - "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", - "requires": { - "@types/debug": "^4.0.0", - "debug": "^4.0.0", - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-core-commonmark": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", - "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", - "requires": { - "decode-named-character-reference": "^1.0.0", - "devlop": "^1.0.0", - "micromark-factory-destination": "^2.0.0", - "micromark-factory-label": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-factory-title": "^2.0.0", - "micromark-factory-whitespace": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-html-tag-name": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-subtokenize": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-extension-gfm": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", - "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", - "requires": { - "micromark-extension-gfm-autolink-literal": "^2.0.0", - "micromark-extension-gfm-footnote": "^2.0.0", - "micromark-extension-gfm-strikethrough": "^2.0.0", - "micromark-extension-gfm-table": "^2.0.0", - "micromark-extension-gfm-tagfilter": "^2.0.0", - "micromark-extension-gfm-task-list-item": "^2.0.0", - "micromark-util-combine-extensions": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-extension-gfm-autolink-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", - "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", - "requires": { - "micromark-util-character": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-extension-gfm-footnote": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", - "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", - "requires": { - "devlop": "^1.0.0", - "micromark-core-commonmark": "^2.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-normalize-identifier": "^2.0.0", - "micromark-util-sanitize-uri": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-extension-gfm-strikethrough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", - "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", - "requires": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-classify-character": "^2.0.0", - "micromark-util-resolve-all": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-extension-gfm-table": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", - "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", - "requires": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-extension-gfm-tagfilter": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", - "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", - "requires": { - "micromark-util-types": "^2.0.0" - } - }, - "micromark-extension-gfm-task-list-item": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", - "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", - "requires": { - "devlop": "^1.0.0", - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-factory-destination": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", - "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", - "requires": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-factory-label": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", - "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", - "requires": { - "devlop": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-factory-space": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", - "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", - "requires": { - "micromark-util-character": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-factory-title": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", - "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", - "requires": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-factory-whitespace": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", - "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", - "requires": { - "micromark-factory-space": "^2.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "micromark-util-character": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", - "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", - "requires": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } + "dev": true }, - "micromark-util-chunked": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", - "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", - "requires": { - "micromark-util-symbol": "^2.0.0" - } + "lodash": { + "version": "4.17.23", + "dev": true }, - "micromark-util-classify-character": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", - "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, "requires": { - "micromark-util-character": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" } }, - "micromark-util-combine-extensions": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", - "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "loose-envify": { + "version": "1.4.0", "requires": { - "micromark-util-chunked": "^2.0.0", - "micromark-util-types": "^2.0.0" + "js-tokens": "^3.0.0 || ^4.0.0" } }, - "micromark-util-decode-numeric-character-reference": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", - "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, "requires": { - "micromark-util-symbol": "^2.0.0" + "get-func-name": "^2.0.1" } }, - "micromark-util-decode-string": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", - "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "lowercase-keys": { + "version": "2.0.0", + "dev": true + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "requires": { - "decode-named-character-reference": "^1.0.0", - "micromark-util-character": "^2.0.0", - "micromark-util-decode-numeric-character-reference": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "yallist": "^3.0.2" } }, - "micromark-util-encode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", - "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==" - }, - "micromark-util-html-tag-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", - "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==" + "lucide-react": { + "version": "0.563.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.563.0.tgz", + "integrity": "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA==", + "requires": {} }, - "micromark-util-normalize-identifier": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", - "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "lzma-native": { + "version": "8.0.6", + "resolved": "https://registry.npmjs.org/lzma-native/-/lzma-native-8.0.6.tgz", + "integrity": "sha512-09xfg67mkL2Lz20PrrDeNYZxzeW7ADtpYFbwSQh9U8+76RIzx5QsJBMy8qikv3hbUPfpy6hqwxt6FcGK81g9AA==", + "dev": true, "requires": { - "micromark-util-symbol": "^2.0.0" + "node-addon-api": "^3.1.0", + "node-gyp-build": "^4.2.1", + "readable-stream": "^3.6.0" } }, - "micromark-util-resolve-all": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", - "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "magic-string": { + "version": "0.30.21", + "dev": true, "requires": { - "micromark-util-types": "^2.0.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "micromark-util-sanitize-uri": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", - "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, "requires": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + } } }, - "micromark-util-subtokenize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", - "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==" + }, + "matcher": { + "version": "3.0.0", + "dev": true, + "optional": true, "requires": { - "devlop": "^1.0.0", - "micromark-util-chunked": "^2.0.0", - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" + "escape-string-regexp": "^4.0.0" } }, - "micromark-util-symbol": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", - "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==" - }, - "micromark-util-types": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", - "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==" + "math-intrinsics": { + "version": "1.1.0", + "dev": true }, "mime-db": { "version": "1.52.0", @@ -14187,7 +10646,8 @@ "integrity": "sha512-G3kc34H2cX2gI63RqU+cZq+zWRRPSsNIOjpdl9TN4AQwC4sgwYPl/Q/Obf/d53nOm569T0fYK+tcoSV50BWx8A==" }, "ms": { - "version": "2.1.3" + "version": "2.1.3", + "dev": true }, "mz": { "version": "2.7.0", @@ -14335,12 +10795,6 @@ "set-blocking": "^2.0.0" } }, - "nwsapi": { - "version": "2.2.23", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", - "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "dev": true @@ -14405,36 +10859,6 @@ "aggregate-error": "^3.0.0" } }, - "parse-entities": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", - "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", - "requires": { - "@types/unist": "^2.0.0", - "character-entities-legacy": "^3.0.0", - "character-reference-invalid": "^2.0.0", - "decode-named-character-reference": "^1.0.0", - "is-alphanumerical": "^2.0.0", - "is-decimal": "^2.0.0", - "is-hexadecimal": "^2.0.0" - }, - "dependencies": { - "@types/unist": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", - "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==" - } - } - }, - "parse5": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", - "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", - "dev": true, - "requires": { - "entities": "^6.0.0" - } - }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -14543,24 +10967,10 @@ "retry": "^0.12.0" } }, - "property-information": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", - "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==" - }, "proxy-from-env": { "version": "1.1.0", "dev": true }, - "psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", - "dev": true, - "requires": { - "punycode": "^2.3.1" - } - }, "pump": { "version": "3.0.3", "dev": true, @@ -14569,18 +10979,6 @@ "once": "^1.3.1" } }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true - }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "quick-lru": { "version": "5.1.1", "dev": true @@ -14604,24 +11002,6 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, - "react-markdown": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", - "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", - "requires": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "devlop": "^1.0.0", - "hast-util-to-jsx-runtime": "^2.0.0", - "html-url-attributes": "^3.0.0", - "mdast-util-to-hast": "^13.0.0", - "remark-parse": "^11.0.0", - "remark-rehype": "^11.0.0", - "unified": "^11.0.0", - "unist-util-visit": "^5.0.0", - "vfile": "^6.0.0" - } - }, "react-refresh": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", @@ -14695,62 +11075,10 @@ "readdirp": { "version": "4.1.2" }, - "remark-gfm": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", - "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", - "requires": { - "@types/mdast": "^4.0.0", - "mdast-util-gfm": "^3.0.0", - "micromark-extension-gfm": "^3.0.0", - "remark-parse": "^11.0.0", - "remark-stringify": "^11.0.0", - "unified": "^11.0.0" - } - }, - "remark-parse": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", - "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", - "requires": { - "@types/mdast": "^4.0.0", - "mdast-util-from-markdown": "^2.0.0", - "micromark-util-types": "^2.0.0", - "unified": "^11.0.0" - } - }, - "remark-rehype": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", - "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", - "requires": { - "@types/hast": "^3.0.0", - "@types/mdast": "^4.0.0", - "mdast-util-to-hast": "^13.0.0", - "unified": "^11.0.0", - "vfile": "^6.0.0" - } - }, - "remark-stringify": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", - "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", - "requires": { - "@types/mdast": "^4.0.0", - "mdast-util-to-markdown": "^2.0.0", - "unified": "^11.0.0" - } - }, "require-directory": { "version": "2.1.1", "dev": true }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, "resolve-alpn": { "version": "1.2.1", "dev": true @@ -15007,12 +11335,6 @@ } } }, - "rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", - "dev": true - }, "rxjs": { "version": "7.8.2", "dev": true, @@ -15030,16 +11352,8 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } + "optional": true }, "scheduler": { "version": "0.23.2", @@ -15137,11 +11451,6 @@ "version": "1.2.1", "dev": true }, - "space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==" - }, "sprintf-js": { "version": "1.1.3", "dev": true, @@ -15191,15 +11500,6 @@ "strip-ansi": "^6.0.1" } }, - "stringify-entities": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", - "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", - "requires": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - } - }, "strip-ansi": { "version": "6.0.1", "dev": true, @@ -15216,22 +11516,6 @@ "acorn": "^8.10.0" } }, - "style-to-js": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", - "integrity": "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==", - "requires": { - "style-to-object": "1.0.14" - } - }, - "style-to-object": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz", - "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==", - "requires": { - "inline-style-parser": "0.2.7" - } - }, "sucrase": { "version": "3.35.1", "dev": true, @@ -15259,12 +11543,6 @@ "has-flag": "^4.0.0" } }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, "tailwind-merge": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", @@ -15354,49 +11632,10 @@ "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", "dev": true }, - "tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "dependencies": { - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true - } - } - }, - "tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "requires": { - "punycode": "^2.3.0" - } - }, "tree-kill": { "version": "1.2.2", "dev": true }, - "trim-lines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", - "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==" - }, - "trough": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", - "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==" - }, "ts-interface-checker": { "version": "0.1.13", "dev": true @@ -15450,20 +11689,6 @@ "version": "6.21.0", "dev": true }, - "unified": { - "version": "11.0.5", - "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", - "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", - "requires": { - "@types/unist": "^3.0.0", - "bail": "^2.0.0", - "devlop": "^1.0.0", - "extend": "^3.0.0", - "is-plain-obj": "^4.0.0", - "trough": "^2.0.0", - "vfile": "^6.0.0" - } - }, "unique-filename": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", @@ -15482,49 +11707,6 @@ "imurmurhash": "^0.1.4" } }, - "unist-util-is": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", - "requires": { - "@types/unist": "^3.0.0" - } - }, - "unist-util-position": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", - "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", - "requires": { - "@types/unist": "^3.0.0" - } - }, - "unist-util-stringify-position": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", - "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", - "requires": { - "@types/unist": "^3.0.0" - } - }, - "unist-util-visit": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", - "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", - "requires": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - } - }, - "unist-util-visit-parents": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", - "requires": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - } - }, "universalify": { "version": "0.1.2", "dev": true @@ -15539,16 +11721,6 @@ "picocolors": "^1.1.1" } }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "use-callback-ref": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", @@ -15583,24 +11755,6 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, - "vfile": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", - "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", - "requires": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - } - }, - "vfile-message": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", - "requires": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - } - }, "vite": { "version": "4.5.14", "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.14.tgz", @@ -15723,15 +11877,6 @@ } } }, - "w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "requires": { - "xml-name-validator": "^4.0.0" - } - }, "wait-on": { "version": "7.2.0", "dev": true, @@ -15752,37 +11897,6 @@ "defaults": "^1.0.3" } }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true - }, - "whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "requires": { - "iconv-lite": "0.6.3" - } - }, - "whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true - }, - "whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", - "dev": true, - "requires": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - } - }, "which": { "version": "2.0.2", "dev": true, @@ -15822,25 +11936,6 @@ "version": "1.0.2", "dev": true }, - "ws": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", - "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", - "dev": true, - "requires": {} - }, - "xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, "y18n": { "version": "5.0.8", "dev": true @@ -15887,22 +11982,11 @@ "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", "dev": true }, - "zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "peer": true - }, "zustand": { "version": "5.0.11", "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.11.tgz", "integrity": "sha512-fdZY+dk7zn/vbWNCYmzZULHRrss0jx5pPFiOuMZ/5HJN6Yv3u+1Wswy/4MpZEkEGhtNH+pwxZB8OKgUBPzYAGg==", "requires": {} - }, - "zwitch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", - "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==" } } } diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 4bfb859fa..89998e802 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -16,16 +16,12 @@ "rebuild:native": "electron-rebuild -f -w node-pty" }, "dependencies": { - "@anthropic-ai/claude-agent-sdk": "^0.2.49", - "@openai/codex-sdk": "^0.104.0", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", "@radix-ui/react-tabs": "^1.1.13", "@xterm/addon-fit": "^0.11.0", "@xterm/xterm": "^6.0.0", "@xyflow/react": "^12.5.0", - "ai": "^6.0.94", - "ai-sdk-provider-claude-code": "^3.4.2", "chokidar": "^4.0.3", "clsx": "^2.1.1", "lucide-react": "^0.563.0", @@ -35,10 +31,8 @@ "node-pty": "^1.1.0", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-markdown": "^10.1.0", "react-resizable-panels": "^4.6.2", "react-router-dom": "^7.13.0", - "remark-gfm": "^4.0.1", "sql.js": "^1.13.0", "tailwind-merge": "^3.4.0", "yaml": "^2.8.2", @@ -46,8 +40,6 @@ }, "devDependencies": { "@tailwindcss/postcss": "^4.1.18", - "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", "@types/node": "^20.11.30", "@types/node-cron": "^3.0.11", "@types/react": "^18.2.74", @@ -59,7 +51,6 @@ "cross-env": "^7.0.3", "electron": "^40.2.1", "electron-rebuild": "^3.2.9", - "jsdom": "^22.1.0", "postcss": "^8.5.6", "tailwindcss": "^4.1.18", "tsup": "^8.3.5", diff --git a/apps/desktop/src/main/main.ts b/apps/desktop/src/main/main.ts index cbf575fcb..67ee8545e 100644 --- a/apps/desktop/src/main/main.ts +++ b/apps/desktop/src/main/main.ts @@ -21,8 +21,6 @@ import { createPackService } from "./services/packs/packService"; import { createJobEngine } from "./services/jobs/jobEngine"; import { createHostedAgentService } from "./services/hosted/hostedAgentService"; import { createByokLlmService } from "./services/byok/byokLlmService"; -import { createAiIntegrationService } from "./services/ai/aiIntegrationService"; -import { createAgentChatService } from "./services/chat/agentChatService"; import { createGithubService } from "./services/github/githubService"; import { createPrService } from "./services/prs/prService"; import { createPrPollingService } from "./services/prs/prPollingService"; @@ -254,12 +252,6 @@ app.whenReady().then(async () => { logger }); - const aiIntegrationService = createAiIntegrationService({ - db, - logger, - projectConfigService - }); - const ciService = createCiService({ db, logger, @@ -383,7 +375,6 @@ app.whenReady().then(async () => { hostedAgentService, byokLlmService, projectConfigService, - conflictService, openExternal: async (url) => { await shell.openExternal(url); } @@ -404,19 +395,6 @@ app.whenReady().then(async () => { }); let orchestratorServiceRef: ReturnType | null = null; - const onTrackedSessionEnded = ({ laneId, sessionId, exitCode }: { laneId: string; sessionId: string; exitCode: number | null }) => { - jobEngine?.onSessionEnded({ laneId, sessionId }); - automationService?.onSessionEnded({ laneId, sessionId }); - if (orchestratorServiceRef) { - void orchestratorServiceRef - .onTrackedSessionEnded({ - laneId, - sessionId, - exitCode - }) - .catch(() => {}); - } - }; const ptyService = createPtyService({ projectRoot, @@ -427,23 +405,22 @@ app.whenReady().then(async () => { logger, broadcastData: (ev) => broadcast(IPC.ptyData, ev), broadcastExit: (ev) => broadcast(IPC.ptyExit, ev), - onSessionEnded: onTrackedSessionEnded, + onSessionEnded: ({ laneId, sessionId, exitCode }) => { + jobEngine.onSessionEnded({ laneId, sessionId }); + automationService?.onSessionEnded({ laneId, sessionId }); + if (orchestratorServiceRef) { + void orchestratorServiceRef + .onTrackedSessionEnded({ + laneId, + sessionId, + exitCode + }) + .catch(() => {}); + } + }, loadPty }); - const agentChatService = createAgentChatService({ - projectRoot, - adeDir: adePaths.adeDir, - transcriptsDir: adePaths.transcriptsDir, - laneService, - sessionService, - projectConfigService, - logger, - appVersion: app.getVersion(), - onEvent: (event) => broadcast(IPC.agentChatEvent, event), - onSessionEnded: onTrackedSessionEnded - }); - const gitService = createGitOperationsService({ laneService, operationService, @@ -619,7 +596,6 @@ app.whenReady().then(async () => { operationService, gitService, conflictService, - aiIntegrationService, hostedAgentService, byokLlmService, githubService, @@ -631,7 +607,6 @@ app.whenReady().then(async () => { missionService, orchestratorService, ciService, - agentChatService, packService, projectConfigService, processService, @@ -680,11 +655,6 @@ app.whenReady().then(async () => { } catch { // ignore } - try { - void ctxRef.agentChatService.disposeAll(); - } catch { - // ignore - } try { ctxRef.db.flushNow(); ctxRef.db.close(); diff --git a/apps/desktop/src/main/services/ai/agentExecutor.ts b/apps/desktop/src/main/services/ai/agentExecutor.ts deleted file mode 100644 index c2712b5f7..000000000 --- a/apps/desktop/src/main/services/ai/agentExecutor.ts +++ /dev/null @@ -1,77 +0,0 @@ -export type AgentProvider = "claude" | "codex"; - -export type AgentPermissionMode = "read-only" | "edit" | "full-auto"; - -export type AgentSandboxLevel = "strict" | "workspace" | "unrestricted"; - -export type AgentToolInvocation = { - name: string; - args: unknown; -}; - -export type ClaudeProviderOverrides = { - permissionMode?: "default" | "acceptEdits" | "bypassPermissions" | "plan"; - settingSources?: Array<"user" | "project" | "local">; - hooks?: Record; - sandbox?: boolean; - maxBudgetUsd?: number; -}; - -export type CodexProviderOverrides = { - approvalMode?: "untrusted" | "on-request" | "on-failure" | "never"; - sandboxPermissions?: "read-only" | "workspace-write" | "danger-full-access"; - writablePaths?: string[]; - commandAllowlist?: string[]; -}; - -export type ExecutorOpts = { - cwd: string; - contextPack?: unknown; - systemPrompt?: string; - jsonSchema?: unknown; - model?: string; - timeoutMs: number; - maxBudgetUsd?: number; - oneShot?: boolean; - permissions: { - mode: AgentPermissionMode; - allowedTools?: string[]; - disallowedTools?: string[]; - canUseTool?: (invocation: AgentToolInvocation) => boolean | Promise; - sandboxLevel?: AgentSandboxLevel; - }; - providerConfig?: { - claude?: ClaudeProviderOverrides; - codex?: CodexProviderOverrides; - }; -}; - -export type AgentEvent = - | { type: "text"; content: string } - | { type: "tool_call"; name: string; args: unknown } - | { type: "tool_result"; name: string; result: unknown } - | { type: "structured_output"; data: unknown } - | { type: "error"; message: string } - | { - type: "done"; - sessionId: string; - usage?: { - inputTokens?: number | null; - outputTokens?: number | null; - }; - model?: string | null; - provider?: AgentProvider; - }; - -export type AgentModelDescriptor = { - id: string; - label: string; - description?: string; -}; - -export interface AgentExecutor { - readonly provider: AgentProvider; - execute(prompt: string, opts: ExecutorOpts): AsyncIterable; - resume(sessionId: string, prompt?: string, opts?: Omit): AsyncIterable; - listModels?(): Promise; -} diff --git a/apps/desktop/src/main/services/ai/aiIntegrationService.ts b/apps/desktop/src/main/services/ai/aiIntegrationService.ts deleted file mode 100644 index e78612a6f..000000000 --- a/apps/desktop/src/main/services/ai/aiIntegrationService.ts +++ /dev/null @@ -1,700 +0,0 @@ -import { randomUUID } from "node:crypto"; -import type { Logger } from "../logging/logger"; -import type { AdeDb } from "../state/kvDb"; -import type { createProjectConfigService } from "../config/projectConfigService"; -import type { AgentModelDescriptor, AgentProvider, ExecutorOpts } from "./agentExecutor"; -import { createClaudeExecutor } from "./claudeExecutor"; -import { createCodexExecutor } from "./codexExecutor"; -import { commandExists } from "./utils"; - -export type AiTaskType = - | "planning" - | "implementation" - | "review" - | "conflict_resolution" - | "narrative" - | "pr_description" - | "terminal_summary" - | "mission_planning" - | "initial_context"; - -export type AiFeatureKey = - | "narratives" - | "conflict_proposals" - | "pr_descriptions" - | "terminal_summaries" - | "mission_planning" - | "orchestrator" - | "initial_context"; - -export type AiProviderMode = "guest" | "subscription"; - -export type AiIntegrationStatus = { - mode: AiProviderMode; - availableProviders: { - claude: boolean; - codex: boolean; - }; - models: { - claude: AgentModelDescriptor[]; - codex: AgentModelDescriptor[]; - }; -}; - -export type ExecuteAiTaskArgs = { - feature: AiFeatureKey; - taskType: AiTaskType; - prompt: string; - cwd: string; - jsonSchema?: unknown; - systemPrompt?: string; - timeoutMs?: number; - model?: string; - permissionMode?: ExecutorOpts["permissions"]["mode"]; - oneShot?: boolean; -}; - -export type ExecuteAiTaskResult = { - text: string; - structuredOutput: unknown; - provider: AgentProvider; - model: string | null; - sessionId: string | null; - inputTokens: number | null; - outputTokens: number | null; - durationMs: number; -}; - -type RuntimeTaskDefaults = { - provider: AgentProvider; - model: string; - timeoutMs: number; - permissionMode: ExecutorOpts["permissions"]["mode"]; -}; - -const TASK_DEFAULTS: Record = { - planning: { - provider: "claude", - model: "sonnet", - timeoutMs: 45_000, - permissionMode: "read-only" - }, - implementation: { - provider: "codex", - model: "gpt-5.3-codex", - timeoutMs: 120_000, - permissionMode: "edit" - }, - review: { - provider: "claude", - model: "sonnet", - timeoutMs: 30_000, - permissionMode: "read-only" - }, - conflict_resolution: { - provider: "claude", - model: "sonnet", - timeoutMs: 60_000, - permissionMode: "read-only" - }, - narrative: { - provider: "claude", - model: "haiku", - timeoutMs: 15_000, - permissionMode: "read-only" - }, - pr_description: { - provider: "claude", - model: "haiku", - timeoutMs: 15_000, - permissionMode: "read-only" - }, - terminal_summary: { - provider: "claude", - model: "haiku", - timeoutMs: 10_000, - permissionMode: "read-only" - }, - mission_planning: { - provider: "claude", - model: "sonnet", - timeoutMs: 45_000, - permissionMode: "read-only" - }, - initial_context: { - provider: "claude", - model: "sonnet", - timeoutMs: 45_000, - permissionMode: "read-only" - } -}; - -const CODEX_FALLBACK_MODELS: AgentModelDescriptor[] = [ - { id: "gpt-5.3-codex", label: "gpt-5.3-codex" }, - { id: "gpt-5.2-codex", label: "gpt-5.2-codex" }, - { id: "gpt-5.1-codex-max", label: "gpt-5.1-codex-max" }, - { id: "codex-mini-latest", label: "codex-mini-latest" }, - { id: "o4-mini", label: "o4-mini" }, - { id: "o3", label: "o3" } -]; - -type ClaudeProviderConfig = NonNullable["claude"]>; - -function isRecord(value: unknown): value is Record { - return !!value && typeof value === "object" && !Array.isArray(value); -} - -function toStringOrNull(value: unknown): string | null { - const text = typeof value === "string" ? value.trim() : ""; - return text.length ? text : null; -} - -function toNumberOrNull(value: unknown): number | null { - const num = Number(value); - return Number.isFinite(num) ? num : null; -} - -function startOfDayIso(now = new Date()): string { - const utc = Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate(), 0, 0, 0, 0); - return new Date(utc).toISOString(); -} - -function extractTaskRouting(snapshot: ReturnType["get"]>): Record { - if (isRecord(snapshot.effective.ai) && isRecord(snapshot.effective.ai.taskRouting)) { - return snapshot.effective.ai.taskRouting; - } - - // Backward compatibility for older config shape. - const providers = isRecord(snapshot.effective.providers) ? snapshot.effective.providers : {}; - const legacyAi = isRecord(providers.ai) ? providers.ai : {}; - if (isRecord(legacyAi.taskRouting)) { - return legacyAi.taskRouting; - } - - return {}; -} - -function extractAiConfig(snapshot: ReturnType["get"]>): Record { - if (isRecord(snapshot.effective.ai)) return snapshot.effective.ai; - const providers = isRecord(snapshot.effective.providers) ? snapshot.effective.providers : {}; - const legacyAi = isRecord(providers.ai) ? providers.ai : {}; - return legacyAi; -} - -function extractTaskOverride(snapshot: ReturnType["get"]>, taskType: AiTaskType): Record { - const routing = extractTaskRouting(snapshot); - return isRecord(routing[taskType]) ? (routing[taskType] as Record) : {}; -} - -function mapClaudePermission(mode: string | null): ExecutorOpts["permissions"]["mode"] { - if (mode === "acceptEdits") return "edit"; - if (mode === "bypassPermissions") return "full-auto"; - return "read-only"; -} - -function mapCodexPermission(args: { - sandboxPermissions: string | null; - approvalMode: string | null; -}): ExecutorOpts["permissions"]["mode"] { - if (args.sandboxPermissions === "danger-full-access" || args.approvalMode === "never") return "full-auto"; - if (args.sandboxPermissions === "workspace-write" || args.approvalMode === "on-request" || args.approvalMode === "on-failure") { - return "edit"; - } - return "read-only"; -} - -export function createAiIntegrationService(args: { - db: AdeDb; - logger: Logger; - projectConfigService: ReturnType; -}) { - const { db, logger, projectConfigService } = args; - - const executors = { - claude: createClaudeExecutor(), - codex: createCodexExecutor() - }; - - const getAvailability = () => ({ - claude: commandExists("claude"), - codex: commandExists("codex") - }); - - const getMode = (): AiProviderMode => { - const availability = getAvailability(); - return availability.claude || availability.codex ? "subscription" : "guest"; - }; - - const getFeatureFlag = (feature: AiFeatureKey): boolean => { - const snapshot = projectConfigService.get(); - const aiConfig = extractAiConfig(snapshot); - const features = isRecord(aiConfig.features) ? aiConfig.features : {}; - const value = features[feature]; - return value == null ? true : Boolean(value); - }; - - const getDailyBudgetLimit = (feature: AiFeatureKey): number | null => { - const snapshot = projectConfigService.get(); - const aiConfig = extractAiConfig(snapshot); - const budgets = isRecord(aiConfig.budgets) ? aiConfig.budgets : {}; - const entry = isRecord(budgets[feature]) ? (budgets[feature] as Record) : {}; - - const daily = toNumberOrNull(entry.dailyLimit) ?? toNumberOrNull(entry.daily_limit); - if (daily == null || daily <= 0) return null; - return daily; - }; - - const countDailyUsage = (feature: AiFeatureKey): number => { - const row = db.get<{ count: number }>( - ` - select count(*) as count - from ai_usage_log - where feature = ? - and timestamp >= ? - and success = 1 - `, - [feature, startOfDayIso()] - ); - - return Number(row?.count ?? 0); - }; - - const checkBudget = (feature: AiFeatureKey): void => { - const limit = getDailyBudgetLimit(feature); - if (limit == null) return; - - const used = countDailyUsage(feature); - if (used >= limit) { - throw new Error(`Daily AI budget reached for '${feature}' (${used}/${limit}).`); - } - }; - - const logUsage = (args: { - feature: AiFeatureKey; - provider: AgentProvider; - model: string | null; - inputTokens: number | null; - outputTokens: number | null; - durationMs: number; - success: boolean; - sessionId: string | null; - }) => { - db.run( - ` - insert into ai_usage_log( - id, - timestamp, - feature, - provider, - model, - input_tokens, - output_tokens, - duration_ms, - success, - session_id - ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - `, - [ - randomUUID(), - new Date().toISOString(), - args.feature, - args.provider, - args.model, - args.inputTokens, - args.outputTokens, - Math.max(0, Math.floor(args.durationMs)), - args.success ? 1 : 0, - args.sessionId - ] - ); - }; - - const resolveProviderForTask = (taskType: AiTaskType, modelOverride?: string | null): AgentProvider => { - const snapshot = projectConfigService.get(); - const defaults = TASK_DEFAULTS[taskType]; - const override = extractTaskOverride(snapshot, taskType); - - const preferred = toStringOrNull(override.provider) ?? toStringOrNull(modelOverride); - const normalizedPreferred = preferred?.toLowerCase() ?? ""; - - const availability = getAvailability(); - - const preferredProvider = - normalizedPreferred === "claude" || normalizedPreferred === "codex" - ? (normalizedPreferred as AgentProvider) - : defaults.provider; - - if (preferredProvider === "claude" && availability.claude) return "claude"; - if (preferredProvider === "codex" && availability.codex) return "codex"; - if (availability.claude) return "claude"; - if (availability.codex) return "codex"; - - throw new Error("No compatible AI CLI provider detected. Install and authenticate Claude Code and/or Codex."); - }; - - const buildExecutorOpts = (args: { - taskType: AiTaskType; - provider: AgentProvider; - cwd: string; - model?: string; - timeoutMs?: number; - systemPrompt?: string; - jsonSchema?: unknown; - permissionMode?: ExecutorOpts["permissions"]["mode"]; - oneShot?: boolean; - }): ExecutorOpts => { - const snapshot = projectConfigService.get(); - const defaults = TASK_DEFAULTS[args.taskType]; - const taskOverride = extractTaskOverride(snapshot, args.taskType); - const aiConfig = extractAiConfig(snapshot); - - const model = - toStringOrNull(args.model) ?? - toStringOrNull(taskOverride.model) ?? - defaults.model; - - const timeoutMs = - toNumberOrNull(args.timeoutMs) ?? - toNumberOrNull(taskOverride.timeoutMs) ?? - toNumberOrNull(taskOverride.timeout_ms) ?? - defaults.timeoutMs; - - const permissions = isRecord(aiConfig.permissions) ? (aiConfig.permissions as Record) : {}; - const claudePermissions = isRecord(permissions.claude) ? (permissions.claude as Record) : {}; - const codexPermissions = isRecord(permissions.codex) ? (permissions.codex as Record) : {}; - - const permissionMode = (() => { - if (args.permissionMode) return args.permissionMode; - if (args.provider === "claude") { - return mapClaudePermission(toStringOrNull(claudePermissions.permissionMode) ?? toStringOrNull(claudePermissions.permission_mode)); - } - return mapCodexPermission({ - sandboxPermissions: toStringOrNull(codexPermissions.sandboxPermissions) ?? toStringOrNull(codexPermissions.sandbox_permissions), - approvalMode: toStringOrNull(codexPermissions.approvalMode) ?? toStringOrNull(codexPermissions.approval_mode) - }); - })(); - - return { - cwd: args.cwd, - model, - timeoutMs: Math.max(1_000, Math.floor(timeoutMs)), - systemPrompt: args.systemPrompt, - jsonSchema: args.jsonSchema, - oneShot: args.oneShot, - maxBudgetUsd: toNumberOrNull(claudePermissions.maxBudgetUsd) ?? toNumberOrNull(claudePermissions.max_budget_usd) ?? undefined, - permissions: { - mode: permissionMode, - allowedTools: undefined, - disallowedTools: undefined - }, - providerConfig: { - claude: { - permissionMode: toStringOrNull(claudePermissions.permissionMode) as ClaudeProviderConfig["permissionMode"], - settingSources: Array.isArray(claudePermissions.settingSources) - ? claudePermissions.settingSources.filter((entry): entry is "user" | "project" | "local" => - entry === "user" || entry === "project" || entry === "local" - ) - : Array.isArray(claudePermissions.settings_sources) - ? claudePermissions.settings_sources.filter((entry): entry is "user" | "project" | "local" => - entry === "user" || entry === "project" || entry === "local" - ) - : [], - sandbox: claudePermissions.sandbox === true, - maxBudgetUsd: toNumberOrNull(claudePermissions.maxBudgetUsd) ?? toNumberOrNull(claudePermissions.max_budget_usd) ?? undefined - }, - codex: { - approvalMode: - (toStringOrNull(codexPermissions.approvalMode) ?? toStringOrNull(codexPermissions.approval_mode)) as - | "untrusted" - | "on-request" - | "on-failure" - | "never" - | undefined, - sandboxPermissions: - (toStringOrNull(codexPermissions.sandboxPermissions) ?? toStringOrNull(codexPermissions.sandbox_permissions)) as - | "read-only" - | "workspace-write" - | "danger-full-access" - | undefined, - writablePaths: Array.isArray(codexPermissions.writablePaths) - ? codexPermissions.writablePaths.map((entry) => String(entry)) - : Array.isArray(codexPermissions.writable_paths) - ? codexPermissions.writable_paths.map((entry) => String(entry)) - : [], - commandAllowlist: Array.isArray(codexPermissions.commandAllowlist) - ? codexPermissions.commandAllowlist.map((entry) => String(entry)) - : Array.isArray(codexPermissions.command_allowlist) - ? codexPermissions.command_allowlist.map((entry) => String(entry)) - : [] - } - } - }; - }; - - const executeTask = async (args: ExecuteAiTaskArgs): Promise => { - if (getMode() === "guest") { - throw new Error("No AI provider is available. Install and authenticate Claude Code and/or Codex CLI."); - } - - if (!getFeatureFlag(args.feature)) { - throw new Error(`AI feature '${args.feature}' is disabled in settings.`); - } - - checkBudget(args.feature); - - const provider = resolveProviderForTask(args.taskType, null); - const executor = executors[provider]; - const opts = buildExecutorOpts({ - taskType: args.taskType, - provider, - cwd: args.cwd, - model: args.model, - timeoutMs: args.timeoutMs, - systemPrompt: args.systemPrompt, - jsonSchema: args.jsonSchema, - permissionMode: args.permissionMode, - oneShot: args.oneShot - }); - - const startedAt = Date.now(); - let sessionId: string | null = null; - let resolvedModel: string | null = opts.model ?? null; - let inputTokens: number | null = null; - let outputTokens: number | null = null; - let text = ""; - let structuredOutput: unknown = null; - - try { - for await (const event of executor.execute(args.prompt, opts)) { - if (event.type === "text") { - text += event.content; - continue; - } - if (event.type === "structured_output") { - structuredOutput = event.data; - continue; - } - if (event.type === "error") { - throw new Error(event.message || "AI execution failed."); - } - if (event.type === "done") { - sessionId = event.sessionId; - resolvedModel = event.model ?? resolvedModel; - inputTokens = toNumberOrNull(event.usage?.inputTokens ?? null); - outputTokens = toNumberOrNull(event.usage?.outputTokens ?? null); - } - } - - const durationMs = Date.now() - startedAt; - logUsage({ - feature: args.feature, - provider, - model: resolvedModel, - inputTokens, - outputTokens, - durationMs, - success: true, - sessionId - }); - - return { - text, - structuredOutput, - provider, - model: resolvedModel, - sessionId, - inputTokens, - outputTokens, - durationMs - }; - } catch (error) { - const durationMs = Date.now() - startedAt; - logUsage({ - feature: args.feature, - provider, - model: resolvedModel, - inputTokens, - outputTokens, - durationMs, - success: false, - sessionId - }); - - logger.warn("ai.task.failed", { - taskType: args.taskType, - provider, - feature: args.feature, - durationMs, - error: error instanceof Error ? error.message : String(error) - }); - - throw error; - } - }; - - const listModels = async (provider: AgentProvider): Promise => { - const executor = executors[provider]; - if (!executor.listModels) { - return provider === "codex" ? CODEX_FALLBACK_MODELS : []; - } - - try { - const models = await executor.listModels(); - if (models.length) return models; - } catch { - // fallback below - } - - return provider === "codex" ? CODEX_FALLBACK_MODELS : []; - }; - - return { - getMode, - - getStatus: async (): Promise => { - const availability = getAvailability(); - return { - mode: getMode(), - availableProviders: availability, - models: { - claude: availability.claude ? await listModels("claude") : [], - codex: availability.codex ? await listModels("codex") : CODEX_FALLBACK_MODELS - } - }; - }, - - executeTask, - - listModels, - - getFeatureFlag, - - getDailyUsage(feature: AiFeatureKey): number { - return countDailyUsage(feature); - }, - - getDailyBudgetLimit, - - getAvailability, - - // Backward-compatible convenience methods used by migrated services. - async generateNarrative(args: { - laneId: string; - cwd: string; - prompt: string; - timeoutMs?: number; - model?: string; - }): Promise { - return await executeTask({ - feature: "narratives", - taskType: "narrative", - prompt: args.prompt, - cwd: args.cwd, - timeoutMs: args.timeoutMs, - model: args.model, - permissionMode: "read-only", - oneShot: true - }); - }, - - async requestConflictProposal(args: { - laneId: string; - cwd: string; - prompt: string; - timeoutMs?: number; - model?: string; - jsonSchema?: unknown; - }): Promise { - return await executeTask({ - feature: "conflict_proposals", - taskType: "conflict_resolution", - prompt: args.prompt, - cwd: args.cwd, - timeoutMs: args.timeoutMs, - model: args.model, - jsonSchema: args.jsonSchema, - permissionMode: "read-only", - oneShot: true - }); - }, - - async draftPrDescription(args: { - laneId: string; - cwd: string; - prompt: string; - timeoutMs?: number; - model?: string; - }): Promise { - return await executeTask({ - feature: "pr_descriptions", - taskType: "pr_description", - prompt: args.prompt, - cwd: args.cwd, - timeoutMs: args.timeoutMs, - model: args.model, - permissionMode: "read-only", - oneShot: true - }); - }, - - async summarizeTerminal(args: { - cwd: string; - prompt: string; - timeoutMs?: number; - model?: string; - jsonSchema?: unknown; - }): Promise { - return await executeTask({ - feature: "terminal_summaries", - taskType: "terminal_summary", - prompt: args.prompt, - cwd: args.cwd, - timeoutMs: args.timeoutMs, - model: args.model, - jsonSchema: args.jsonSchema, - permissionMode: "read-only", - oneShot: true - }); - }, - - async planMission(args: { - cwd: string; - prompt: string; - timeoutMs?: number; - model?: string; - jsonSchema?: unknown; - }): Promise { - return await executeTask({ - feature: "mission_planning", - taskType: "mission_planning", - prompt: args.prompt, - cwd: args.cwd, - timeoutMs: args.timeoutMs, - model: args.model, - jsonSchema: args.jsonSchema, - permissionMode: "read-only", - oneShot: true - }); - }, - - async generateInitialContext(args: { - cwd: string; - prompt: string; - timeoutMs?: number; - model?: string; - jsonSchema?: unknown; - }): Promise { - return await executeTask({ - feature: "initial_context", - taskType: "initial_context", - prompt: args.prompt, - cwd: args.cwd, - timeoutMs: args.timeoutMs, - model: args.model, - jsonSchema: args.jsonSchema, - permissionMode: "read-only", - oneShot: true - }); - } - }; -} diff --git a/apps/desktop/src/main/services/ai/claudeExecutor.ts b/apps/desktop/src/main/services/ai/claudeExecutor.ts deleted file mode 100644 index f41c443b5..000000000 --- a/apps/desktop/src/main/services/ai/claudeExecutor.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { randomUUID } from "node:crypto"; -import { generateText } from "ai"; -import { createClaudeCode, type ClaudeCodeSettings } from "ai-sdk-provider-claude-code"; -import { unstable_v2_createSession } from "@anthropic-ai/claude-agent-sdk"; -import type { CanUseTool, ModelInfo, PermissionResult } from "@anthropic-ai/claude-agent-sdk"; -import type { - AgentEvent, - AgentExecutor, - AgentModelDescriptor, - ExecutorOpts -} from "./agentExecutor"; -import { parseStructuredOutput, withTimeout } from "./utils"; - -const CLAUDE_ALIAS_TO_MODEL: Record = { - opus: "claude-opus-4-6", - sonnet: "claude-sonnet-4-6", - haiku: "claude-haiku-4-5-20251001" -}; - -const DEFAULT_CLAUDE_MODELS: AgentModelDescriptor[] = [ - { id: "opus", label: "Opus", description: "Highest reasoning quality" }, - { id: "sonnet", label: "Sonnet", description: "Balanced default" }, - { id: "haiku", label: "Haiku", description: "Fast and low-cost" } -]; - -function resolveClaudeModel(model: string | undefined): string { - const requested = String(model ?? "").trim(); - if (!requested) return "sonnet"; - const alias = requested.toLowerCase(); - return CLAUDE_ALIAS_TO_MODEL[alias] ?? requested; -} - -function mapPermissionMode(mode: ExecutorOpts["permissions"]["mode"]): ClaudeCodeSettings["permissionMode"] { - if (mode === "read-only") return "plan"; - if (mode === "edit") return "acceptEdits"; - return "bypassPermissions"; -} - -function mapCanUseTool(canUseTool: ExecutorOpts["permissions"]["canUseTool"]): CanUseTool | undefined { - if (!canUseTool) return undefined; - - return async (toolName, input): Promise => { - const approved = await canUseTool({ - name: toolName, - args: input - }); - - if (approved) return { behavior: "allow" }; - return { - behavior: "deny", - message: `Tool '${toolName}' blocked by ADE policy.`, - interrupt: false - }; - }; -} - -export function createClaudeExecutor(): AgentExecutor { - const provider = createClaudeCode(); - - const listModels = async (): Promise => { - try { - const session = unstable_v2_createSession({ - model: CLAUDE_ALIAS_TO_MODEL.sonnet, - permissionMode: "plan" - }) as unknown as { - supportedModels?: () => Promise; - close: () => void; - }; - - try { - if (typeof session.supportedModels !== "function") { - return DEFAULT_CLAUDE_MODELS; - } - - const discovered = await session.supportedModels(); - const models = discovered - .map((entry: ModelInfo): AgentModelDescriptor | null => { - const id = String(entry.value ?? "").trim(); - if (!id) return null; - const description = String(entry.description ?? "").trim(); - return { - id, - label: String(entry.displayName ?? entry.value ?? id).trim() || id, - ...(description ? { description } : {}) - }; - }) - .filter((entry): entry is AgentModelDescriptor => entry !== null); - - if (models.length > 0) return models; - } finally { - session.close(); - } - } catch { - // Fallback handled below. - } - - return DEFAULT_CLAUDE_MODELS; - }; - - const execute = (prompt: string, opts: ExecutorOpts): AsyncIterable => { - return { - async *[Symbol.asyncIterator]() { - const sessionId = randomUUID(); - const permissionMode = opts.providerConfig?.claude?.permissionMode ?? mapPermissionMode(opts.permissions.mode); - const sandboxEnabled = opts.providerConfig?.claude?.sandbox; - const mergedSettings: ClaudeCodeSettings = { - cwd: opts.cwd, - permissionMode, - systemPrompt: opts.systemPrompt, - settingSources: opts.providerConfig?.claude?.settingSources ?? [], - allowedTools: opts.permissions.allowedTools, - disallowedTools: opts.permissions.disallowedTools, - canUseTool: mapCanUseTool(opts.permissions.canUseTool), - maxBudgetUsd: opts.providerConfig?.claude?.maxBudgetUsd ?? opts.maxBudgetUsd, - ...(sandboxEnabled != null ? { sandbox: { enabled: sandboxEnabled } } : {}), - hooks: opts.providerConfig?.claude?.hooks as ClaudeCodeSettings["hooks"] - }; - - const modelId = resolveClaudeModel(opts.model); - - try { - const operation = generateText({ - model: provider(modelId as any, mergedSettings), - system: opts.systemPrompt, - prompt - }); - - const result = await withTimeout( - operation, - opts.timeoutMs, - `Claude execution timed out after ${opts.timeoutMs}ms.` - ); - - const text = String(result.text ?? ""); - if (text.trim().length > 0) { - yield { type: "text", content: text } satisfies AgentEvent; - } - - if (opts.jsonSchema) { - const structured = parseStructuredOutput(text); - if (structured != null) { - yield { type: "structured_output", data: structured } satisfies AgentEvent; - } - } - - yield { - type: "done", - sessionId, - provider: "claude", - model: modelId, - usage: { - inputTokens: result.usage?.inputTokens ?? null, - outputTokens: result.usage?.outputTokens ?? null - } - } satisfies AgentEvent; - } catch (error) { - yield { - type: "error", - message: error instanceof Error ? error.message : String(error) - } satisfies AgentEvent; - } - } - }; - }; - - return { - provider: "claude", - execute, - resume(sessionId: string): AsyncIterable { - return { - async *[Symbol.asyncIterator]() { - yield { - type: "error", - message: `Claude session resume is not implemented for session '${sessionId}'.` - } satisfies AgentEvent; - } - }; - }, - listModels - }; -} diff --git a/apps/desktop/src/main/services/ai/codexExecutor.ts b/apps/desktop/src/main/services/ai/codexExecutor.ts deleted file mode 100644 index 286aede19..000000000 --- a/apps/desktop/src/main/services/ai/codexExecutor.ts +++ /dev/null @@ -1,284 +0,0 @@ -import { randomUUID } from "node:crypto"; -import { - Codex, - type ApprovalMode, - type CodexOptions, - type SandboxMode, - type ThreadItem, - type ThreadOptions, - type TurnOptions, - type Usage -} from "@openai/codex-sdk"; -import type { - AgentEvent, - AgentExecutor, - AgentModelDescriptor, - ExecutorOpts -} from "./agentExecutor"; -import { parseStructuredOutput } from "./utils"; - -const DEFAULT_CODEX_MODELS: AgentModelDescriptor[] = [ - { id: "gpt-5.3-codex", label: "gpt-5.3-codex" }, - { id: "gpt-5.2-codex", label: "gpt-5.2-codex" }, - { id: "gpt-5.1-codex-max", label: "gpt-5.1-codex-max" }, - { id: "codex-mini-latest", label: "codex-mini-latest" }, - { id: "o4-mini", label: "o4-mini" }, - { id: "o3", label: "o3" } -]; - -type CodexOverrides = NonNullable["codex"]>; - -function mapSandbox(mode: ExecutorOpts["permissions"]["mode"]): SandboxMode { - if (mode === "read-only") return "read-only"; - if (mode === "edit") return "workspace-write"; - return "danger-full-access"; -} - -function mapApproval(mode: ExecutorOpts["permissions"]["mode"]): ApprovalMode { - if (mode === "read-only") return "untrusted"; - if (mode === "edit") return "on-request"; - return "never"; -} - -function toNumber(value: unknown): number | null { - const numeric = Number(value); - return Number.isFinite(numeric) ? numeric : null; -} - -function toText(value: unknown): string { - return typeof value === "string" ? value : String(value ?? ""); -} - -function mapToolItem(item: ThreadItem): AgentEvent[] { - if (item.type === "command_execution") { - const events: AgentEvent[] = [{ type: "tool_call", name: "command", args: { command: item.command } }]; - if (item.status === "completed" || item.status === "failed") { - events.push({ - type: "tool_result", - name: "command", - result: { - status: item.status, - output: item.aggregated_output, - exitCode: item.exit_code ?? null - } - }); - } - return events; - } - - if (item.type === "mcp_tool_call") { - const events: AgentEvent[] = [{ - type: "tool_call", - name: item.tool, - args: item.arguments - }]; - - if (item.status === "completed" || item.status === "failed") { - events.push({ - type: "tool_result", - name: item.tool, - result: item.status === "completed" ? item.result : item.error - }); - } - - return events; - } - - if (item.type === "file_change") { - return [ - { - type: "tool_result", - name: "file_change", - result: { - status: item.status, - changes: item.changes - } - } - ]; - } - - return []; -} - -function buildCodexConfig(overrides: CodexOverrides | undefined): CodexOptions["config"] { - if (!overrides) return undefined; - - const config: NonNullable = {}; - const writablePaths = (overrides.writablePaths ?? []).map((entry) => String(entry).trim()).filter(Boolean); - if (writablePaths.length) { - config["sandbox_workspace_write.writable_roots"] = writablePaths; - } - - const commandAllowlist = (overrides.commandAllowlist ?? []).map((entry) => String(entry).trim()).filter(Boolean); - if (commandAllowlist.length) { - config["tools.shell.allowlist"] = commandAllowlist; - } - - return Object.keys(config).length ? config : undefined; -} - -export function createCodexExecutor(): AgentExecutor { - const listModels = async (): Promise => DEFAULT_CODEX_MODELS; - - const execute = (prompt: string, opts: ExecutorOpts): AsyncIterable => { - return { - async *[Symbol.asyncIterator]() { - const codexConfig = buildCodexConfig(opts.providerConfig?.codex); - const codex = new Codex({ - ...(codexConfig ? { config: codexConfig } : {}) - }); - - const codexOverrides = opts.providerConfig?.codex; - const sandboxMode = codexOverrides?.sandboxPermissions ?? mapSandbox(opts.permissions.mode); - const approvalPolicy = codexOverrides?.approvalMode ?? mapApproval(opts.permissions.mode); - - const threadOptions: ThreadOptions = { - model: opts.model, - sandboxMode, - approvalPolicy, - workingDirectory: opts.cwd, - skipGitRepoCheck: false, - ...(codexOverrides?.writablePaths?.length - ? { additionalDirectories: codexOverrides.writablePaths } - : {}) - }; - - const thread = codex.startThread(threadOptions); - const turnOptions: TurnOptions = { - ...(opts.jsonSchema ? { outputSchema: opts.jsonSchema } : {}) - }; - - const abortController = new AbortController(); - const timeout = Math.max(1_000, Math.floor(opts.timeoutMs || 0)); - const timeoutHandle = setTimeout(() => abortController.abort(), timeout); - - let sessionId: string = randomUUID(); - let usage: Usage | null = null; - let finalText = ""; - - try { - const streamed = await thread.runStreamed(prompt, { - ...turnOptions, - signal: abortController.signal - }); - - for await (const event of streamed.events) { - if (event.type === "thread.started") { - sessionId = event.thread_id; - continue; - } - - if (event.type === "item.started" || event.type === "item.updated" || event.type === "item.completed") { - const item = event.item; - - if (item.type === "agent_message") { - const nextText = toText(item.text); - if (nextText.length > finalText.length) { - const delta = nextText.slice(finalText.length); - if (delta.trim().length > 0) { - yield { type: "text", content: delta } satisfies AgentEvent; - } - } - finalText = nextText; - } - - for (const mapped of mapToolItem(item)) { - yield mapped; - } - - continue; - } - - if (event.type === "turn.completed") { - usage = event.usage; - continue; - } - - if (event.type === "turn.failed") { - yield { - type: "error", - message: event.error.message || "Codex turn failed." - } satisfies AgentEvent; - } - - if (event.type === "error") { - yield { - type: "error", - message: event.message || "Codex stream failed." - } satisfies AgentEvent; - } - } - - if (opts.jsonSchema) { - const structured = parseStructuredOutput(finalText); - if (structured != null) { - yield { type: "structured_output", data: structured } satisfies AgentEvent; - } - } - - yield { - type: "done", - sessionId, - provider: "codex", - model: opts.model ?? null, - usage: { - inputTokens: toNumber(usage?.input_tokens), - outputTokens: toNumber(usage?.output_tokens) - } - } satisfies AgentEvent; - } catch (error) { - yield { - type: "error", - message: error instanceof Error ? error.message : String(error) - } satisfies AgentEvent; - } finally { - clearTimeout(timeoutHandle); - } - } - }; - }; - - return { - provider: "codex", - execute, - resume(sessionId: string, prompt = "Continue.", opts): AsyncIterable { - return { - async *[Symbol.asyncIterator]() { - const codex = new Codex(); - const thread = codex.resumeThread(sessionId, { - model: opts?.model, - sandboxMode: opts?.providerConfig?.codex?.sandboxPermissions ?? "workspace-write", - approvalPolicy: opts?.providerConfig?.codex?.approvalMode ?? "on-request" - }); - - try { - const turn = await thread.run(prompt, { - ...(opts?.jsonSchema ? { outputSchema: opts.jsonSchema } : {}) - }); - - if (turn.finalResponse.trim().length) { - yield { type: "text", content: turn.finalResponse } satisfies AgentEvent; - } - - yield { - type: "done", - sessionId: thread.id ?? sessionId, - provider: "codex", - model: opts?.model ?? null, - usage: { - inputTokens: toNumber(turn.usage?.input_tokens), - outputTokens: toNumber(turn.usage?.output_tokens) - } - } satisfies AgentEvent; - } catch (error) { - yield { - type: "error", - message: error instanceof Error ? error.message : String(error) - } satisfies AgentEvent; - } - } - }; - }, - listModels - }; -} diff --git a/apps/desktop/src/main/services/ai/utils.ts b/apps/desktop/src/main/services/ai/utils.ts deleted file mode 100644 index 69d707d35..000000000 --- a/apps/desktop/src/main/services/ai/utils.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { spawnSync } from "node:child_process"; - -export function commandExists(command: string): boolean { - try { - if (process.platform === "win32") { - const result = spawnSync("where", [command], { encoding: "utf8" }); - return result.status === 0; - } - const result = spawnSync("sh", ["-lc", `command -v ${command} >/dev/null 2>&1`], { encoding: "utf8" }); - return result.status === 0; - } catch { - return false; - } -} - -export function extractFirstJsonObject(text: string): string | null { - const raw = String(text ?? "").trim(); - if (!raw) return null; - - if (raw.startsWith("{") && raw.endsWith("}")) return raw; - - const fenced = raw.match(/```(?:json)?\s*([\s\S]*?)\s*```/i); - if (fenced?.[1]) { - const inner = fenced[1].trim(); - if (inner.startsWith("{") && inner.endsWith("}")) return inner; - } - - const first = raw.indexOf("{"); - const last = raw.lastIndexOf("}"); - if (first >= 0 && last > first) { - const candidate = raw.slice(first, last + 1).trim(); - if (candidate.startsWith("{") && candidate.endsWith("}")) return candidate; - } - - return null; -} - -export function parseStructuredOutput(text: string): unknown { - const candidate = extractFirstJsonObject(text); - if (!candidate) return null; - try { - return JSON.parse(candidate); - } catch { - return null; - } -} - -export async function withTimeout(promise: Promise, timeoutMs: number, message: string): Promise { - const boundedTimeout = Math.max(1_000, Math.floor(timeoutMs || 0)); - let timeoutHandle: ReturnType | null = null; - const timeoutPromise = new Promise((_, reject) => { - timeoutHandle = setTimeout(() => reject(new Error(message)), boundedTimeout); - }); - - try { - return await Promise.race([promise, timeoutPromise]); - } finally { - if (timeoutHandle) clearTimeout(timeoutHandle); - } -} - -export function normalizeText(value: unknown): string { - return typeof value === "string" ? value : String(value ?? ""); -} diff --git a/apps/desktop/src/main/services/chat/agentChatService.test.ts b/apps/desktop/src/main/services/chat/agentChatService.test.ts deleted file mode 100644 index 2c10b36ef..000000000 --- a/apps/desktop/src/main/services/chat/agentChatService.test.ts +++ /dev/null @@ -1,986 +0,0 @@ -import fs from "node:fs"; -import os from "node:os"; -import path from "node:path"; -import { EventEmitter } from "node:events"; -import { PassThrough } from "node:stream"; -import { describe, expect, it, beforeEach, afterEach, vi } from "vitest"; - -vi.mock("ai", () => ({ - streamText: vi.fn() -})); - -vi.mock("node:child_process", async () => { - const actual = await vi.importActual("node:child_process"); - return { - ...actual, - spawn: vi.fn() - }; -}); - -vi.mock("ai-sdk-provider-claude-code", () => ({ - createClaudeCode: vi.fn(() => { - return (model: string, options: unknown) => ({ - specificationVersion: "v3", - model, - __options: options - }); - }) -})); - -vi.mock("@anthropic-ai/claude-agent-sdk", () => ({ - unstable_v2_createSession: vi.fn(() => ({ - supportedModels: vi.fn(async () => []), - close: vi.fn() - })) -})); - -vi.mock("../git/git", () => ({ - runGit: vi.fn(async () => ({ - exitCode: 0, - stdout: "abc123\n", - stderr: "" - })) -})); - -import { streamText } from "ai"; -import { spawn } from "node:child_process"; -import { runGit } from "../git/git"; -import { createAgentChatService } from "./agentChatService"; -import type { - AgentChatEventEnvelope, - AgentChatProvider, - AgentChatSession, - TerminalSessionStatus, - TerminalToolType -} from "../../../shared/types"; - -type SessionRow = { - id: string; - laneId: string; - laneName: string; - ptyId: string | null; - tracked: boolean; - pinned: boolean; - goal: string | null; - toolType: TerminalToolType | null; - title: string; - status: TerminalSessionStatus; - startedAt: string; - endedAt: string | null; - exitCode: number | null; - transcriptPath: string; - headShaStart: string | null; - headShaEnd: string | null; - lastOutputPreview: string | null; - summary: string | null; - runtimeState: "running" | "waiting-input" | "idle" | "exited" | "killed"; - resumeCommand: string | null; -}; - -type MockSessionService = ReturnType; - -type CreatedFixture = { - projectRoot: string; - adeDir: string; - transcriptsDir: string; - laneWorktreePath: string; - laneService: { - getLaneBaseAndBranch: ReturnType; - }; - projectConfigService: { - get: ReturnType; - }; - sessionService: MockSessionService; - emitted: AgentChatEventEnvelope[]; - ended: Array<{ laneId: string; sessionId: string; exitCode: number | null }>; - service: ReturnType; -}; - -type SentMessage = { - jsonrpc?: string; - id?: string | number; - method?: string; - params?: any; - result?: any; - error?: any; -}; - -function createMockSessionService() { - const rows = new Map(); - - const service = { - __rows: rows, - create: vi.fn((args: { - sessionId: string; - laneId: string; - ptyId: string | null; - tracked: boolean; - title: string; - startedAt: string; - transcriptPath: string; - toolType?: TerminalToolType | null; - resumeCommand?: string | null; - }) => { - rows.set(args.sessionId, { - id: args.sessionId, - laneId: args.laneId, - laneName: `Lane ${args.laneId}`, - ptyId: args.ptyId, - tracked: args.tracked, - pinned: false, - goal: null, - toolType: args.toolType ?? null, - title: args.title, - status: "running", - startedAt: args.startedAt, - endedAt: null, - exitCode: null, - transcriptPath: args.transcriptPath, - headShaStart: null, - headShaEnd: null, - lastOutputPreview: null, - summary: null, - runtimeState: "running", - resumeCommand: args.resumeCommand ?? null - }); - }), - - get: vi.fn((sessionId: string): SessionRow | null => rows.get(sessionId) ?? null), - - list: vi.fn((args: { laneId?: string; limit?: number } = {}): SessionRow[] => { - const laneId = args.laneId?.trim(); - const all = [...rows.values()].filter((row) => (!laneId ? true : row.laneId === laneId)); - all.sort((a, b) => Date.parse(b.startedAt) - Date.parse(a.startedAt)); - const limit = typeof args.limit === "number" ? args.limit : all.length; - return all.slice(0, limit); - }), - - reopen: vi.fn((sessionId: string) => { - const row = rows.get(sessionId); - if (!row) return; - row.status = "running"; - row.endedAt = null; - row.exitCode = null; - row.runtimeState = "running"; - }), - - setHeadShaStart: vi.fn((sessionId: string, sha: string) => { - const row = rows.get(sessionId); - if (!row) return; - row.headShaStart = sha; - }), - - setHeadShaEnd: vi.fn((sessionId: string, sha: string) => { - const row = rows.get(sessionId); - if (!row) return; - row.headShaEnd = sha; - }), - - setLastOutputPreview: vi.fn((sessionId: string, preview: string) => { - const row = rows.get(sessionId); - if (!row) return; - row.lastOutputPreview = preview; - }), - - setSummary: vi.fn((sessionId: string, summary: string | null) => { - const row = rows.get(sessionId); - if (!row) return; - row.summary = summary; - }), - - setResumeCommand: vi.fn((sessionId: string, resumeCommand: string | null) => { - const row = rows.get(sessionId); - if (!row) return; - row.resumeCommand = resumeCommand; - }), - - end: vi.fn((args: { sessionId: string; endedAt: string; exitCode: number | null; status: TerminalSessionStatus }) => { - const row = rows.get(args.sessionId); - if (!row) return; - row.status = args.status; - row.endedAt = args.endedAt; - row.exitCode = args.exitCode; - row.runtimeState = args.status === "running" ? "running" : args.status === "disposed" ? "killed" : "exited"; - row.ptyId = null; - }), - - readTranscriptTail: vi.fn((transcriptPath: string, maxBytes: number) => { - if (!transcriptPath || !fs.existsSync(transcriptPath)) return ""; - const data = fs.readFileSync(transcriptPath, "utf8"); - return data.length > maxBytes ? data.slice(-maxBytes) : data; - }) - }; - - return service; -} - -function createMockCodexProcess() { - const stdin = new PassThrough(); - const stdout = new PassThrough(); - const stderr = new PassThrough(); - - const proc = new EventEmitter() as any; - proc.stdin = stdin; - proc.stdout = stdout; - proc.stderr = stderr; - proc.kill = vi.fn(() => true); - - const sent: SentMessage[] = []; - const handlers = new Map void>(); - - let buffer = ""; - stdin.on("data", (chunk: Buffer | string) => { - buffer += chunk.toString(); - while (true) { - const idx = buffer.indexOf("\n"); - if (idx < 0) break; - const line = buffer.slice(0, idx); - buffer = buffer.slice(idx + 1); - if (!line.trim().length) continue; - const parsed = JSON.parse(line) as SentMessage; - sent.push(parsed); - if (parsed.method && handlers.has(parsed.method)) { - handlers.get(parsed.method)?.(parsed); - } - } - }); - - const writeOut = (payload: SentMessage) => { - stdout.write(`${JSON.stringify(payload)}\n`); - }; - - return { - proc, - sent, - onRequest: (method: string, handler: (msg: SentMessage) => void) => { - handlers.set(method, handler); - }, - notify: (method: string, params?: unknown) => { - writeOut({ jsonrpc: "2.0", method, params }); - }, - serverRequest: (id: string | number, method: string, params?: unknown) => { - writeOut({ jsonrpc: "2.0", id, method, params }); - }, - respond: (id: string | number, result?: unknown) => { - writeOut({ jsonrpc: "2.0", id, result }); - }, - reject: (id: string | number, message: string) => { - writeOut({ jsonrpc: "2.0", id, error: { code: -32000, message } }); - } - }; -} - -function makeFullStream(parts: any[]): AsyncIterable { - return { - async *[Symbol.asyncIterator]() { - for (const part of parts) { - yield part; - } - } - }; -} - -function createFixture(provider: AgentChatProvider): CreatedFixture { - const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ade-agent-chat-tests-")); - const adeDir = path.join(projectRoot, ".ade"); - const transcriptsDir = path.join(adeDir, "transcripts"); - const laneWorktreePath = path.join(projectRoot, "lane-worktree"); - - fs.mkdirSync(adeDir, { recursive: true }); - fs.mkdirSync(transcriptsDir, { recursive: true }); - fs.mkdirSync(laneWorktreePath, { recursive: true }); - - const laneService = { - getLaneBaseAndBranch: vi.fn((laneId: string) => ({ - worktreePath: laneWorktreePath, - baseRef: "main", - branchRef: `feature/${laneId}` - })) - }; - - const projectConfigService = { - get: vi.fn(() => ({ - effective: { - ai: { - chat: { - defaultApprovalPolicy: "approve_mutations", - codexSandbox: "workspace-write", - claudePermissionMode: "acceptEdits", - sessionBudgetUsd: 10, - sendOnEnter: true - } - } - } - })) - }; - - const sessionService = createMockSessionService(); - const emitted: AgentChatEventEnvelope[] = []; - const ended: Array<{ laneId: string; sessionId: string; exitCode: number | null }> = []; - - const service = createAgentChatService({ - projectRoot, - adeDir, - transcriptsDir, - laneService: laneService as any, - sessionService: sessionService as any, - projectConfigService: projectConfigService as any, - logger: { - debug: () => {}, - info: () => {}, - warn: () => {}, - error: () => {} - } as any, - appVersion: "0.0.0-test", - onEvent: (event) => emitted.push(event), - onSessionEnded: (entry) => ended.push(entry) - }); - - return { - projectRoot, - adeDir, - transcriptsDir, - laneWorktreePath, - laneService, - projectConfigService, - sessionService, - emitted, - ended, - service - }; -} - -async function waitForEvent(events: AgentChatEventEnvelope[], predicate: (event: AgentChatEventEnvelope) => boolean) { - await waitForCondition(() => { - expect(events.some(predicate)).toBe(true); - }); - return events.find(predicate) ?? null; -} - -async function waitForCondition( - assertion: () => void, - options: { timeoutMs?: number; intervalMs?: number } = {} -): Promise { - const timeoutMs = options.timeoutMs ?? 5_000; - const intervalMs = options.intervalMs ?? 10; - const deadline = Date.now() + timeoutMs; - - let lastError: unknown; - while (Date.now() <= deadline) { - try { - assertion(); - return; - } catch (error) { - lastError = error; - } - await new Promise((resolve) => setTimeout(resolve, intervalMs)); - } - - if (lastError instanceof Error) throw lastError; - throw new Error("Timed out waiting for condition."); -} - -const spawnMock = vi.mocked(spawn); -const runGitMock = vi.mocked(runGit); -const streamTextMock = vi.mocked(streamText); - -describe("agentChatService", () => { - beforeEach(() => { - vi.clearAllMocks(); - runGitMock.mockResolvedValue({ exitCode: 0, stdout: "abc123\n", stderr: "" } as any); - streamTextMock.mockReset(); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - describe("CodexChatBackend", () => { - it("performs JSON-RPC handshake with initialize then initialized", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => { - codex.respond(msg.id!, { serverInfo: { name: "codex" } }); - }); - codex.onRequest("thread/start", (msg) => { - codex.respond(msg.id!, { thread: { id: "thread-1" } }); - }); - - const session = await fixture.service.createSession({ - laneId: "lane-1", - provider: "codex", - model: "gpt-5.3-codex" - }); - - expect(session.provider).toBe("codex"); - const initialize = codex.sent.find((entry) => entry.method === "initialize"); - expect(initialize).toBeTruthy(); - expect(initialize?.params?.clientInfo?.name).toBe("ade"); - expect(initialize?.params?.clientInfo?.title).toBe("ADE"); - - const initializedIndex = codex.sent.findIndex((entry) => entry.method === "initialized"); - const initializeIndex = codex.sent.findIndex((entry) => entry.method === "initialize"); - expect(initializeIndex).toBeGreaterThanOrEqual(0); - expect(initializedIndex).toBeGreaterThan(initializeIndex); - - await fixture.service.disposeAll(); - }); - - it("sends thread/start with lane cwd, model, approval, and sandbox", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - let threadStart: SentMessage | null = null; - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => { - threadStart = msg; - codex.respond(msg.id!, { thread: { id: "thread-abc" } }); - }); - - await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - - expect(threadStart).toBeTruthy(); - expect(threadStart?.params?.cwd).toBe(fixture.laneWorktreePath); - expect(threadStart?.params?.model).toBe("gpt-5.3-codex"); - expect(threadStart?.params?.approvalPolicy).toBe("on-request"); - expect(threadStart?.params?.sandbox).toBe("workspace-write"); - - await fixture.service.disposeAll(); - }); - - it("maps turn notifications into ChatEvents for sendMessage", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-1" } })); - codex.onRequest("turn/start", (msg) => { - codex.respond(msg.id!, { turn: { id: "turn-1" } }); - - codex.notify("item/agentMessage/delta", { - turnId: "turn-1", - itemId: "agent-1", - delta: "Hello" - }); - - codex.notify("item/started", { - item: { - id: "cmd-1", - type: "commandExecution", - command: "npm test", - cwd: fixture.laneWorktreePath, - status: "inProgress", - aggregatedOutput: "" - } - }); - - codex.notify("item/commandExecution/outputDelta", { - turnId: "turn-1", - itemId: "cmd-1", - delta: "all good\n" - }); - - codex.notify("item/completed", { - item: { - id: "cmd-1", - type: "commandExecution", - command: "npm test", - cwd: fixture.laneWorktreePath, - status: "completed", - exitCode: 0, - durationMs: 140, - aggregatedOutput: "all good\n" - } - }); - - codex.notify("item/started", { - item: { - id: "file-1", - type: "fileChange", - status: "inProgress", - changes: [ - { - path: "src/index.ts", - kind: "add", - diff: "+++ src/index.ts\n+export const ok = true;\n" - } - ] - } - }); - - codex.notify("item/completed", { - item: { - id: "file-1", - type: "fileChange", - status: "completed", - changes: [ - { - path: "src/index.ts", - kind: "add", - diff: "+++ src/index.ts\n+export const ok = true;\n" - } - ] - } - }); - - codex.notify("turn/completed", { - turn: { - id: "turn-1", - status: "completed" - } - }); - }); - codex.onRequest("turn/interrupt", (msg) => codex.respond(msg.id!, {})); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "Run checks" }); - - await waitForEvent(fixture.emitted, (entry) => entry.event.type === "done"); - - const eventTypes = fixture.emitted.map((entry) => entry.event.type); - expect(eventTypes).toContain("text"); - expect(eventTypes).toContain("command"); - expect(eventTypes).toContain("file_change"); - expect(eventTypes).toContain("done"); - - const turnStart = codex.sent.find((entry) => entry.method === "turn/start"); - expect(turnStart?.params?.threadId).toBe("thread-1"); - expect(turnStart?.params?.input?.[0]?.type).toBe("text"); - - await fixture.service.disposeAll(); - }); - - it("emits approval_request and sends accept decision response", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-1" } })); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - - codex.serverRequest(7001, "item/commandExecution/requestApproval", { - itemId: "cmd-approval-1", - command: "rm -rf tmp", - cwd: fixture.laneWorktreePath, - reason: "Needs user approval" - }); - - await waitForEvent( - fixture.emitted, - (entry) => entry.event.type === "approval_request" && entry.event.itemId === "cmd-approval-1" - ); - - await fixture.service.approveToolUse({ - sessionId: session.id, - itemId: "cmd-approval-1", - decision: "accept" - }); - - const response = codex.sent.find((entry) => entry.id === 7001 && Object.prototype.hasOwnProperty.call(entry, "result")); - expect(response?.result?.decision).toBe("accept"); - - await fixture.service.disposeAll(); - }); - - it("sends turn/steer while turn is active", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-1" } })); - codex.onRequest("turn/start", (msg) => { - codex.respond(msg.id!, { turn: { id: "turn-active" } }); - }); - codex.onRequest("turn/steer", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("turn/interrupt", (msg) => codex.respond(msg.id!, {})); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "start" }); - await fixture.service.steer({ sessionId: session.id, text: "refine" }); - - const steerRequest = codex.sent.find((entry) => entry.method === "turn/steer"); - expect(steerRequest).toBeTruthy(); - expect(steerRequest?.params?.threadId).toBe("thread-1"); - expect(steerRequest?.params?.expectedTurnId).toBe("turn-active"); - expect(steerRequest?.params?.input?.[0]?.text).toBe("refine"); - - await fixture.service.disposeAll(); - }); - - it("sends turn/interrupt on interrupt", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-1" } })); - codex.onRequest("turn/start", (msg) => codex.respond(msg.id!, { turn: { id: "turn-active" } })); - codex.onRequest("turn/interrupt", (msg) => codex.respond(msg.id!, {})); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "start" }); - await fixture.service.interrupt({ sessionId: session.id }); - - const interruptRequest = codex.sent.find((entry) => entry.method === "turn/interrupt"); - expect(interruptRequest?.params?.threadId).toBe("thread-1"); - expect(interruptRequest?.params?.turnId).toBe("turn-active"); - - await fixture.service.disposeAll(); - }); - - it("maps error notification with codexErrorInfo", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-1" } })); - - await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - - codex.notify("error", { - turnId: "turn-err", - error: { - message: "Context exceeded", - codexErrorInfo: { - kind: "ContextWindowExceeded" - } - } - }); - - const errorEvent = await waitForEvent(fixture.emitted, (entry) => entry.event.type === "error"); - expect(errorEvent?.event.type).toBe("error"); - if (errorEvent?.event.type === "error") { - expect(errorEvent.event.message).toContain("Context exceeded"); - expect(errorEvent.event.errorInfo).toContain("ContextWindowExceeded"); - } - - await fixture.service.disposeAll(); - }); - }); - - describe("ClaudeChatBackend", () => { - it("supports multi-turn messages and carries conversation context", async () => { - const fixture = createFixture("claude"); - - streamTextMock - .mockImplementationOnce(() => ({ - fullStream: makeFullStream([ - { type: "text-delta", text: "hello" }, - { type: "finish", totalUsage: { inputTokens: 2, outputTokens: 3 } } - ]) - }) as any) - .mockImplementationOnce(() => ({ - fullStream: makeFullStream([ - { type: "text-delta", text: "next" }, - { type: "finish", totalUsage: { inputTokens: 4, outputTokens: 5 } } - ]) - }) as any); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "claude", model: "sonnet" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "First" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "Second" }); - - expect(streamTextMock).toHaveBeenCalledTimes(2); - - const firstInput = streamTextMock.mock.calls[0]?.[0] as any; - const secondInput = streamTextMock.mock.calls[1]?.[0] as any; - - expect(firstInput.messages).toHaveLength(1); - expect(secondInput.messages).toHaveLength(3); - expect(secondInput.messages[2]?.content).toContain("Second"); - - await fixture.service.disposeAll(); - }); - - it("maps text-delta chunks into text ChatEvents", async () => { - const fixture = createFixture("claude"); - - streamTextMock.mockImplementationOnce(() => ({ - fullStream: makeFullStream([ - { type: "text-delta", text: "A" }, - { type: "text-delta", text: "B" }, - { type: "finish", totalUsage: { inputTokens: 1, outputTokens: 2 } } - ]) - }) as any); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "claude", model: "sonnet" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "Go" }); - - const textEvents = fixture.emitted.filter((entry) => entry.event.type === "text"); - expect(textEvents.map((entry) => (entry.event.type === "text" ? entry.event.text : "")).join("")).toContain("AB"); - - await fixture.service.disposeAll(); - }); - - it("routes tool approval through pending approval queue", async () => { - const fixture = createFixture("claude"); - - streamTextMock.mockImplementationOnce((input: any) => ({ - fullStream: { - async *[Symbol.asyncIterator]() { - const permission = await input.model.__options.canUseTool("Bash", { command: "ls" }); - yield { type: "text-delta", text: `tool:${permission.behavior}` }; - yield { type: "finish", totalUsage: { inputTokens: 1, outputTokens: 1 } }; - } - } - }) as any); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "claude", model: "sonnet" }); - const sendPromise = fixture.service.sendMessage({ sessionId: session.id, text: "Use a tool" }); - - const approval = await waitForEvent(fixture.emitted, (entry) => entry.event.type === "approval_request"); - expect(approval?.event.type).toBe("approval_request"); - - if (approval?.event.type === "approval_request") { - await fixture.service.approveToolUse({ - sessionId: session.id, - itemId: approval.event.itemId, - decision: "accept" - }); - } - - await sendPromise; - - const textEvent = fixture.emitted.find( - (entry) => entry.event.type === "text" && entry.event.text.includes("tool:allow") - ); - expect(textEvent).toBeTruthy(); - - await fixture.service.disposeAll(); - }); - - it("queues steer text and runs it as follow-up turn after completion", async () => { - const fixture = createFixture("claude"); - let releaseFirstTurn: (() => void) | null = null; - - streamTextMock - .mockImplementationOnce(() => ({ - fullStream: { - async *[Symbol.asyncIterator]() { - yield { type: "text-delta", text: "working" }; - await new Promise((resolve) => { - releaseFirstTurn = resolve; - }); - yield { type: "finish", totalUsage: { inputTokens: 1, outputTokens: 1 } }; - } - } - }) as any) - .mockImplementationOnce(() => ({ - fullStream: makeFullStream([ - { type: "text-delta", text: "steered" }, - { type: "finish", totalUsage: { inputTokens: 1, outputTokens: 1 } } - ]) - }) as any); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "claude", model: "sonnet" }); - const sendPromise = fixture.service.sendMessage({ sessionId: session.id, text: "initial" }); - - await waitForEvent(fixture.emitted, (entry) => entry.event.type === "text" && entry.event.text.includes("working")); - - await fixture.service.steer({ sessionId: session.id, text: "follow-up steer" }); - releaseFirstTurn?.(); - await sendPromise; - - await waitForCondition(() => { - expect(streamTextMock).toHaveBeenCalledTimes(2); - }); - - const secondInput = streamTextMock.mock.calls[1]?.[0] as any; - expect(secondInput.messages[secondInput.messages.length - 1]?.content).toContain("follow-up steer"); - - await fixture.service.disposeAll(); - }); - - it("aborts active stream on interrupt and emits interrupted status", async () => { - const fixture = createFixture("claude"); - let capturedSignal: AbortSignal | null = null; - - streamTextMock.mockImplementationOnce((input: any) => { - capturedSignal = input.abortSignal; - return { - fullStream: { - async *[Symbol.asyncIterator]() { - await new Promise((resolve) => { - if (input.abortSignal.aborted) { - resolve(); - return; - } - input.abortSignal.addEventListener("abort", () => resolve(), { once: true }); - }); - throw new Error("aborted"); - } - } - }; - }); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "claude", model: "sonnet" }); - const sendPromise = fixture.service.sendMessage({ sessionId: session.id, text: "long-running" }); - - await waitForCondition(() => { - expect(capturedSignal).toBeTruthy(); - }); - - await fixture.service.interrupt({ sessionId: session.id }); - await sendPromise; - - expect(capturedSignal?.aborted).toBe(true); - const interrupted = fixture.emitted.find( - (entry) => entry.event.type === "status" && entry.event.turnStatus === "interrupted" - ); - expect(interrupted).toBeTruthy(); - - await fixture.service.disposeAll(); - }); - - it("persists session state and resumes with prior messages", async () => { - const fixture = createFixture("claude"); - - streamTextMock - .mockImplementationOnce(() => ({ - fullStream: makeFullStream([ - { type: "text-delta", text: "first-response" }, - { type: "finish", totalUsage: { inputTokens: 1, outputTokens: 1 } } - ]) - }) as any) - .mockImplementationOnce(() => ({ - fullStream: makeFullStream([ - { type: "text-delta", text: "second-response" }, - { type: "finish", totalUsage: { inputTokens: 2, outputTokens: 2 } } - ]) - }) as any); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "claude", model: "sonnet" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "first-message" }); - await fixture.service.dispose({ sessionId: session.id }); - - const metadataPath = path.join(fixture.adeDir, "chat-sessions", `${session.id}.json`); - expect(fs.existsSync(metadataPath)).toBe(true); - - const persisted = JSON.parse(fs.readFileSync(metadataPath, "utf8")) as { - messages?: Array<{ role: string; content: string }>; - }; - expect((persisted.messages ?? []).length).toBeGreaterThanOrEqual(2); - - const resumedService = createAgentChatService({ - projectRoot: fixture.projectRoot, - adeDir: fixture.adeDir, - transcriptsDir: fixture.transcriptsDir, - laneService: fixture.laneService as any, - sessionService: fixture.sessionService as any, - projectConfigService: fixture.projectConfigService as any, - logger: { - debug: () => {}, - info: () => {}, - warn: () => {}, - error: () => {} - } as any, - appVersion: "0.0.0-test", - onEvent: (event) => fixture.emitted.push(event), - onSessionEnded: (entry) => fixture.ended.push(entry) - }); - - await resumedService.resumeSession({ sessionId: session.id }); - await resumedService.sendMessage({ sessionId: session.id, text: "second-message" }); - - const secondInput = streamTextMock.mock.calls[1]?.[0] as any; - expect(secondInput.messages.length).toBeGreaterThanOrEqual(3); - expect(secondInput.messages[0]?.content).toContain("first-message"); - - await resumedService.disposeAll(); - }); - }); - - describe("Session integration", () => { - it("registers terminal_session rows with codex-chat and claude-chat tool types", async () => { - const codexFixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-row" } })); - - await codexFixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - const codexCreateArgs = codexFixture.sessionService.create.mock.calls[0]?.[0]; - expect(codexCreateArgs.toolType).toBe("codex-chat"); - - await codexFixture.service.disposeAll(); - - const claudeFixture = createFixture("claude"); - await claudeFixture.service.createSession({ laneId: "lane-1", provider: "claude", model: "sonnet" }); - const claudeCreateArgs = claudeFixture.sessionService.create.mock.calls[0]?.[0]; - expect(claudeCreateArgs.toolType).toBe("claude-chat"); - - await claudeFixture.service.disposeAll(); - }); - - it("writes JSONL transcripts and appends ChatEvents", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-1" } })); - codex.onRequest("turn/start", (msg) => { - codex.respond(msg.id!, { turn: { id: "turn-1" } }); - codex.notify("item/agentMessage/delta", { turnId: "turn-1", itemId: "agent-1", delta: "transcript line" }); - codex.notify("turn/completed", { turn: { id: "turn-1", status: "completed" } }); - }); - codex.onRequest("turn/interrupt", (msg) => codex.respond(msg.id!, {})); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "hello" }); - - await waitForEvent(fixture.emitted, (entry) => entry.event.type === "done"); - - const row = fixture.sessionService.__rows.get(session.id); - expect(row).toBeTruthy(); - expect(row?.transcriptPath.endsWith(".chat.jsonl")).toBe(true); - expect(fs.existsSync(row!.transcriptPath)).toBe(true); - - const transcript = fs.readFileSync(row!.transcriptPath, "utf8"); - const lines = transcript.trim().split(/\r?\n/).filter(Boolean); - expect(lines.length).toBeGreaterThanOrEqual(2); - - const parsed = JSON.parse(lines[0]!) as AgentChatEventEnvelope; - expect(parsed.sessionId).toBe(session.id); - - await fixture.service.disposeAll(); - }); - - it("disposes sessions through sessionService.end with summary and head sha metadata", async () => { - const fixture = createFixture("codex"); - const codex = createMockCodexProcess(); - spawnMock.mockReturnValue(codex.proc as any); - - codex.onRequest("initialize", (msg) => codex.respond(msg.id!, {})); - codex.onRequest("thread/start", (msg) => codex.respond(msg.id!, { thread: { id: "thread-1" } })); - codex.onRequest("turn/start", (msg) => { - codex.respond(msg.id!, { turn: { id: "turn-1" } }); - codex.notify("item/agentMessage/delta", { turnId: "turn-1", itemId: "agent-1", delta: "preview output" }); - }); - codex.onRequest("turn/interrupt", (msg) => codex.respond(msg.id!, {})); - - const session = await fixture.service.createSession({ laneId: "lane-1", provider: "codex", model: "gpt-5.3-codex" }); - await fixture.service.sendMessage({ sessionId: session.id, text: "hello" }); - await fixture.service.dispose({ sessionId: session.id }); - - expect(fixture.sessionService.end).toHaveBeenCalled(); - const endArg = fixture.sessionService.end.mock.calls.at(-1)?.[0]; - expect(endArg.sessionId).toBe(session.id); - expect(endArg.status).toBe("disposed"); - - const row = fixture.sessionService.__rows.get(session.id); - expect(row?.lastOutputPreview).toContain("preview output"); - expect((row?.summary ?? "").toLowerCase()).toContain("session closed"); - expect(row?.headShaEnd).toBe("abc123"); - }); - }); -}); diff --git a/apps/desktop/src/main/services/chat/agentChatService.ts b/apps/desktop/src/main/services/chat/agentChatService.ts deleted file mode 100644 index dd43855f3..000000000 --- a/apps/desktop/src/main/services/chat/agentChatService.ts +++ /dev/null @@ -1,1754 +0,0 @@ -import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process"; -import { randomUUID } from "node:crypto"; -import fs from "node:fs"; -import path from "node:path"; -import readline from "node:readline"; -import { streamText } from "ai"; -import { createClaudeCode } from "ai-sdk-provider-claude-code"; -import { - unstable_v2_createSession, - type ModelInfo, - type PermissionResult -} from "@anthropic-ai/claude-agent-sdk"; -import type { Logger } from "../logging/logger"; -import type { createLaneService } from "../lanes/laneService"; -import type { createSessionService } from "../sessions/sessionService"; -import type { createProjectConfigService } from "../config/projectConfigService"; -import { runGit } from "../git/git"; -import type { - AgentChatApprovalDecision, - AgentChatCreateArgs, - AgentChatDisposeArgs, - AgentChatEvent, - AgentChatEventEnvelope, - AgentChatFileRef, - AgentChatInterruptArgs, - AgentChatModelInfo, - AgentChatProvider, - AgentChatSession, - AgentChatSessionSummary, - AgentChatSteerArgs, - AgentChatSendArgs, - TerminalSessionStatus, - TerminalToolType -} from "../../../shared/types"; - -type JsonRpcEnvelope = { - jsonrpc?: string; - id?: string | number; - method?: string; - params?: unknown; - result?: unknown; - error?: { - code?: number; - message?: string; - data?: unknown; - }; -}; - -type PersistedClaudeMessage = { - role: "user" | "assistant"; - content: string; -}; - -type PersistedChatState = { - version: 1; - sessionId: string; - laneId: string; - provider: AgentChatProvider; - model: string; - threadId?: string; - messages?: PersistedClaudeMessage[]; - updatedAt: string; -}; - -type PendingRpc = { - resolve: (value: any) => void; - reject: (error: Error) => void; -}; - -type PendingCodexApproval = { - requestId: string | number; - kind: "command" | "file_change"; -}; - -type PendingClaudeApproval = { - resolve: (decision: AgentChatApprovalDecision) => void; -}; - -type CodexRuntime = { - kind: "codex"; - process: ChildProcessWithoutNullStreams; - reader: readline.Interface; - nextRequestId: number; - pending: Map; - approvals: Map; - activeTurnId: string | null; - commandOutputByItemId: Map; - fileDeltaByItemId: Map; - fileChangesByItemId: Map>; - request: (method: string, params?: unknown) => Promise; - notify: (method: string, params?: unknown) => void; - sendResponse: (id: string | number, result: unknown) => void; - sendError: (id: string | number, message: string) => void; -}; - -type ClaudeRuntime = { - kind: "claude"; - messages: PersistedClaudeMessage[]; - busy: boolean; - abortController: AbortController | null; - activeTurnId: string | null; - pendingSteers: string[]; - approvals: Map; - interrupted: boolean; -}; - -type ChatRuntime = CodexRuntime | ClaudeRuntime; - -type ManagedChatSession = { - session: AgentChatSession; - transcriptPath: string; - metadataPath: string; - laneWorktreePath: string; - runtime: ChatRuntime | null; - preview: string | null; - closed: boolean; - endedNotified: boolean; -}; - -type ResolvedChatConfig = { - codexApprovalPolicy: "untrusted" | "on-request" | "on-failure" | "never"; - codexSandboxMode: "read-only" | "workspace-write" | "danger-full-access"; - claudePermissionMode: "plan" | "acceptEdits" | "bypassPermissions"; - sessionBudgetUsd: number | null; -}; - -const DEFAULT_CODEX_MODEL = "gpt-5.3-codex"; -const DEFAULT_CLAUDE_MODEL = "sonnet"; - -const CODEX_FALLBACK_MODELS: AgentChatModelInfo[] = [ - { id: "gpt-5.3-codex", displayName: "gpt-5.3-codex", isDefault: true }, - { id: "gpt-5.2-codex", displayName: "gpt-5.2-codex", isDefault: false }, - { id: "gpt-5.1-codex-max", displayName: "gpt-5.1-codex-max", isDefault: false }, - { id: "codex-mini-latest", displayName: "codex-mini-latest", isDefault: false }, - { id: "o4-mini", displayName: "o4-mini", isDefault: false }, - { id: "o3", displayName: "o3", isDefault: false } -]; - -const CLAUDE_ALIAS_TO_MODEL: Record = { - opus: "claude-opus-4-6", - sonnet: "claude-sonnet-4-6", - haiku: "claude-haiku-4-5-20251001" -}; - -const CLAUDE_FALLBACK_MODELS: AgentChatModelInfo[] = [ - { id: "opus", displayName: "Opus", isDefault: false }, - { id: "sonnet", displayName: "Sonnet", isDefault: true }, - { id: "haiku", displayName: "Haiku", isDefault: false } -]; - -function isChatToolType(toolType: TerminalToolType | null | undefined): toolType is "codex-chat" | "claude-chat" { - return toolType === "codex-chat" || toolType === "claude-chat"; -} - -function providerFromToolType(toolType: TerminalToolType | null | undefined): AgentChatProvider { - return toolType === "claude-chat" ? "claude" : "codex"; -} - -function toolTypeFromProvider(provider: AgentChatProvider): "codex-chat" | "claude-chat" { - return provider === "claude" ? "claude-chat" : "codex-chat"; -} - -function mapTerminalStatusToChatStatus(status: TerminalSessionStatus): AgentChatSession["status"] { - if (status === "running") return "idle"; - return "ended"; -} - -function mapCommandStatus(raw: string | null | undefined): "running" | "completed" | "failed" { - if (raw === "completed") return "completed"; - if (raw === "failed" || raw === "declined") return "failed"; - return "running"; -} - -function mapFileChangeKind(raw: unknown): "create" | "modify" | "delete" { - const type = typeof raw === "string" - ? raw - : raw && typeof raw === "object" && typeof (raw as { type?: unknown }).type === "string" - ? String((raw as { type?: unknown }).type) - : "update"; - if (type === "add") return "create"; - if (type === "delete") return "delete"; - return "modify"; -} - -function mapCodexTurnStatus(raw: unknown): "completed" | "interrupted" | "failed" { - const value = typeof raw === "string" ? raw : ""; - if (value === "interrupted") return "interrupted"; - if (value === "failed") return "failed"; - return "completed"; -} - -function formatCodexErrorInfo(value: unknown): string | undefined { - if (value == null) return undefined; - if (typeof value === "string") return value; - try { - return JSON.stringify(value); - } catch { - return String(value); - } -} - -function mapApprovalDecisionForCodex(decision: AgentChatApprovalDecision): "accept" | "acceptForSession" | "decline" | "cancel" { - if (decision === "accept_for_session") return "acceptForSession"; - if (decision === "accept") return "accept"; - if (decision === "cancel") return "cancel"; - return "decline"; -} - -function normalizePreview(text: string, maxChars = 220): string | null { - const lines = text - .split(/\r?\n/) - .map((line) => line.trim()) - .filter(Boolean); - if (!lines.length) return null; - const preview = lines[lines.length - 1] ?? ""; - return preview.length > maxChars ? preview.slice(0, maxChars) : preview; -} - -function parseJsonLine(raw: string): JsonRpcEnvelope | null { - const line = raw.trim(); - if (!line) return null; - try { - const parsed = JSON.parse(line) as unknown; - if (!parsed || typeof parsed !== "object") return null; - return parsed as JsonRpcEnvelope; - } catch { - return null; - } -} - -function resolveClaudeModel(model: string): string { - const normalized = model.trim().toLowerCase(); - if (!normalized) return CLAUDE_ALIAS_TO_MODEL.sonnet; - return CLAUDE_ALIAS_TO_MODEL[normalized] ?? model; -} - -function toIso(): string { - return new Date().toISOString(); -} - -export function createAgentChatService(args: { - projectRoot: string; - adeDir: string; - transcriptsDir: string; - laneService: ReturnType; - sessionService: ReturnType; - projectConfigService: ReturnType; - logger: Logger; - appVersion: string; - onEvent?: (event: AgentChatEventEnvelope) => void; - onSessionEnded?: (args: { laneId: string; sessionId: string; exitCode: number | null }) => void; -}) { - const { - projectRoot, - adeDir, - transcriptsDir, - laneService, - sessionService, - projectConfigService, - logger, - appVersion, - onEvent, - onSessionEnded - } = args; - - const chatSessionsDir = path.join(adeDir, "chat-sessions"); - fs.mkdirSync(chatSessionsDir, { recursive: true }); - fs.mkdirSync(transcriptsDir, { recursive: true }); - - const claudeProvider = createClaudeCode(); - const managedSessions = new Map(); - - const resolveChatConfig = (): ResolvedChatConfig => { - const snapshot = projectConfigService.get(); - const ai = snapshot.effective.ai ?? {}; - const permissions = ai.permissions ?? {}; - const chat = ai.chat ?? {}; - - const approvalPolicy = (() => { - if (chat.defaultApprovalPolicy === "auto") return "never" as const; - if (chat.defaultApprovalPolicy === "approve_all") return "untrusted" as const; - if (chat.defaultApprovalPolicy === "approve_mutations") return "on-request" as const; - if (permissions.codex?.approvalMode) return permissions.codex.approvalMode; - return "on-request" as const; - })(); - - const sandboxMode = (() => { - if (chat.codexSandbox) return chat.codexSandbox; - if (permissions.codex?.sandboxPermissions) return permissions.codex.sandboxPermissions; - return "workspace-write" as const; - })(); - - const claudePermissionMode = (() => { - if (chat.claudePermissionMode) return chat.claudePermissionMode; - if (permissions.claude?.permissionMode === "plan") return "plan" as const; - if (permissions.claude?.permissionMode === "bypassPermissions") return "bypassPermissions" as const; - if (permissions.claude?.permissionMode === "acceptEdits") return "acceptEdits" as const; - return "acceptEdits" as const; - })(); - - const budget = Number(chat.sessionBudgetUsd ?? permissions.claude?.maxBudgetUsd ?? NaN); - const sessionBudgetUsd = Number.isFinite(budget) && budget > 0 ? budget : null; - - return { - codexApprovalPolicy: approvalPolicy, - codexSandboxMode: sandboxMode, - claudePermissionMode, - sessionBudgetUsd - }; - }; - - const computeHeadShaBestEffort = async (laneId: string): Promise => { - const { worktreePath } = laneService.getLaneBaseAndBranch(laneId); - const cwd = fs.existsSync(worktreePath) ? worktreePath : projectRoot; - const res = await runGit(["rev-parse", "HEAD"], { cwd, timeoutMs: 8_000 }); - if (res.exitCode !== 0) return null; - const sha = res.stdout.trim(); - return sha.length ? sha : null; - }; - - const metadataPathFor = (sessionId: string): string => path.join(chatSessionsDir, `${sessionId}.json`); - - const persistChatState = (managed: ManagedChatSession): void => { - const payload: PersistedChatState = { - version: 1, - sessionId: managed.session.id, - laneId: managed.session.laneId, - provider: managed.session.provider, - model: managed.session.model, - ...(managed.session.threadId ? { threadId: managed.session.threadId } : {}), - ...(managed.runtime?.kind === "claude" ? { messages: managed.runtime.messages } : {}), - updatedAt: toIso() - }; - - try { - fs.mkdirSync(path.dirname(managed.metadataPath), { recursive: true }); - fs.writeFileSync(managed.metadataPath, JSON.stringify(payload, null, 2), "utf8"); - } catch (error) { - logger.warn("agent_chat.persist_failed", { - sessionId: managed.session.id, - error: error instanceof Error ? error.message : String(error) - }); - } - }; - - const readPersistedState = (sessionId: string): PersistedChatState | null => { - const filePath = metadataPathFor(sessionId); - if (!fs.existsSync(filePath)) return null; - try { - const parsed = JSON.parse(fs.readFileSync(filePath, "utf8")) as unknown; - if (!parsed || typeof parsed !== "object") return null; - const record = parsed as Partial; - if (record.version !== 1) return null; - const provider = record.provider; - if (provider !== "codex" && provider !== "claude") return null; - const laneId = String(record.laneId ?? "").trim(); - const model = String(record.model ?? "").trim(); - if (!laneId || !model) return null; - const messages = Array.isArray(record.messages) - ? record.messages - .filter((entry): entry is PersistedClaudeMessage => { - if (!entry || typeof entry !== "object") return false; - const role = (entry as { role?: unknown }).role; - const content = (entry as { content?: unknown }).content; - return (role === "user" || role === "assistant") && typeof content === "string"; - }) - : undefined; - return { - version: 1, - sessionId, - laneId, - provider, - model, - ...(typeof record.threadId === "string" && record.threadId.trim().length - ? { threadId: record.threadId.trim() } - : {}), - ...(messages?.length ? { messages } : {}), - updatedAt: typeof record.updatedAt === "string" && record.updatedAt.trim().length ? record.updatedAt : toIso() - }; - } catch { - return null; - } - }; - - const writeTranscript = (managed: ManagedChatSession, envelope: AgentChatEventEnvelope): void => { - try { - fs.mkdirSync(path.dirname(managed.transcriptPath), { recursive: true }); - fs.appendFileSync(managed.transcriptPath, `${JSON.stringify(envelope)}\n`, "utf8"); - } catch { - // ignore transcript write failures - } - }; - - const setSessionPreview = (managed: ManagedChatSession, candidate: string): void => { - const next = normalizePreview(candidate); - if (!next) return; - if (next === managed.preview) return; - managed.preview = next; - sessionService.setLastOutputPreview(managed.session.id, next); - }; - - const emitChatEvent = (managed: ManagedChatSession, event: AgentChatEvent): void => { - managed.session.lastActivityAt = toIso(); - - if (event.type === "text") { - setSessionPreview(managed, event.text); - } else if (event.type === "command") { - setSessionPreview(managed, event.output); - } else if (event.type === "error") { - setSessionPreview(managed, event.message); - } - - if (event.type === "done") { - const summary = managed.preview - ? `${event.status}: ${managed.preview}` - : `Turn ${event.status}`; - sessionService.setSummary(managed.session.id, summary); - } - - const envelope: AgentChatEventEnvelope = { - sessionId: managed.session.id, - timestamp: toIso(), - event - }; - - writeTranscript(managed, envelope); - onEvent?.(envelope); - }; - - const finishSession = async ( - managed: ManagedChatSession, - status: TerminalSessionStatus, - options?: { exitCode?: number | null; summary?: string | null } - ): Promise => { - if (managed.endedNotified) return; - managed.endedNotified = true; - - if (options?.summary !== undefined) { - sessionService.setSummary(managed.session.id, options.summary); - } - - const endedAt = toIso(); - sessionService.end({ - sessionId: managed.session.id, - endedAt, - exitCode: options?.exitCode ?? null, - status - }); - - const endSha = await computeHeadShaBestEffort(managed.session.laneId).catch(() => null); - if (endSha) { - sessionService.setHeadShaEnd(managed.session.id, endSha); - } - - managed.session.status = "ended"; - managed.closed = true; - persistChatState(managed); - - try { - onSessionEnded?.({ laneId: managed.session.laneId, sessionId: managed.session.id, exitCode: options?.exitCode ?? null }); - } catch { - // ignore callback failures - } - }; - - const ensureManagedSession = (sessionId: string): ManagedChatSession => { - const existing = managedSessions.get(sessionId); - if (existing) return existing; - - const row = sessionService.get(sessionId); - if (!row) { - throw new Error(`Chat session '${sessionId}' was not found.`); - } - if (!isChatToolType(row.toolType)) { - throw new Error(`Session '${sessionId}' is not an agent chat session.`); - } - - const provider = providerFromToolType(row.toolType); - const persisted = readPersistedState(sessionId); - const model = persisted?.model ?? (provider === "codex" ? DEFAULT_CODEX_MODEL : DEFAULT_CLAUDE_MODEL); - const lane = laneService.getLaneBaseAndBranch(row.laneId); - - const managed: ManagedChatSession = { - session: { - id: sessionId, - laneId: row.laneId, - provider, - model, - status: mapTerminalStatusToChatStatus(row.status), - ...(persisted?.threadId ? { threadId: persisted.threadId } : {}), - createdAt: row.startedAt, - lastActivityAt: persisted?.updatedAt ?? row.endedAt ?? row.startedAt - }, - transcriptPath: row.transcriptPath || path.join(transcriptsDir, `${sessionId}.chat.jsonl`), - metadataPath: metadataPathFor(sessionId), - laneWorktreePath: lane.worktreePath, - runtime: null, - preview: row.lastOutputPreview ?? null, - closed: row.status !== "running", - endedNotified: row.status !== "running" - }; - - managedSessions.set(sessionId, managed); - return managed; - }; - - const sendCodexMessage = async (managed: ManagedChatSession, text: string, attachments: AgentChatFileRef[] = []): Promise => { - if (!managed.session.threadId) { - throw new Error(`Codex session '${managed.session.id}' is missing thread id.`); - } - if (!managed.runtime || managed.runtime.kind !== "codex") { - throw new Error(`Codex runtime is not available for session '${managed.session.id}'.`); - } - if (managed.runtime.activeTurnId) { - throw new Error("A turn is already active. Use steer or interrupt."); - } - - const input: Array> = [ - { - type: "text", - text, - text_elements: [] - } - ]; - - for (const attachment of attachments) { - if (attachment.type === "image") { - input.push({ type: "localImage", path: attachment.path }); - continue; - } - const name = path.basename(attachment.path) || attachment.path; - input.push({ type: "mention", name, path: attachment.path }); - } - - managed.session.status = "active"; - emitChatEvent(managed, { type: "user_message", text, attachments }); - - const result = await managed.runtime.request<{ turn?: { id?: string } }>("turn/start", { - threadId: managed.session.threadId, - input - }); - - const turnId = typeof result?.turn?.id === "string" ? result.turn.id : null; - if (turnId) { - managed.runtime.activeTurnId = turnId; - } - persistChatState(managed); - }; - - const runClaudeTurn = async (managed: ManagedChatSession, text: string, attachments: AgentChatFileRef[] = []): Promise => { - if (!managed.runtime || managed.runtime.kind !== "claude") { - throw new Error(`Claude runtime is not available for session '${managed.session.id}'.`); - } - - const runtime = managed.runtime; - if (runtime.busy) { - throw new Error("A turn is already active. Use steer or interrupt."); - } - - const turnId = randomUUID(); - runtime.busy = true; - runtime.activeTurnId = turnId; - runtime.interrupted = false; - managed.session.status = "active"; - - const attachmentHint = attachments.length - ? `\n\nAttached context:\n${attachments.map((file) => `- ${file.type}: ${file.path}`).join("\n")}` - : ""; - const userContent = `${text}${attachmentHint}`; - - runtime.messages.push({ role: "user", content: userContent }); - emitChatEvent(managed, { type: "user_message", text, attachments, turnId }); - emitChatEvent(managed, { type: "status", turnStatus: "started", turnId }); - - const chatConfig = resolveChatConfig(); - const abortController = new AbortController(); - runtime.abortController = abortController; - - let assistantText = ""; - let usage: { inputTokens?: number | null; outputTokens?: number | null } | undefined; - - const canUseTool = async (toolName: string, toolInput: unknown): Promise => { - const itemId = randomUUID(); - emitChatEvent(managed, { - type: "approval_request", - itemId, - kind: "tool_call", - description: `Tool '${toolName}' requests approval`, - detail: toolInput, - turnId - }); - - const decision = await new Promise((resolve) => { - runtime.approvals.set(itemId, { resolve }); - }); - runtime.approvals.delete(itemId); - - if (decision === "accept" || decision === "accept_for_session") { - return { behavior: "allow" }; - } - - return { - behavior: "deny", - message: `Tool '${toolName}' blocked by user decision.`, - interrupt: false - }; - }; - - try { - const stream = streamText({ - model: claudeProvider(resolveClaudeModel(managed.session.model), { - cwd: managed.laneWorktreePath, - permissionMode: chatConfig.claudePermissionMode, - settingSources: [], - maxBudgetUsd: chatConfig.sessionBudgetUsd ?? undefined, - canUseTool - } as any), - messages: runtime.messages.map((message) => ({ role: message.role, content: message.content })) as any, - abortSignal: abortController.signal - }); - - for await (const part of stream.fullStream as AsyncIterable) { - if (!part || typeof part !== "object") continue; - - if (part.type === "text-delta") { - const delta = String(part.text ?? ""); - if (!delta.length) continue; - assistantText += delta; - emitChatEvent(managed, { - type: "text", - text: delta, - turnId, - itemId: typeof part.id === "string" ? part.id : undefined - }); - continue; - } - - if (part.type === "reasoning-delta") { - const delta = String(part.text ?? ""); - if (!delta.length) continue; - emitChatEvent(managed, { - type: "reasoning", - text: delta, - turnId, - itemId: typeof part.id === "string" ? part.id : undefined - }); - continue; - } - - if (part.type === "tool-call") { - emitChatEvent(managed, { - type: "tool_call", - tool: String(part.toolName ?? "tool"), - args: part.input, - itemId: String(part.toolCallId ?? randomUUID()), - turnId - }); - continue; - } - - if (part.type === "tool-result") { - emitChatEvent(managed, { - type: "tool_result", - tool: String(part.toolName ?? "tool"), - result: part.output, - itemId: String(part.toolCallId ?? randomUUID()), - turnId, - status: part.preliminary ? "running" : "completed" - }); - continue; - } - - if (part.type === "tool-error") { - emitChatEvent(managed, { - type: "error", - message: `Tool '${String(part.toolName ?? "tool")}' failed: ${String(part.error ?? "unknown error")}`, - turnId, - itemId: String(part.toolCallId ?? randomUUID()) - }); - continue; - } - - if (part.type === "tool-approval-request") { - const itemId = String(part.approvalId ?? randomUUID()); - emitChatEvent(managed, { - type: "approval_request", - itemId, - kind: "tool_call", - description: `Approve tool '${String(part.toolCall?.toolName ?? "tool")}'`, - detail: part.toolCall, - turnId - }); - continue; - } - - if (part.type === "finish") { - const totalUsage = part.totalUsage as - | { - inputTokens?: number; - outputTokens?: number; - } - | undefined; - usage = { - inputTokens: totalUsage?.inputTokens ?? null, - outputTokens: totalUsage?.outputTokens ?? null - }; - continue; - } - - if (part.type === "error") { - emitChatEvent(managed, { - type: "error", - message: String(part.error ?? "Claude stream error."), - turnId - }); - } - } - - if (assistantText.trim().length) { - runtime.messages.push({ role: "assistant", content: assistantText }); - } - - runtime.busy = false; - runtime.activeTurnId = null; - runtime.abortController = null; - managed.session.status = "idle"; - - emitChatEvent(managed, { type: "status", turnStatus: "completed", turnId }); - emitChatEvent(managed, { - type: "done", - turnId, - status: "completed", - ...(usage ? { usage } : {}) - }); - - const endSha = await computeHeadShaBestEffort(managed.session.laneId).catch(() => null); - if (endSha) { - sessionService.setHeadShaEnd(managed.session.id, endSha); - } - - persistChatState(managed); - - if (runtime.pendingSteers.length) { - const steerText = runtime.pendingSteers.shift() ?? ""; - if (steerText.trim().length) { - await runClaudeTurn(managed, steerText, []); - } - } - } catch (error) { - runtime.busy = false; - runtime.activeTurnId = null; - runtime.abortController = null; - - if (runtime.interrupted) { - managed.session.status = "idle"; - emitChatEvent(managed, { type: "status", turnStatus: "interrupted", turnId }); - emitChatEvent(managed, { type: "done", turnId, status: "interrupted" }); - } else { - managed.session.status = "idle"; - emitChatEvent(managed, { - type: "error", - message: error instanceof Error ? error.message : String(error), - turnId - }); - emitChatEvent(managed, { type: "status", turnStatus: "failed", turnId }); - emitChatEvent(managed, { type: "done", turnId, status: "failed" }); - } - - persistChatState(managed); - } - }; - - const handleCodexServerRequest = (managed: ManagedChatSession, runtime: CodexRuntime, payload: JsonRpcEnvelope): void => { - const method = typeof payload.method === "string" ? payload.method : ""; - const id = payload.id; - if (id == null) return; - - if (method === "item/commandExecution/requestApproval") { - const params = (payload.params as { itemId?: string; command?: string; cwd?: string; reason?: string } | null) ?? {}; - const itemId = String(params.itemId ?? randomUUID()); - runtime.approvals.set(itemId, { requestId: id, kind: "command" }); - emitChatEvent(managed, { - type: "approval_request", - itemId, - kind: "command", - description: params.reason?.trim() || `Run command: ${params.command ?? "command"}`, - detail: { - command: params.command ?? null, - cwd: params.cwd ?? null, - reason: params.reason ?? null - }, - turnId: runtime.activeTurnId ?? undefined - }); - return; - } - - if (method === "item/fileChange/requestApproval") { - const params = (payload.params as { itemId?: string; reason?: string; grantRoot?: string } | null) ?? {}; - const itemId = String(params.itemId ?? randomUUID()); - runtime.approvals.set(itemId, { requestId: id, kind: "file_change" }); - emitChatEvent(managed, { - type: "approval_request", - itemId, - kind: "file_change", - description: params.reason?.trim() || "Approve file changes", - detail: { - grantRoot: params.grantRoot ?? null, - reason: params.reason ?? null - }, - turnId: runtime.activeTurnId ?? undefined - }); - return; - } - - runtime.sendError(id, `Unsupported server request: ${method || "unknown"}`); - }; - - const handleCodexItemEvent = ( - managed: ManagedChatSession, - runtime: CodexRuntime, - item: Record, - eventKind: "started" | "completed" - ): void => { - const itemId = String(item.id ?? randomUUID()); - const itemType = String(item.type ?? ""); - const turnId = runtime.activeTurnId ?? undefined; - - if (itemType === "commandExecution") { - const status = mapCommandStatus( - String(item.status ?? (eventKind === "completed" ? "completed" : "inProgress")) - ); - const output = String(item.aggregatedOutput ?? runtime.commandOutputByItemId.get(itemId) ?? ""); - runtime.commandOutputByItemId.set(itemId, output); - emitChatEvent(managed, { - type: "command", - command: String(item.command ?? "command"), - cwd: String(item.cwd ?? managed.laneWorktreePath), - output, - itemId, - turnId, - exitCode: typeof item.exitCode === "number" ? item.exitCode : null, - durationMs: typeof item.durationMs === "number" ? item.durationMs : null, - status - }); - return; - } - - if (itemType === "fileChange") { - const changes = Array.isArray(item.changes) - ? item.changes - .map((change) => { - if (!change || typeof change !== "object") return null; - const record = change as { path?: unknown; kind?: unknown; diff?: unknown }; - const filePath = typeof record.path === "string" ? record.path : ""; - if (!filePath) return null; - return { - path: filePath, - kind: mapFileChangeKind(record.kind), - diff: typeof record.diff === "string" ? record.diff : "" - }; - }) - .filter((entry): entry is { path: string; kind: "create" | "modify" | "delete"; diff: string } => entry != null) - : []; - - runtime.fileChangesByItemId.set(itemId, changes.map((change) => ({ path: change.path, kind: change.kind }))); - - const status = mapCommandStatus( - String(item.status ?? (eventKind === "completed" ? "completed" : "inProgress")) - ); - for (const change of changes) { - emitChatEvent(managed, { - type: "file_change", - path: change.path, - diff: change.diff || runtime.fileDeltaByItemId.get(itemId) || "", - kind: change.kind, - itemId, - turnId, - status - }); - } - return; - } - - if (itemType === "mcpToolCall") { - if (eventKind === "started") { - emitChatEvent(managed, { - type: "tool_call", - tool: String(item.tool ?? "tool"), - args: item.arguments, - itemId, - turnId - }); - } - if (eventKind === "completed") { - const status = String(item.status ?? "completed"); - emitChatEvent(managed, { - type: "tool_result", - tool: String(item.tool ?? "tool"), - result: status === "failed" ? item.error : item.result, - itemId, - turnId, - status: status === "failed" ? "failed" : "completed" - }); - } - } - }; - - const handleCodexNotification = async (managed: ManagedChatSession, runtime: CodexRuntime, payload: JsonRpcEnvelope): Promise => { - const method = typeof payload.method === "string" ? payload.method : ""; - const params = (payload.params as Record | null) ?? {}; - - if (method === "turn/started") { - const turn = (params.turn as { id?: unknown } | null) ?? null; - const turnId = typeof turn?.id === "string" ? turn.id : null; - runtime.activeTurnId = turnId; - managed.session.status = "active"; - emitChatEvent(managed, { - type: "status", - turnStatus: "started", - ...(turnId ? { turnId } : {}) - }); - persistChatState(managed); - return; - } - - if (method === "turn/completed") { - const turn = (params.turn as { id?: unknown; status?: unknown; error?: { message?: unknown; codexErrorInfo?: unknown } | null } | null) ?? null; - const turnId = typeof turn?.id === "string" ? turn.id : runtime.activeTurnId ?? randomUUID(); - runtime.activeTurnId = null; - const status = mapCodexTurnStatus(turn?.status); - managed.session.status = "idle"; - - if (status === "failed" && turn?.error?.message) { - emitChatEvent(managed, { - type: "error", - message: String(turn.error.message), - turnId, - errorInfo: formatCodexErrorInfo(turn.error.codexErrorInfo) - }); - } - - emitChatEvent(managed, { - type: "status", - turnStatus: status, - turnId, - ...(status === "failed" && turn?.error?.message - ? { message: String(turn.error.message) } - : {}) - }); - - emitChatEvent(managed, { type: "done", turnId, status }); - - const endSha = await computeHeadShaBestEffort(managed.session.laneId).catch(() => null); - if (endSha) { - sessionService.setHeadShaEnd(managed.session.id, endSha); - } - - persistChatState(managed); - return; - } - - if (method === "item/agentMessage/delta") { - const delta = String((params.delta as string | undefined) ?? ""); - if (!delta.length) return; - emitChatEvent(managed, { - type: "text", - text: delta, - turnId: typeof params.turnId === "string" ? params.turnId : undefined, - itemId: typeof params.itemId === "string" ? params.itemId : undefined - }); - return; - } - - if (method === "item/reasoning/summaryTextDelta" || method === "item/reasoning/textDelta") { - const delta = String((params.delta as string | undefined) ?? ""); - if (!delta.length) return; - emitChatEvent(managed, { - type: "reasoning", - text: delta, - turnId: typeof params.turnId === "string" ? params.turnId : undefined, - itemId: typeof params.itemId === "string" ? params.itemId : undefined, - summaryIndex: typeof params.summaryIndex === "number" ? params.summaryIndex : undefined - }); - return; - } - - if (method === "item/commandExecution/outputDelta") { - const itemId = String((params.itemId as string | undefined) ?? randomUUID()); - const delta = String((params.delta as string | undefined) ?? ""); - const next = `${runtime.commandOutputByItemId.get(itemId) ?? ""}${delta}`; - runtime.commandOutputByItemId.set(itemId, next); - emitChatEvent(managed, { - type: "command", - command: "command", - cwd: managed.laneWorktreePath, - output: delta, - itemId, - turnId: typeof params.turnId === "string" ? params.turnId : undefined, - status: "running" - }); - return; - } - - if (method === "item/fileChange/outputDelta") { - const itemId = String((params.itemId as string | undefined) ?? randomUUID()); - const delta = String((params.delta as string | undefined) ?? ""); - const next = `${runtime.fileDeltaByItemId.get(itemId) ?? ""}${delta}`; - runtime.fileDeltaByItemId.set(itemId, next); - - const knownChanges = runtime.fileChangesByItemId.get(itemId) ?? []; - if (knownChanges.length) { - for (const change of knownChanges) { - emitChatEvent(managed, { - type: "file_change", - path: change.path, - kind: change.kind, - diff: delta, - itemId, - turnId: typeof params.turnId === "string" ? params.turnId : undefined, - status: "running" - }); - } - } else { - emitChatEvent(managed, { - type: "file_change", - path: "(pending file)", - kind: "modify", - diff: delta, - itemId, - turnId: typeof params.turnId === "string" ? params.turnId : undefined, - status: "running" - }); - } - return; - } - - if (method === "turn/plan/updated") { - const plan = Array.isArray(params.plan) ? params.plan : []; - const steps = plan - .map((step) => { - if (!step || typeof step !== "object") return null; - const record = step as { step?: unknown; status?: unknown }; - const text = typeof record.step === "string" ? record.step : ""; - if (!text) return null; - const rawStatus = typeof record.status === "string" ? record.status : "pending"; - const mappedStatus = rawStatus === "completed" - ? "completed" - : rawStatus === "inProgress" - ? "in_progress" - : rawStatus === "failed" - ? "failed" - : "pending"; - return { - text, - status: mappedStatus - }; - }) - .filter((entry): entry is { text: string; status: "pending" | "in_progress" | "completed" | "failed" } => entry != null); - - emitChatEvent(managed, { - type: "plan", - steps, - turnId: typeof params.turnId === "string" ? params.turnId : undefined, - explanation: typeof params.explanation === "string" ? params.explanation : null - }); - return; - } - - if (method === "item/started") { - const item = (params.item as Record | null) ?? null; - if (!item) return; - handleCodexItemEvent(managed, runtime, item, "started"); - return; - } - - if (method === "item/completed") { - const item = (params.item as Record | null) ?? null; - if (!item) return; - handleCodexItemEvent(managed, runtime, item, "completed"); - return; - } - - if (method === "error") { - const error = (params.error as { message?: unknown; codexErrorInfo?: unknown } | null) ?? null; - emitChatEvent(managed, { - type: "error", - message: String(error?.message ?? "Codex app-server error."), - turnId: typeof params.turnId === "string" ? params.turnId : undefined, - errorInfo: formatCodexErrorInfo(error?.codexErrorInfo) - }); - } - }; - - const startCodexRuntime = async (managed: ManagedChatSession): Promise => { - const proc = spawn("codex", ["app-server"], { - cwd: managed.laneWorktreePath, - stdio: ["pipe", "pipe", "pipe"] - }); - - const reader = readline.createInterface({ input: proc.stdout }); - const pending = new Map(); - - const runtime: CodexRuntime = { - kind: "codex", - process: proc, - reader, - nextRequestId: 1, - pending, - approvals: new Map(), - activeTurnId: null, - commandOutputByItemId: new Map(), - fileDeltaByItemId: new Map(), - fileChangesByItemId: new Map>(), - request: async (method: string, params?: unknown): Promise => { - const id = runtime.nextRequestId; - runtime.nextRequestId += 1; - - const payload: JsonRpcEnvelope = { - jsonrpc: "2.0", - id, - method, - ...(params !== undefined ? { params } : {}) - }; - - if (!proc.stdin.writable) { - throw new Error("Codex app-server stdin is not writable."); - } - - return new Promise((resolve, reject) => { - pending.set(String(id), { resolve, reject }); - proc.stdin.write(`${JSON.stringify(payload)}\n`); - }); - }, - notify: (method: string, params?: unknown) => { - if (!proc.stdin.writable) return; - const payload: JsonRpcEnvelope = { - jsonrpc: "2.0", - method, - ...(params !== undefined ? { params } : {}) - }; - proc.stdin.write(`${JSON.stringify(payload)}\n`); - }, - sendResponse: (id: string | number, result: unknown) => { - if (!proc.stdin.writable) return; - proc.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, result })}\n`); - }, - sendError: (id: string | number, message: string) => { - if (!proc.stdin.writable) return; - proc.stdin.write( - `${JSON.stringify({ jsonrpc: "2.0", id, error: { code: -32001, message } })}\n` - ); - } - }; - - reader.on("line", (line) => { - const payload = parseJsonLine(line); - if (!payload) return; - - if (payload.method && payload.id != null) { - handleCodexServerRequest(managed, runtime, payload); - return; - } - - if (payload.method) { - void handleCodexNotification(managed, runtime, payload).catch((error) => { - logger.warn("agent_chat.codex_notification_failed", { - sessionId: managed.session.id, - method: payload.method, - error: error instanceof Error ? error.message : String(error) - }); - }); - return; - } - - if (payload.id != null) { - const key = String(payload.id); - const request = pending.get(key); - if (!request) return; - pending.delete(key); - - if (payload.error) { - request.reject(new Error(payload.error.message || "Codex request failed.")); - return; - } - - request.resolve(payload.result); - } - }); - - proc.stderr.on("data", (chunk: Buffer) => { - const text = chunk.toString("utf8").trim(); - if (!text.length) return; - logger.warn("agent_chat.codex_stderr", { - sessionId: managed.session.id, - line: text - }); - }); - - proc.on("exit", (code, signal) => { - const message = `Codex app-server exited (code=${code ?? "null"}, signal=${signal ?? "null"}).`; - - for (const request of pending.values()) { - request.reject(new Error(message)); - } - pending.clear(); - - runtime.approvals.clear(); - - if (managed.closed || managed.session.status === "ended") return; - - emitChatEvent(managed, { - type: "error", - message - }); - - void finishSession(managed, "failed", { - summary: message, - exitCode: code ?? null - }).catch(() => {}); - }); - - await runtime.request("initialize", { - clientInfo: { - name: "ade", - title: "ADE", - version: appVersion - }, - capabilities: { - experimentalApi: true - } - }); - - runtime.notify("initialized"); - return runtime; - }; - - const ensureCodexSessionRuntime = async (managed: ManagedChatSession): Promise => { - if (managed.runtime?.kind === "codex") return managed.runtime; - const runtime = await startCodexRuntime(managed); - managed.runtime = runtime; - return runtime; - }; - - const ensureClaudeSessionRuntime = (managed: ManagedChatSession): ClaudeRuntime => { - if (managed.runtime?.kind === "claude") return managed.runtime; - - const persisted = readPersistedState(managed.session.id); - const runtime: ClaudeRuntime = { - kind: "claude", - messages: persisted?.messages ?? [], - busy: false, - abortController: null, - activeTurnId: null, - pendingSteers: [], - approvals: new Map(), - interrupted: false - }; - - managed.runtime = runtime; - return runtime; - }; - - const listCodexModelsFromAppServer = async (): Promise => { - const tempSession: ManagedChatSession = { - session: { - id: randomUUID(), - laneId: "temporary", - provider: "codex", - model: DEFAULT_CODEX_MODEL, - status: "idle", - createdAt: toIso(), - lastActivityAt: toIso() - }, - transcriptPath: path.join(transcriptsDir, `${randomUUID()}.chat.jsonl`), - metadataPath: metadataPathFor(randomUUID()), - laneWorktreePath: projectRoot, - runtime: null, - preview: null, - closed: false, - endedNotified: false - }; - - let runtime: CodexRuntime | null = null; - - try { - runtime = await startCodexRuntime(tempSession); - const response = await runtime.request<{ data?: Array> }>("model/list", {}); - const rows = Array.isArray(response?.data) ? response.data : []; - const models = rows - .map((row) => { - const id = typeof row.id === "string" ? row.id.trim() : ""; - if (!id) return null; - - const displayName = typeof row.displayName === "string" && row.displayName.trim().length - ? row.displayName.trim() - : id; - const isDefault = Boolean(row.isDefault); - - const reasoningEfforts = Array.isArray(row.supportedReasoningEfforts) - ? row.supportedReasoningEfforts - .map((entry) => { - if (!entry || typeof entry !== "object") return null; - const effort = typeof (entry as { reasoningEffort?: unknown }).reasoningEffort === "string" - ? String((entry as { reasoningEffort?: unknown }).reasoningEffort) - : ""; - const description = typeof (entry as { description?: unknown }).description === "string" - ? String((entry as { description?: unknown }).description) - : ""; - if (!effort) return null; - return { effort, description }; - }) - .filter((entry): entry is { effort: string; description: string } => entry != null) - : undefined; - - return { - id, - displayName, - isDefault, - ...(reasoningEfforts?.length ? { reasoningEfforts } : {}) - } satisfies AgentChatModelInfo; - }) - .filter((entry): entry is AgentChatModelInfo => entry != null); - - if (models.length) return models; - return CODEX_FALLBACK_MODELS; - } catch { - return CODEX_FALLBACK_MODELS; - } finally { - // This throwaway runtime is not a tracked session; suppress exit-side lifecycle hooks. - tempSession.closed = true; - tempSession.endedNotified = true; - tempSession.session.status = "ended"; - try { - runtime?.reader.close(); - } catch { - // ignore - } - try { - runtime?.process.kill(); - } catch { - // ignore - } - } - }; - - const listClaudeModelsFromSdk = async (): Promise => { - try { - const session = unstable_v2_createSession({ - model: CLAUDE_ALIAS_TO_MODEL.sonnet, - permissionMode: "plan" - }) as unknown as { - supportedModels?: () => Promise; - close: () => void; - }; - - try { - if (typeof session.supportedModels !== "function") { - return CLAUDE_FALLBACK_MODELS; - } - - const discovered = await session.supportedModels(); - const mapped = discovered - .map((entry): AgentChatModelInfo | null => { - const id = String(entry.value ?? "").trim(); - if (!id.length) return null; - const displayName = String(entry.displayName ?? entry.value ?? id).trim() || id; - return { - id, - displayName, - isDefault: id === CLAUDE_ALIAS_TO_MODEL.sonnet - }; - }) - .filter((entry): entry is AgentChatModelInfo => entry != null); - - if (mapped.length) { - if (!mapped.some((entry) => entry.isDefault)) { - const preferredIdx = mapped.findIndex((entry) => /sonnet/i.test(entry.id) || /sonnet/i.test(entry.displayName)); - if (preferredIdx >= 0) { - mapped[preferredIdx] = { ...mapped[preferredIdx]!, isDefault: true }; - } else { - mapped[0] = { ...mapped[0]!, isDefault: true }; - } - } - return mapped; - } - } finally { - session.close(); - } - } catch { - // fall back below - } - - return CLAUDE_FALLBACK_MODELS; - }; - - const createSession = async ({ laneId, provider, model }: AgentChatCreateArgs): Promise => { - const lane = laneService.getLaneBaseAndBranch(laneId); - const sessionId = randomUUID(); - const startedAt = toIso(); - const transcriptPath = path.join(transcriptsDir, `${sessionId}.chat.jsonl`); - const metadataPath = metadataPathFor(sessionId); - - fs.mkdirSync(path.dirname(transcriptPath), { recursive: true }); - - const normalizedModel = model.trim() || (provider === "codex" ? DEFAULT_CODEX_MODEL : DEFAULT_CLAUDE_MODEL); - - sessionService.create({ - sessionId, - laneId, - ptyId: null, - tracked: true, - title: provider === "codex" ? "Codex Chat" : "Claude Chat", - startedAt, - transcriptPath, - toolType: toolTypeFromProvider(provider), - resumeCommand: provider === "codex" ? "chat:codex" : `chat:claude:${sessionId}` - }); - - const managed: ManagedChatSession = { - session: { - id: sessionId, - laneId, - provider, - model: normalizedModel, - status: "idle", - createdAt: startedAt, - lastActivityAt: startedAt - }, - transcriptPath, - metadataPath, - laneWorktreePath: lane.worktreePath, - runtime: null, - preview: null, - closed: false, - endedNotified: false - }; - - managedSessions.set(sessionId, managed); - - const headStart = await computeHeadShaBestEffort(laneId).catch(() => null); - if (headStart) { - sessionService.setHeadShaStart(sessionId, headStart); - } - - try { - if (provider === "codex") { - const runtime = await ensureCodexSessionRuntime(managed); - const config = resolveChatConfig(); - const response = await runtime.request<{ - thread?: { id?: string }; - model?: string; - }>("thread/start", { - model: normalizedModel, - cwd: lane.worktreePath, - approvalPolicy: config.codexApprovalPolicy, - sandbox: config.codexSandboxMode, - experimentalRawEvents: false, - persistExtendedHistory: true - }); - - const threadId = typeof response.thread?.id === "string" ? response.thread.id : undefined; - if (threadId) { - managed.session.threadId = threadId; - sessionService.setResumeCommand(sessionId, `chat:codex:${threadId}`); - } - } else { - ensureClaudeSessionRuntime(managed); - } - - persistChatState(managed); - return managed.session; - } catch (error) { - await finishSession(managed, "failed", { - summary: error instanceof Error ? error.message : String(error) - }).catch(() => {}); - throw error; - } - }; - - const sendMessage = async ({ sessionId, text, attachments = [] }: AgentChatSendArgs): Promise => { - const trimmed = text.trim(); - if (!trimmed.length) return; - - const managed = ensureManagedSession(sessionId); - - if (managed.session.status === "ended") { - sessionService.reopen(sessionId); - managed.session.status = "idle"; - managed.closed = false; - managed.endedNotified = false; - } - - if (managed.session.provider === "codex") { - const runtime = await ensureCodexSessionRuntime(managed); - if (!managed.session.threadId) { - const persisted = readPersistedState(sessionId); - const threadId = persisted?.threadId; - if (threadId) { - const config = resolveChatConfig(); - await runtime.request("thread/resume", { - threadId, - model: managed.session.model, - cwd: managed.laneWorktreePath, - approvalPolicy: config.codexApprovalPolicy, - sandbox: config.codexSandboxMode, - persistExtendedHistory: true - }); - managed.session.threadId = threadId; - } - } - - await sendCodexMessage(managed, trimmed, attachments); - return; - } - - ensureClaudeSessionRuntime(managed); - await runClaudeTurn(managed, trimmed, attachments); - }; - - const steer = async ({ sessionId, text }: AgentChatSteerArgs): Promise => { - const trimmed = text.trim(); - if (!trimmed.length) return; - - const managed = ensureManagedSession(sessionId); - - if (managed.session.provider === "codex") { - const runtime = await ensureCodexSessionRuntime(managed); - if (!managed.session.threadId || !runtime.activeTurnId) { - throw new Error("No active turn to steer."); - } - - emitChatEvent(managed, { - type: "user_message", - text: trimmed, - turnId: runtime.activeTurnId - }); - - await runtime.request("turn/steer", { - threadId: managed.session.threadId, - expectedTurnId: runtime.activeTurnId, - input: [ - { - type: "text", - text: trimmed, - text_elements: [] - } - ] - }); - return; - } - - const runtime = ensureClaudeSessionRuntime(managed); - if (runtime.busy) { - runtime.pendingSteers.push(trimmed); - emitChatEvent(managed, { - type: "user_message", - text: trimmed, - turnId: runtime.activeTurnId ?? undefined - }); - persistChatState(managed); - return; - } - - await runClaudeTurn(managed, trimmed, []); - }; - - const interrupt = async ({ sessionId }: AgentChatInterruptArgs): Promise => { - const managed = ensureManagedSession(sessionId); - - if (managed.session.provider === "codex") { - const runtime = await ensureCodexSessionRuntime(managed); - if (!managed.session.threadId || !runtime.activeTurnId) return; - await runtime.request("turn/interrupt", { - threadId: managed.session.threadId, - turnId: runtime.activeTurnId - }); - return; - } - - const runtime = ensureClaudeSessionRuntime(managed); - runtime.interrupted = true; - runtime.abortController?.abort(); - }; - - const resumeSession = async ({ sessionId }: { sessionId: string }): Promise => { - const managed = ensureManagedSession(sessionId); - const persisted = readPersistedState(sessionId); - - if (managed.session.provider === "codex") { - const runtime = await ensureCodexSessionRuntime(managed); - const config = resolveChatConfig(); - const threadId = persisted?.threadId ?? managed.session.threadId; - if (threadId) { - await runtime.request("thread/resume", { - threadId, - model: managed.session.model, - cwd: managed.laneWorktreePath, - approvalPolicy: config.codexApprovalPolicy, - sandbox: config.codexSandboxMode, - persistExtendedHistory: true - }); - managed.session.threadId = threadId; - sessionService.setResumeCommand(sessionId, `chat:codex:${threadId}`); - } - } else { - const runtime = ensureClaudeSessionRuntime(managed); - runtime.messages = persisted?.messages ?? runtime.messages; - sessionService.setResumeCommand(sessionId, `chat:claude:${sessionId}`); - } - - sessionService.reopen(sessionId); - managed.session.status = "idle"; - managed.closed = false; - managed.endedNotified = false; - - persistChatState(managed); - return managed.session; - }; - - const listSessions = async (laneId?: string): Promise => { - const rows = sessionService.list({ ...(laneId ? { laneId } : {}), limit: 500 }); - const chatRows = rows.filter((row) => isChatToolType(row.toolType)); - - return chatRows.map((row) => { - const persisted = readPersistedState(row.id); - const provider = providerFromToolType(row.toolType); - return { - sessionId: row.id, - laneId: row.laneId, - provider, - model: persisted?.model ?? (provider === "codex" ? DEFAULT_CODEX_MODEL : DEFAULT_CLAUDE_MODEL), - status: row.status === "running" ? "idle" : "ended", - startedAt: row.startedAt, - endedAt: row.endedAt, - lastActivityAt: persisted?.updatedAt ?? row.endedAt ?? row.startedAt, - lastOutputPreview: row.lastOutputPreview, - summary: row.summary, - ...(persisted?.threadId ? { threadId: persisted.threadId } : {}) - } satisfies AgentChatSessionSummary; - }); - }; - - const approveToolUse = async ({ sessionId, itemId, decision }: { sessionId: string; itemId: string; decision: AgentChatApprovalDecision }): Promise => { - const managed = ensureManagedSession(sessionId); - - if (managed.runtime?.kind === "codex") { - const pending = managed.runtime.approvals.get(itemId); - if (!pending) { - throw new Error(`No pending approval found for item '${itemId}'.`); - } - - const mapped = mapApprovalDecisionForCodex(decision); - if (pending.kind === "command") { - managed.runtime.sendResponse(pending.requestId, { decision: mapped }); - } else { - managed.runtime.sendResponse(pending.requestId, { decision: mapped }); - } - managed.runtime.approvals.delete(itemId); - return; - } - - if (managed.runtime?.kind === "claude") { - const pending = managed.runtime.approvals.get(itemId); - if (!pending) { - throw new Error(`No pending approval found for item '${itemId}'.`); - } - managed.runtime.approvals.delete(itemId); - pending.resolve(decision); - return; - } - - throw new Error(`Session '${sessionId}' does not have a live runtime for approvals.`); - }; - - const getAvailableModels = async ({ provider }: { provider: AgentChatProvider }): Promise => { - if (provider === "codex") { - return listCodexModelsFromAppServer(); - } - return listClaudeModelsFromSdk(); - }; - - const dispose = async ({ sessionId }: AgentChatDisposeArgs): Promise => { - const managed = ensureManagedSession(sessionId); - let clearClaudeRuntimeAfterFinish = false; - - if (managed.runtime?.kind === "codex") { - try { - if (managed.session.threadId && managed.runtime.activeTurnId) { - await managed.runtime.request("turn/interrupt", { - threadId: managed.session.threadId, - turnId: managed.runtime.activeTurnId - }); - } - } catch { - // ignore interrupt failures while disposing - } - - try { - managed.runtime.reader.close(); - } catch { - // ignore - } - try { - managed.runtime.process.kill(); - } catch { - // ignore - } - managed.runtime.pending.clear(); - managed.runtime.approvals.clear(); - managed.runtime = null; - } - - if (managed.runtime?.kind === "claude") { - managed.runtime.interrupted = true; - managed.runtime.abortController?.abort(); - for (const pending of managed.runtime.approvals.values()) { - pending.resolve("cancel"); - } - managed.runtime.approvals.clear(); - clearClaudeRuntimeAfterFinish = true; - } - - await finishSession(managed, "disposed", { - summary: managed.preview ? `Session closed: ${managed.preview}` : "Session closed." - }); - - if (clearClaudeRuntimeAfterFinish) { - managed.runtime = null; - } - }; - - const disposeAll = async (): Promise => { - for (const sessionId of [...managedSessions.keys()]) { - try { - await dispose({ sessionId }); - } catch { - // ignore shutdown errors - } - } - }; - - return { - createSession, - sendMessage, - steer, - interrupt, - resumeSession, - listSessions, - approveToolUse, - getAvailableModels, - dispose, - disposeAll - }; -} diff --git a/apps/desktop/src/main/services/config/projectConfigService.ts b/apps/desktop/src/main/services/config/projectConfigService.ts index c14cdd67e..3ad9c956e 100644 --- a/apps/desktop/src/main/services/config/projectConfigService.ts +++ b/apps/desktop/src/main/services/config/projectConfigService.ts @@ -4,10 +4,6 @@ import { createHash } from "node:crypto"; import YAML from "yaml"; import cron from "node-cron"; import type { - AiConfig, - AiFeatureKey, - AiTaskRoutingKey, - AiTaskRoutingRule, AutomationAction, AutomationActionType, AutomationRule, @@ -293,250 +289,6 @@ function coerceLaneOverlayPolicy(value: unknown): ConfigLaneOverlayPolicy | null return out; } -const AI_TASK_KEYS: AiTaskRoutingKey[] = [ - "planning", - "implementation", - "review", - "conflict_resolution", - "narrative", - "pr_description", - "terminal_summary", - "mission_planning", - "initial_context" -]; - -const AI_FEATURE_KEYS: AiFeatureKey[] = [ - "narratives", - "conflict_proposals", - "pr_descriptions", - "terminal_summaries", - "mission_planning", - "orchestrator", - "initial_context" -]; - -function coerceAiTaskRoutingRule(value: unknown): AiTaskRoutingRule | null { - if (!isRecord(value)) return null; - const providerRaw = asString(value.provider)?.trim().toLowerCase(); - const provider = - providerRaw === "auto" || providerRaw === "claude" || providerRaw === "codex" - ? providerRaw - : undefined; - const model = asString(value.model); - const timeoutMs = asNumber(value.timeoutMs) ?? asNumber(value.timeout_ms); - const maxOutputTokens = asNumber(value.maxOutputTokens) ?? asNumber(value.max_output_tokens); - const temperature = asNumber(value.temperature); - - const out: AiTaskRoutingRule = {}; - if (provider) out.provider = provider; - if (model != null) out.model = model; - if (timeoutMs != null) out.timeoutMs = timeoutMs; - if (maxOutputTokens != null) out.maxOutputTokens = maxOutputTokens; - if (temperature != null) out.temperature = temperature; - - return Object.keys(out).length ? out : null; -} - -function coerceAiConfig(value: unknown): AiConfig | undefined { - if (!isRecord(value)) return undefined; - - const out: AiConfig = {}; - const mode = asString(value.mode)?.trim(); - if (mode === "guest" || mode === "subscription" || mode === "hosted" || mode === "byok" || mode === "cli") { - out.mode = mode; - } - - const defaultProvider = (asString(value.defaultProvider) ?? asString(value.default_provider))?.trim().toLowerCase(); - if (defaultProvider === "auto" || defaultProvider === "claude" || defaultProvider === "codex") { - out.defaultProvider = defaultProvider; - } - - const taskRoutingRaw = isRecord(value.taskRouting) - ? value.taskRouting - : isRecord(value.task_routing) - ? value.task_routing - : null; - if (taskRoutingRaw) { - const routing: Partial> = {}; - for (const taskKey of AI_TASK_KEYS) { - const rule = coerceAiTaskRoutingRule(taskRoutingRaw[taskKey]); - if (rule) routing[taskKey] = rule; - } - if (Object.keys(routing).length) out.taskRouting = routing; - } - - const featuresRaw = isRecord(value.features) ? value.features : null; - if (featuresRaw) { - const features: Partial> = {}; - for (const key of AI_FEATURE_KEYS) { - const bool = asBool(featuresRaw[key]); - if (bool != null) features[key] = bool; - } - if (Object.keys(features).length) out.features = features; - } - - const budgetsRaw = isRecord(value.budgets) ? value.budgets : null; - if (budgetsRaw) { - const budgets: NonNullable = {}; - for (const key of AI_FEATURE_KEYS) { - const entry = isRecord(budgetsRaw[key]) ? budgetsRaw[key] : null; - if (!entry) continue; - const dailyLimit = asNumber(entry.dailyLimit) ?? asNumber(entry.daily_limit); - if (dailyLimit == null) continue; - budgets[key] = { dailyLimit }; - } - if (Object.keys(budgets).length) out.budgets = budgets; - } - - const permissionsRaw = isRecord(value.permissions) ? value.permissions : null; - if (permissionsRaw) { - const permissions: NonNullable = {}; - const claude = isRecord(permissionsRaw.claude) ? permissionsRaw.claude : null; - if (claude) { - const entry: NonNullable["claude"]> = {}; - const permissionMode = (asString(claude.permissionMode) ?? asString(claude.permission_mode))?.trim(); - if (permissionMode === "default" || permissionMode === "acceptEdits" || permissionMode === "bypassPermissions" || permissionMode === "plan") { - entry.permissionMode = permissionMode; - } - const settingsSources = Array.isArray(claude.settingsSources) - ? claude.settingsSources - : Array.isArray(claude.settings_sources) - ? claude.settings_sources - : null; - if (settingsSources) { - const normalized = settingsSources - .map((item) => String(item).trim()) - .filter((item): item is "user" | "project" | "local" => item === "user" || item === "project" || item === "local"); - if (normalized.length) entry.settingsSources = normalized; - } - const maxBudgetUsd = asNumber(claude.maxBudgetUsd) ?? asNumber(claude.max_budget_usd); - if (maxBudgetUsd != null) entry.maxBudgetUsd = maxBudgetUsd; - const sandbox = asBool(claude.sandbox); - if (sandbox != null) entry.sandbox = sandbox; - if (Object.keys(entry).length) permissions.claude = entry; - } - - const codex = isRecord(permissionsRaw.codex) ? permissionsRaw.codex : null; - if (codex) { - const entry: NonNullable["codex"]> = {}; - const sandboxPermissions = (asString(codex.sandboxPermissions) ?? asString(codex.sandbox_permissions))?.trim(); - if (sandboxPermissions === "read-only" || sandboxPermissions === "workspace-write" || sandboxPermissions === "danger-full-access") { - entry.sandboxPermissions = sandboxPermissions; - } - const approvalMode = (asString(codex.approvalMode) ?? asString(codex.approval_mode))?.trim(); - if (approvalMode === "untrusted" || approvalMode === "on-request" || approvalMode === "on-failure" || approvalMode === "never") { - entry.approvalMode = approvalMode; - } - const writablePaths = asStringArray(codex.writablePaths) ?? asStringArray(codex.writable_paths); - if (writablePaths?.length) entry.writablePaths = writablePaths; - const commandAllowlist = asStringArray(codex.commandAllowlist) ?? asStringArray(codex.command_allowlist); - if (commandAllowlist?.length) entry.commandAllowlist = commandAllowlist; - if (Object.keys(entry).length) permissions.codex = entry; - } - - if (Object.keys(permissions).length) out.permissions = permissions; - } - - const conflictRaw = isRecord(value.conflictResolution) - ? value.conflictResolution - : isRecord(value.conflict_resolution) - ? value.conflict_resolution - : null; - if (conflictRaw) { - const conflict: NonNullable = {}; - const changeTarget = (asString(conflictRaw.changeTarget) ?? asString(conflictRaw.change_target))?.trim(); - if (changeTarget === "target" || changeTarget === "source" || changeTarget === "ai_decides") { - conflict.changeTarget = changeTarget; - } - const postResolution = (asString(conflictRaw.postResolution) ?? asString(conflictRaw.post_resolution))?.trim(); - if (postResolution === "unstaged" || postResolution === "staged" || postResolution === "commit") { - conflict.postResolution = postResolution; - } - const prBehavior = (asString(conflictRaw.prBehavior) ?? asString(conflictRaw.pr_behavior))?.trim(); - if (prBehavior === "do_nothing" || prBehavior === "open_pr" || prBehavior === "add_to_existing") { - conflict.prBehavior = prBehavior; - } - const autonomy = asString(conflictRaw.autonomy)?.trim(); - if (autonomy === "propose_only" || autonomy === "auto_apply") { - conflict.autonomy = autonomy; - } - const threshold = asNumber(conflictRaw.autoApplyThreshold) ?? asNumber(conflictRaw.auto_apply_threshold); - if (threshold != null) conflict.autoApplyThreshold = threshold; - if (Object.keys(conflict).length) out.conflictResolution = conflict; - } - - const chatRaw = isRecord(value.chat) ? value.chat : null; - if (chatRaw) { - const chat: NonNullable = {}; - const defaultProvider = (asString(chatRaw.defaultProvider) ?? asString(chatRaw.default_provider))?.trim(); - if (defaultProvider === "codex" || defaultProvider === "claude" || defaultProvider === "last_used") { - chat.defaultProvider = defaultProvider; - } - const approvalPolicy = (asString(chatRaw.defaultApprovalPolicy) ?? asString(chatRaw.default_approval_policy))?.trim(); - if (approvalPolicy === "auto" || approvalPolicy === "approve_mutations" || approvalPolicy === "approve_all") { - chat.defaultApprovalPolicy = approvalPolicy; - } - const sendOnEnter = asBool(chatRaw.sendOnEnter) ?? asBool(chatRaw.send_on_enter); - if (sendOnEnter != null) { - chat.sendOnEnter = sendOnEnter; - } - const codexSandbox = (asString(chatRaw.codexSandbox) ?? asString(chatRaw.codex_sandbox))?.trim(); - if (codexSandbox === "read-only" || codexSandbox === "workspace-write" || codexSandbox === "danger-full-access") { - chat.codexSandbox = codexSandbox; - } - const claudePermissionMode = (asString(chatRaw.claudePermissionMode) ?? asString(chatRaw.claude_permission_mode))?.trim(); - if (claudePermissionMode === "plan" || claudePermissionMode === "acceptEdits" || claudePermissionMode === "bypassPermissions") { - chat.claudePermissionMode = claudePermissionMode; - } - const sessionBudgetUsd = asNumber(chatRaw.sessionBudgetUsd) ?? asNumber(chatRaw.session_budget_usd); - if (sessionBudgetUsd != null) { - chat.sessionBudgetUsd = sessionBudgetUsd; - } - if (Object.keys(chat).length) out.chat = chat; - } - - return Object.keys(out).length ? out : undefined; -} - -function mergeAiConfig(sharedAi?: AiConfig, localAi?: AiConfig): AiConfig | undefined { - if (!sharedAi && !localAi) return undefined; - const taskRouting: Partial> = { - ...(sharedAi?.taskRouting ?? {}), - ...(localAi?.taskRouting ?? {}) - }; - const features = { - ...(sharedAi?.features ?? {}), - ...(localAi?.features ?? {}) - }; - const budgets = { - ...(sharedAi?.budgets ?? {}), - ...(localAi?.budgets ?? {}) - }; - const permissions = { - ...(sharedAi?.permissions ?? {}), - ...(localAi?.permissions ?? {}) - }; - const conflictResolution = { - ...(sharedAi?.conflictResolution ?? {}), - ...(localAi?.conflictResolution ?? {}) - }; - const chat = { - ...(sharedAi?.chat ?? {}), - ...(localAi?.chat ?? {}) - }; - const out: AiConfig = { - mode: localAi?.mode ?? sharedAi?.mode, - defaultProvider: localAi?.defaultProvider ?? sharedAi?.defaultProvider, - ...(Object.keys(taskRouting).length ? { taskRouting } : {}), - ...(Object.keys(features).length ? { features } : {}), - ...(Object.keys(budgets).length ? { budgets } : {}), - ...(Object.keys(permissions).length ? { permissions } : {}), - ...(Object.keys(conflictResolution).length ? { conflictResolution } : {}), - ...(Object.keys(chat).length ? { chat } : {}) - }; - return Object.keys(out).length ? out : undefined; -} - function coerceConfigFile(value: unknown): ProjectConfigFile { if (!isRecord(value)) { return { version: VERSION, processes: [], stackButtons: [], testSuites: [], laneOverlayPolicies: [], automations: [] }; @@ -580,12 +332,6 @@ function coerceConfigFile(value: unknown): ProjectConfigFile { } : undefined; - const ai = - coerceAiConfig((value as Record).ai) ?? - (isRecord((value as Record).providers) - ? coerceAiConfig(((value as Record).providers as Record).ai) - : undefined); - return { version, processes, @@ -596,7 +342,6 @@ function coerceConfigFile(value: unknown): ProjectConfigFile { ...(environments.length ? { environments } : {}), ...(github ? { github } : {}), ...(git ? { git } : {}), - ...(ai ? { ai } : {}), ...(isRecord(value.providers) ? { providers: value.providers } : {}) }; } @@ -634,7 +379,6 @@ function toCanonicalYaml(config: ProjectConfigFile): string { ...(config.environments ? { environments: config.environments } : {}), ...(config.github ? { github: config.github } : {}), ...(config.git ? { git: config.git } : {}), - ...(config.ai ? { ai: config.ai } : {}), ...(config.providers ? { providers: config.providers } : {}) }; return YAML.stringify(normalized, { indent: 2 }); @@ -814,26 +558,11 @@ function resolveEffectiveConfig(shared: ProjectConfigFile, local: ProjectConfigF } : undefined; - const mergedAi = mergeAiConfig(shared.ai, local.ai); - const environments = [...(shared.environments ?? []), ...(local.environments ?? [])]; - const legacyModeRaw = typeof mergedProviders?.mode === "string" ? String(mergedProviders.mode).trim().toLowerCase() : ""; - const aiModeRaw = typeof mergedAi?.mode === "string" ? String(mergedAi.mode).trim().toLowerCase() : ""; - const providerMode: ProviderMode = (() => { - const resolved = aiModeRaw || legacyModeRaw; - if (resolved === "guest") return "guest"; - if (resolved === "subscription") return "subscription"; - if (resolved === "hosted" || resolved === "byok" || resolved === "cli") return "subscription"; - return "guest"; - })(); - - const effectiveAi = mergedAi - ? { - ...mergedAi, - mode: providerMode - } - : undefined; + const modeRaw = typeof mergedProviders?.mode === "string" ? mergedProviders.mode : undefined; + const providerMode: ProviderMode = + modeRaw === "hosted" || modeRaw === "byok" || modeRaw === "cli" || modeRaw === "guest" ? modeRaw : "guest"; return { version: VERSION, @@ -848,7 +577,6 @@ function resolveEffectiveConfig(shared: ProjectConfigFile, local: ProjectConfigF git: { autoRebaseOnHeadChange: mergedGit?.autoRebaseOnHeadChange ?? false }, - ...(effectiveAi ? { ai: effectiveAi } : {}), ...(mergedProviders ? { providers: mergedProviders } : {}) }; } diff --git a/apps/desktop/src/main/services/ipc/registerIpc.ts b/apps/desktop/src/main/services/ipc/registerIpc.ts index 50c2c14e7..d32e4ac1e 100644 --- a/apps/desktop/src/main/services/ipc/registerIpc.ts +++ b/apps/desktop/src/main/services/ipc/registerIpc.ts @@ -102,18 +102,6 @@ import type { HostedSignInArgs, HostedSignInResult, HostedStatus, - AgentChatApproveArgs, - AgentChatCreateArgs, - AgentChatDisposeArgs, - AgentChatInterruptArgs, - AgentChatListArgs, - AgentChatModelInfo, - AgentChatModelsArgs, - AgentChatResumeArgs, - AgentChatSendArgs, - AgentChatSession, - AgentChatSessionSummary, - AgentChatSteerArgs, AgentTool, KeybindingOverride, KeybindingsSnapshot, @@ -257,13 +245,11 @@ import type { createPackService } from "../packs/packService"; import type { createOperationService } from "../history/operationService"; import type { createConflictService } from "../conflicts/conflictService"; import type { createJobEngine } from "../jobs/jobEngine"; -import type { createAiIntegrationService } from "../ai/aiIntegrationService"; import type { createHostedAgentService } from "../hosted/hostedAgentService"; import type { createGithubService } from "../github/githubService"; import type { createPrService } from "../prs/prService"; import type { createPrPollingService } from "../prs/prPollingService"; import type { createByokLlmService } from "../byok/byokLlmService"; -import type { createAgentChatService } from "../chat/agentChatService"; import { readGlobalState, writeGlobalState } from "../state/globalState"; import type { createKeybindingsService } from "../keybindings/keybindingsService"; import type { createTerminalProfilesService } from "../terminalProfiles/terminalProfilesService"; @@ -299,10 +285,8 @@ export type AppContext = { operationService: ReturnType; gitService: ReturnType; conflictService: ReturnType; - aiIntegrationService: ReturnType; hostedAgentService: ReturnType; byokLlmService: ReturnType; - agentChatService: ReturnType; githubService: ReturnType; prService: ReturnType; prPollingService: ReturnType; @@ -1630,52 +1614,6 @@ export function registerIpc({ return ctx.packService.getSessionDelta(arg.sessionId); }); - ipcMain.handle(IPC.agentChatList, async (_event, arg: AgentChatListArgs = {}): Promise => { - const ctx = getCtx(); - const laneId = typeof arg?.laneId === "string" ? arg.laneId.trim() : ""; - return ctx.agentChatService.listSessions(laneId || undefined); - }); - - ipcMain.handle(IPC.agentChatCreate, async (_event, arg: AgentChatCreateArgs): Promise => { - const ctx = getCtx(); - return await ctx.agentChatService.createSession(arg); - }); - - ipcMain.handle(IPC.agentChatSend, async (_event, arg: AgentChatSendArgs): Promise => { - const ctx = getCtx(); - await ctx.agentChatService.sendMessage(arg); - }); - - ipcMain.handle(IPC.agentChatSteer, async (_event, arg: AgentChatSteerArgs): Promise => { - const ctx = getCtx(); - await ctx.agentChatService.steer(arg); - }); - - ipcMain.handle(IPC.agentChatInterrupt, async (_event, arg: AgentChatInterruptArgs): Promise => { - const ctx = getCtx(); - await ctx.agentChatService.interrupt(arg); - }); - - ipcMain.handle(IPC.agentChatResume, async (_event, arg: AgentChatResumeArgs): Promise => { - const ctx = getCtx(); - return await ctx.agentChatService.resumeSession(arg); - }); - - ipcMain.handle(IPC.agentChatApprove, async (_event, arg: AgentChatApproveArgs): Promise => { - const ctx = getCtx(); - await ctx.agentChatService.approveToolUse(arg); - }); - - ipcMain.handle(IPC.agentChatModels, async (_event, arg: AgentChatModelsArgs): Promise => { - const ctx = getCtx(); - return await ctx.agentChatService.getAvailableModels(arg); - }); - - ipcMain.handle(IPC.agentChatDispose, async (_event, arg: AgentChatDisposeArgs): Promise => { - const ctx = getCtx(); - await ctx.agentChatService.dispose(arg); - }); - ipcMain.handle(IPC.ptyCreate, async (_event, arg: PtyCreateArgs): Promise => { const ctx = getCtx(); return await ctx.ptyService.create(arg); diff --git a/apps/desktop/src/main/services/packs/packService.ts b/apps/desktop/src/main/services/packs/packService.ts index 06f0d3243..fa6f82678 100644 --- a/apps/desktop/src/main/services/packs/packService.ts +++ b/apps/desktop/src/main/services/packs/packService.ts @@ -274,84 +274,6 @@ function parsePorcelainPaths(stdout: string): string[] { return [...out]; } -function parseChatTranscriptDelta(rawTranscript: string): { - touchedFiles: string[]; - failureLines: string[]; -} { - const touched = new Set(); - const failureLines: string[] = []; - const seenFailure = new Set(); - - const pushFailure = (value: string | null | undefined) => { - const normalized = String(value ?? "").replace(/\s+/g, " ").trim(); - if (!normalized.length) return; - const clipped = normalized.length > 320 ? normalized.slice(0, 320) : normalized; - if (seenFailure.has(clipped)) return; - seenFailure.add(clipped); - failureLines.push(clipped); - }; - - for (const rawLine of rawTranscript.split(/\r?\n/)) { - const line = rawLine.trim(); - if (!line.length) continue; - - let parsed: unknown; - try { - parsed = JSON.parse(line); - } catch { - continue; - } - - if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) continue; - const event = (parsed as { event?: unknown }).event; - if (!event || typeof event !== "object" || Array.isArray(event)) continue; - const eventRecord = event as Record; - const type = typeof eventRecord.type === "string" ? eventRecord.type : ""; - - if (type === "file_change") { - const pathValue = String(eventRecord.path ?? "").trim(); - if (pathValue.length && !pathValue.startsWith("(")) touched.add(pathValue); - continue; - } - - if (type === "command") { - const command = String(eventRecord.command ?? "").trim(); - const output = String(eventRecord.output ?? ""); - const status = String(eventRecord.status ?? "").trim(); - const exitCode = typeof eventRecord.exitCode === "number" ? eventRecord.exitCode : null; - - if (status === "failed" || (exitCode != null && exitCode !== 0)) { - pushFailure(command.length ? `Command failed: ${command}` : "Command failed."); - } - - for (const outputLine of output.split(/\r?\n/)) { - const normalized = outputLine.replace(/\s+/g, " ").trim(); - if (!normalized.length) continue; - if (!/\b(error|failed|exception|fatal|traceback)\b/i.test(normalized)) continue; - pushFailure(normalized); - } - continue; - } - - if (type === "error") { - pushFailure(String(eventRecord.message ?? "Chat error.")); - continue; - } - - if (type === "status") { - const turnStatus = String(eventRecord.turnStatus ?? "").trim(); - if (turnStatus === "failed") { - pushFailure(String(eventRecord.message ?? "Turn failed.")); - } - } - } - - return { - touchedFiles: uniqueSorted(touched), - failureLines: failureLines.slice(-16) - }; -} - function extractSection(existing: string, start: string, end: string, fallback: string): string { const startIdx = existing.indexOf(start); const endIdx = existing.indexOf(end); @@ -3616,42 +3538,22 @@ Before writing, explore to understand: } } - const isChatTranscript = session.transcript_path.endsWith(".chat.jsonl"); - const transcript = sessionService.readTranscriptTail( - session.transcript_path, - 220_000, - isChatTranscript ? { raw: true, alignToLineBoundary: true } : undefined - ); + const transcript = sessionService.readTranscriptTail(session.transcript_path, 220_000); const failureLines = (() => { const out: string[] = []; const seen = new Set(); - const push = (value: string | null | undefined) => { - const normalized = stripAnsi(String(value ?? "")).replace(/\s+/g, " ").trim(); - if (!normalized.length) return; - if (seen.has(normalized)) return; - seen.add(normalized); - out.push(normalized); - }; - for (const rawLine of transcript.split("\n")) { const line = stripAnsi(rawLine).trim(); if (!line) continue; if (!/\b(error|failed|exception|fatal|traceback)\b/i.test(line)) continue; - push(line); - } - - if (isChatTranscript) { - const chatDelta = parseChatTranscriptDelta(transcript); - for (const touchedPath of chatDelta.touchedFiles) { - touched.add(touchedPath); - } - for (const line of chatDelta.failureLines) { - push(line); - } + // Collapse duplicates and near-duplicates (e.g. repeated prompts). + const key = line.replace(/\s+/g, " "); + if (seen.has(key)) continue; + seen.add(key); + out.push(key); } - - return out.slice(-8); - })(); + return out.slice(-8); + })(); const touchedFiles = [...touched].sort(); const computedAt = new Date().toISOString(); diff --git a/apps/desktop/src/main/services/pty/ptyService.ts b/apps/desktop/src/main/services/pty/ptyService.ts index a989a3b37..71cf95fc2 100644 --- a/apps/desktop/src/main/services/pty/ptyService.ts +++ b/apps/desktop/src/main/services/pty/ptyService.ts @@ -90,7 +90,7 @@ function runtimeFromStatus(status: TerminalSessionStatus): TerminalRuntimeState function normalizeToolType(raw: unknown): TerminalToolType | null { const value = typeof raw === "string" ? raw.trim().toLowerCase() : ""; if (!value) return null; - const allowed: TerminalToolType[] = ["shell", "claude", "codex", "codex-chat", "claude-chat", "cursor", "aider", "continue", "other"]; + const allowed: TerminalToolType[] = ["shell", "claude", "codex", "cursor", "aider", "continue", "other"]; return (allowed as string[]).includes(value) ? (value as TerminalToolType) : "other"; } diff --git a/apps/desktop/src/main/services/sessions/sessionService.ts b/apps/desktop/src/main/services/sessions/sessionService.ts index a1c90d447..6504291d1 100644 --- a/apps/desktop/src/main/services/sessions/sessionService.ts +++ b/apps/desktop/src/main/services/sessions/sessionService.ts @@ -21,7 +21,7 @@ export function createSessionService({ db }: { db: AdeDb }) { const normalizeToolType = (raw: unknown): TerminalToolType | null => { const value = typeof raw === "string" ? raw.trim().toLowerCase() : ""; if (!value) return null; - const allowed: TerminalToolType[] = ["shell", "claude", "codex", "codex-chat", "claude-chat", "cursor", "aider", "continue", "other"]; + const allowed: TerminalToolType[] = ["shell", "claude", "codex", "cursor", "aider", "continue", "other"]; return (allowed as string[]).includes(value) ? (value as TerminalToolType) : "other"; }; @@ -234,7 +234,7 @@ export function createSessionService({ db }: { db: AdeDb }) { }: { sessionId: string; laneId: string; - ptyId: string | null; + ptyId: string; tracked: boolean; title: string; startedAt: string; @@ -257,7 +257,7 @@ export function createSessionService({ db }: { db: AdeDb }) { [ sessionId, laneId, - ptyId ?? null, + ptyId, tracked ? 1 : 0, title, startedAt, @@ -268,19 +268,6 @@ export function createSessionService({ db }: { db: AdeDb }) { ); }, - reopen(sessionId: string): void { - db.run( - ` - update terminal_sessions - set status = 'running', - ended_at = null, - exit_code = null - where id = ? - `, - [sessionId] - ); - }, - setHeadShaStart(sessionId: string, sha: string): void { db.run("update terminal_sessions set head_sha_start = ? where id = ?", [sha, sessionId]); }, diff --git a/apps/desktop/src/main/services/state/kvDb.ts b/apps/desktop/src/main/services/state/kvDb.ts index 5023e4a92..5de348b3c 100644 --- a/apps/desktop/src/main/services/state/kvDb.ts +++ b/apps/desktop/src/main/services/state/kvDb.ts @@ -551,33 +551,6 @@ function migrate(db: Database) { ["project_id", "status"] ); - db.run(` - create table if not exists ai_usage_log ( - id text primary key, - timestamp text not null, - feature text not null, - provider text not null, - model text, - input_tokens integer, - output_tokens integer, - duration_ms integer not null, - success integer not null default 0, - session_id text - ) - `); - createIndexIfColumnsExist( - db, - "create index if not exists idx_ai_usage_feature_timestamp on ai_usage_log(feature, timestamp)", - "ai_usage_log", - ["feature", "timestamp"] - ); - createIndexIfColumnsExist( - db, - "create index if not exists idx_ai_usage_timestamp on ai_usage_log(timestamp)", - "ai_usage_log", - ["timestamp"] - ); - // Phase 7 GitHub PR tracking (lane -> PR mapping). db.run(` create table if not exists pull_requests ( diff --git a/apps/desktop/src/preload/global.d.ts b/apps/desktop/src/preload/global.d.ts index 98148032b..d5c8beada 100644 --- a/apps/desktop/src/preload/global.d.ts +++ b/apps/desktop/src/preload/global.d.ts @@ -66,19 +66,6 @@ import type { HostedSignInResult, HostedStatus, AgentTool, - AgentChatApproveArgs, - AgentChatCreateArgs, - AgentChatDisposeArgs, - AgentChatEventEnvelope, - AgentChatInterruptArgs, - AgentChatListArgs, - AgentChatModelInfo, - AgentChatModelsArgs, - AgentChatResumeArgs, - AgentChatSendArgs, - AgentChatSession, - AgentChatSessionSummary, - AgentChatSteerArgs, AutomationsEventPayload, AutomationRuleSummary, AutomationRun, @@ -357,18 +344,6 @@ declare global { readTranscriptTail: (args: ReadTranscriptTailArgs) => Promise; getDelta: (sessionId: string) => Promise; }; - agentChat: { - list: (args?: AgentChatListArgs) => Promise; - create: (args: AgentChatCreateArgs) => Promise; - send: (args: AgentChatSendArgs) => Promise; - steer: (args: AgentChatSteerArgs) => Promise; - interrupt: (args: AgentChatInterruptArgs) => Promise; - resume: (args: AgentChatResumeArgs) => Promise; - approve: (args: AgentChatApproveArgs) => Promise; - models: (args: AgentChatModelsArgs) => Promise; - dispose: (args: AgentChatDisposeArgs) => Promise; - onEvent: (cb: (ev: AgentChatEventEnvelope) => void) => () => void; - }; pty: { create: (args: PtyCreateArgs) => Promise; write: (args: { ptyId: string; data: string }) => Promise; diff --git a/apps/desktop/src/preload/preload.ts b/apps/desktop/src/preload/preload.ts index dd5537194..3bcc11b0b 100644 --- a/apps/desktop/src/preload/preload.ts +++ b/apps/desktop/src/preload/preload.ts @@ -113,19 +113,6 @@ import type { HostedSignInResult, HostedStatus, AgentTool, - AgentChatApproveArgs, - AgentChatCreateArgs, - AgentChatDisposeArgs, - AgentChatEventEnvelope, - AgentChatInterruptArgs, - AgentChatListArgs, - AgentChatModelInfo, - AgentChatModelsArgs, - AgentChatResumeArgs, - AgentChatSendArgs, - AgentChatSession, - AgentChatSessionSummary, - AgentChatSteerArgs, KeybindingOverride, KeybindingsSnapshot, OnboardingDetectionResult, @@ -430,31 +417,6 @@ contextBridge.exposeInMainWorld("ade", { getDelta: async (sessionId: string): Promise => ipcRenderer.invoke(IPC.sessionsGetDelta, { sessionId }) }, - agentChat: { - list: async (args: AgentChatListArgs = {}): Promise => - ipcRenderer.invoke(IPC.agentChatList, args), - create: async (args: AgentChatCreateArgs): Promise => - ipcRenderer.invoke(IPC.agentChatCreate, args), - send: async (args: AgentChatSendArgs): Promise => - ipcRenderer.invoke(IPC.agentChatSend, args), - steer: async (args: AgentChatSteerArgs): Promise => - ipcRenderer.invoke(IPC.agentChatSteer, args), - interrupt: async (args: AgentChatInterruptArgs): Promise => - ipcRenderer.invoke(IPC.agentChatInterrupt, args), - resume: async (args: AgentChatResumeArgs): Promise => - ipcRenderer.invoke(IPC.agentChatResume, args), - approve: async (args: AgentChatApproveArgs): Promise => - ipcRenderer.invoke(IPC.agentChatApprove, args), - models: async (args: AgentChatModelsArgs): Promise => - ipcRenderer.invoke(IPC.agentChatModels, args), - dispose: async (args: AgentChatDisposeArgs): Promise => - ipcRenderer.invoke(IPC.agentChatDispose, args), - onEvent: (cb: (ev: AgentChatEventEnvelope) => void) => { - const listener = (_event: Electron.IpcRendererEvent, payload: AgentChatEventEnvelope) => cb(payload); - ipcRenderer.on(IPC.agentChatEvent, listener); - return () => ipcRenderer.removeListener(IPC.agentChatEvent, listener); - } - }, pty: { create: async (args: PtyCreateArgs): Promise => ipcRenderer.invoke(IPC.ptyCreate, args), write: async (arg: { ptyId: string; data: string }): Promise => ipcRenderer.invoke(IPC.ptyWrite, arg), diff --git a/apps/desktop/src/renderer/components/app/SettingsPage.tsx b/apps/desktop/src/renderer/components/app/SettingsPage.tsx index ca9f2bb89..970b40013 100644 --- a/apps/desktop/src/renderer/components/app/SettingsPage.tsx +++ b/apps/desktop/src/renderer/components/app/SettingsPage.tsx @@ -48,15 +48,6 @@ type ProviderDraft = { }; }; -type ChatSettingsDraft = { - defaultProvider: "codex" | "claude" | "last_used"; - defaultApprovalPolicy: "auto" | "approve_mutations" | "approve_all"; - sendOnEnter: boolean; - codexSandbox: "read-only" | "workspace-write" | "danger-full-access"; - claudePermissionMode: "plan" | "acceptEdits" | "bypassPermissions"; - sessionBudgetUsd: string; -}; - function isRecord(value: unknown): value is Record { return !!value && typeof value === "object" && !Array.isArray(value); } @@ -159,47 +150,6 @@ function validateProviderDraft(draft: ProviderDraft, hasBootstrapConfig: boolean return null; } -function readChatSettingsDraft(snapshot: ProjectConfigSnapshot): ChatSettingsDraft { - const localChat = snapshot.local.ai?.chat; - const effectiveChat = snapshot.effective.ai?.chat; - const chat = { - ...(effectiveChat ?? {}), - ...(localChat ?? {}) - }; - - const defaultProvider = (() => { - const value = chat.defaultProvider; - return value === "codex" || value === "claude" || value === "last_used" ? value : "last_used"; - })(); - - const defaultApprovalPolicy = (() => { - const value = chat.defaultApprovalPolicy; - return value === "auto" || value === "approve_mutations" || value === "approve_all" ? value : "approve_mutations"; - })(); - - const codexSandbox = (() => { - const value = chat.codexSandbox; - return value === "read-only" || value === "workspace-write" || value === "danger-full-access" ? value : "workspace-write"; - })(); - - const claudePermissionMode = (() => { - const value = chat.claudePermissionMode; - return value === "plan" || value === "acceptEdits" || value === "bypassPermissions" ? value : "acceptEdits"; - })(); - - const budget = Number(chat.sessionBudgetUsd ?? 10); - const sessionBudgetUsd = Number.isFinite(budget) && budget > 0 ? String(budget) : "10"; - - return { - defaultProvider, - defaultApprovalPolicy, - sendOnEnter: chat.sendOnEnter ?? true, - codexSandbox, - claudePermissionMode, - sessionBudgetUsd - }; -} - const THEME_META: Record< ThemeId, { label: string; colors: { bg: string; fg: string; card: string; muted: string; border: string; accent: string; accentSecondary: string } } @@ -326,7 +276,6 @@ export function SettingsPage() { const [actionError, setActionError] = useState(null); const [saveNotice, setSaveNotice] = useState(null); const [providerDraft, setProviderDraft] = useState(null); - const [chatDraft, setChatDraft] = useState(null); const [hostedStatus, setHostedStatus] = useState(null); const [hostedBootstrapConfig, setHostedBootstrapConfig] = useState(null); const [hostedBusy, setHostedBusy] = useState(false); @@ -343,7 +292,6 @@ export function SettingsPage() { const [hostedGithubEvents, setHostedGithubEvents] = useState([]); const [hostedGithubBusy, setHostedGithubBusy] = useState(false); const [hostedGithubPollingUntil, setHostedGithubPollingUntil] = useState(null); - const [chatBusy, setChatBusy] = useState(false); const providerMode = useAppStore((s) => s.providerMode); const theme = useAppStore((s) => s.theme); const setTheme = useAppStore((s) => s.setTheme); @@ -366,7 +314,6 @@ export function SettingsPage() { .then((snapshot) => { if (!cancelled) { setProviderDraft(readProviderDraft(snapshot)); - setChatDraft(readChatSettingsDraft(snapshot)); const localSeconds = typeof snapshot.local.github?.prPollingIntervalSeconds === "number" ? snapshot.local.github.prPollingIntervalSeconds : null; const effectiveSeconds = typeof snapshot.effective.github?.prPollingIntervalSeconds === "number" ? snapshot.effective.github.prPollingIntervalSeconds : null; @@ -507,14 +454,13 @@ export function SettingsPage() { return ; } - if (!info || !providerDraft || !chatDraft) { + if (!info || !providerDraft) { return ; } const refreshProviderDraftAndHostedState = async () => { const snapshot = await window.ade.projectConfig.get(); setProviderDraft(readProviderDraft(snapshot)); - setChatDraft(readChatSettingsDraft(snapshot)); const localSeconds = typeof snapshot.local.github?.prPollingIntervalSeconds === "number" ? snapshot.local.github.prPollingIntervalSeconds : null; const effectiveSeconds = typeof snapshot.effective.github?.prPollingIntervalSeconds === "number" ? snapshot.effective.github.prPollingIntervalSeconds : null; @@ -592,54 +538,6 @@ export function SettingsPage() { } }; - const saveChatSettings = async () => { - if (!chatDraft) return; - setActionError(null); - setSaveNotice(null); - setChatBusy(true); - try { - const snapshot = await window.ade.projectConfig.get(); - const currentLocalAi = snapshot.local.ai ?? {}; - const budgetRaw = chatDraft.sessionBudgetUsd.trim(); - if (budgetRaw.length) { - const budget = Number(budgetRaw); - if (!Number.isFinite(budget) || budget <= 0) { - setActionError("Chat session budget must be a positive number."); - return; - } - } - - const nextChat = { - defaultProvider: chatDraft.defaultProvider, - defaultApprovalPolicy: chatDraft.defaultApprovalPolicy, - sendOnEnter: chatDraft.sendOnEnter, - codexSandbox: chatDraft.codexSandbox, - claudePermissionMode: chatDraft.claudePermissionMode, - ...(budgetRaw.length ? { sessionBudgetUsd: Number(budgetRaw) } : {}) - }; - - const nextLocal = { - ...snapshot.local, - ai: { - ...currentLocalAi, - chat: nextChat - } - }; - - await window.ade.projectConfig.save({ - shared: snapshot.shared, - local: nextLocal - }); - - await refreshProviderDraftAndHostedState(); - setSaveNotice("Chat settings saved to .ade/local.yaml."); - } catch (error) { - setActionError(error instanceof Error ? error.message : String(error)); - } finally { - setChatBusy(false); - } - }; - const savePrPollingSettings = async () => { setActionError(null); setSaveNotice(null); @@ -801,141 +699,6 @@ export function SettingsPage() { -
-
Agent Chat
-
- - - - - - - - - - - -
-
- -
-
- {providerDraft.mode === "hosted" ? (
Hosted Agent (Clerk + GitHub/Google)
diff --git a/apps/desktop/src/renderer/components/chat/AgentChatComposer.test.tsx b/apps/desktop/src/renderer/components/chat/AgentChatComposer.test.tsx deleted file mode 100644 index 10d9ade17..000000000 --- a/apps/desktop/src/renderer/components/chat/AgentChatComposer.test.tsx +++ /dev/null @@ -1,131 +0,0 @@ -/* @vitest-environment jsdom */ - -import React from "react"; -import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react"; -import { afterEach, describe, expect, it, vi } from "vitest"; -import { AgentChatComposer } from "./AgentChatComposer"; - -function renderComposer(overrides: Partial> = {}) { - const onProviderChange = vi.fn(); - const onModelChange = vi.fn(); - const onDraftChange = vi.fn(); - const onSubmit = vi.fn(); - const onInterrupt = vi.fn(); - const onApproval = vi.fn(); - const onAddAttachment = vi.fn(); - const onRemoveAttachment = vi.fn(); - const onSearchAttachments = vi.fn(async () => []); - - const props: React.ComponentProps = { - provider: "codex", - model: "gpt-5.3-codex", - models: [ - { id: "gpt-5.3-codex", displayName: "gpt-5.3-codex", isDefault: true }, - { id: "gpt-5.2-codex", displayName: "gpt-5.2-codex", isDefault: false } - ], - draft: "hello", - attachments: [], - pendingApproval: null, - turnActive: false, - sendOnEnter: true, - busy: false, - onProviderChange, - onModelChange, - onDraftChange, - onSubmit, - onInterrupt, - onApproval, - onAddAttachment, - onRemoveAttachment, - onSearchAttachments, - ...overrides - }; - - const utils = render(); - return { - ...utils, - props, - onProviderChange, - onModelChange, - onDraftChange, - onSubmit, - onInterrupt, - onApproval, - onAddAttachment, - onRemoveAttachment, - onSearchAttachments - }; -} - -describe("AgentChatComposer", () => { - afterEach(() => { - cleanup(); - }); - - it("sends message on Enter when send-on-Enter is enabled", () => { - const { onSubmit } = renderComposer({ sendOnEnter: true, draft: "send me" }); - - const textarea = screen.getByPlaceholderText("Ask Codex or Claude to work in this lane...") as HTMLTextAreaElement; - fireEvent.keyDown(textarea, { key: "Enter" }); - - expect(onSubmit).toHaveBeenCalledTimes(1); - }); - - it("sends message on Cmd/Ctrl+Enter when send-on-Enter is disabled", () => { - const { onSubmit } = renderComposer({ sendOnEnter: false, draft: "send me" }); - - const textarea = screen.getByPlaceholderText("Ask Codex or Claude to work in this lane...") as HTMLTextAreaElement; - fireEvent.keyDown(textarea, { key: "Enter" }); - fireEvent.keyDown(textarea, { key: "Enter", metaKey: true }); - - expect(onSubmit).toHaveBeenCalledTimes(1); - }); - - it("shows steer mode and interrupt controls when turn is active", () => { - renderComposer({ turnActive: true, draft: "steer" }); - - expect(screen.getByText("Steering active turn")).toBeTruthy(); - expect(screen.getByRole("button", { name: "Stop" })).toBeTruthy(); - expect(screen.getByRole("button", { name: "Steer" })).toBeTruthy(); - }); - - it("opens @ attachment picker when @ key is pressed", async () => { - renderComposer(); - - const textarea = screen.getByPlaceholderText("Ask Codex or Claude to work in this lane...") as HTMLTextAreaElement; - fireEvent.keyDown(textarea, { key: "@", shiftKey: true, code: "Digit2" }); - - await waitFor(() => { - expect(screen.getByPlaceholderText("Search files in this lane...")).toBeTruthy(); - }); - }); - - it("shows approval actions when approval is pending", () => { - const { onApproval } = renderComposer({ - pendingApproval: { - itemId: "approval-1", - kind: "command", - description: "Run command" - } - }); - - fireEvent.click(screen.getByRole("button", { name: "Accept" })); - fireEvent.click(screen.getByRole("button", { name: "Decline" })); - - expect(onApproval).toHaveBeenCalledWith("accept"); - expect(onApproval).toHaveBeenCalledWith("decline"); - }); - - it("switches provider and model from dropdowns", () => { - const { onProviderChange, onModelChange } = renderComposer(); - - const providerSelect = screen.getByLabelText("Provider") as HTMLSelectElement; - fireEvent.change(providerSelect, { target: { value: "claude" } }); - - const modelSelect = screen.getByLabelText("Model") as HTMLSelectElement; - fireEvent.change(modelSelect, { target: { value: "gpt-5.2-codex" } }); - - expect(onProviderChange).toHaveBeenCalledWith("claude"); - expect(onModelChange).toHaveBeenCalledWith("gpt-5.2-codex"); - }); -}); diff --git a/apps/desktop/src/renderer/components/chat/AgentChatComposer.tsx b/apps/desktop/src/renderer/components/chat/AgentChatComposer.tsx deleted file mode 100644 index b32cca5cd..000000000 --- a/apps/desktop/src/renderer/components/chat/AgentChatComposer.tsx +++ /dev/null @@ -1,358 +0,0 @@ -import React, { useEffect, useMemo, useRef, useState } from "react"; -import { AtSign, ImageIcon, Pause, Play, Square, X } from "lucide-react"; -import type { - AgentChatApprovalDecision, - AgentChatFileRef, - AgentChatModelInfo, - AgentChatProvider -} from "../../../shared/types"; -import { Button } from "../ui/Button"; -import { Chip } from "../ui/Chip"; -import { cn } from "../ui/cn"; - -export function AgentChatComposer({ - provider, - model, - models, - draft, - attachments, - pendingApproval, - turnActive, - sendOnEnter, - busy, - onProviderChange, - onModelChange, - onDraftChange, - onSubmit, - onInterrupt, - onApproval, - onAddAttachment, - onRemoveAttachment, - onSearchAttachments -}: { - provider: AgentChatProvider; - model: string; - models: AgentChatModelInfo[]; - draft: string; - attachments: AgentChatFileRef[]; - pendingApproval: { - itemId: string; - description: string; - kind: "command" | "file_change" | "tool_call"; - } | null; - turnActive: boolean; - sendOnEnter: boolean; - busy: boolean; - onProviderChange: (provider: AgentChatProvider) => void; - onModelChange: (model: string) => void; - onDraftChange: (value: string) => void; - onSubmit: () => void; - onInterrupt: () => void; - onApproval: (decision: AgentChatApprovalDecision) => void; - onAddAttachment: (attachment: AgentChatFileRef) => void; - onRemoveAttachment: (path: string) => void; - onSearchAttachments: (query: string) => Promise; -}) { - const [attachmentPickerOpen, setAttachmentPickerOpen] = useState(false); - const [attachmentQuery, setAttachmentQuery] = useState(""); - const [attachmentBusy, setAttachmentBusy] = useState(false); - const [attachmentResults, setAttachmentResults] = useState([]); - const [attachmentCursor, setAttachmentCursor] = useState(0); - - const attachmentInputRef = useRef(null); - const canAttach = !turnActive; - - const attachedPaths = useMemo(() => new Set(attachments.map((attachment) => attachment.path)), [attachments]); - - useEffect(() => { - if (!attachmentPickerOpen) { - setAttachmentBusy(false); - setAttachmentQuery(""); - setAttachmentResults([]); - setAttachmentCursor(0); - return; - } - const timeout = window.setTimeout(() => { - attachmentInputRef.current?.focus(); - }, 0); - return () => window.clearTimeout(timeout); - }, [attachmentPickerOpen]); - - useEffect(() => { - if (!attachmentPickerOpen) return; - const query = attachmentQuery.trim(); - if (!query.length) { - setAttachmentBusy(false); - setAttachmentResults([]); - setAttachmentCursor(0); - return; - } - - let cancelled = false; - const timeout = window.setTimeout(() => { - setAttachmentBusy(true); - onSearchAttachments(query) - .then((results) => { - if (cancelled) return; - setAttachmentResults(results.filter((result) => !attachedPaths.has(result.path))); - setAttachmentCursor(0); - }) - .catch(() => { - if (cancelled) return; - setAttachmentResults([]); - }) - .finally(() => { - if (!cancelled) setAttachmentBusy(false); - }); - }, 120); - - return () => { - cancelled = true; - window.clearTimeout(timeout); - }; - }, [attachmentPickerOpen, attachmentQuery, attachedPaths, onSearchAttachments]); - - const selectAttachment = (attachment: AgentChatFileRef) => { - onAddAttachment(attachment); - setAttachmentPickerOpen(false); - }; - - return ( -
-
- - - - - {turnActive ? ( - - - Steering active turn - - ) : null} - - -
- - {pendingApproval ? ( -
-
Approval pending · {pendingApproval.kind}
-
{pendingApproval.description}
-
- - - - -
-
- ) : null} - - {attachments.length ? ( -
- {attachments.map((attachment) => ( - - {attachment.type === "image" ? : } - {attachment.path} - - - ))} -
- ) : null} - - {attachmentPickerOpen ? ( -
-
- - setAttachmentQuery(event.target.value)} - placeholder="Search files in this lane..." - className="h-7 flex-1 rounded border border-border/30 bg-bg/60 px-2 text-xs outline-none focus:border-accent/40 focus:ring-1 focus:ring-accent/30" - onKeyDown={(event) => { - if (event.key === "Escape") { - event.preventDefault(); - setAttachmentPickerOpen(false); - return; - } - if (event.key === "ArrowDown") { - event.preventDefault(); - setAttachmentCursor((value) => Math.min(value + 1, Math.max(attachmentResults.length - 1, 0))); - return; - } - if (event.key === "ArrowUp") { - event.preventDefault(); - setAttachmentCursor((value) => Math.max(value - 1, 0)); - return; - } - if (event.key === "Enter") { - const candidate = attachmentResults[attachmentCursor]; - if (!candidate) return; - event.preventDefault(); - selectAttachment(candidate); - } - }} - /> -
-
- {!attachmentQuery.trim().length ? ( -
Type to fuzzy-search files.
- ) : attachmentBusy ? ( -
Searching…
- ) : attachmentResults.length ? ( - attachmentResults.map((result, index) => ( - - )) - ) : ( -
No matching files.
- )} -
-
- ) : null} - -
-