From 240637e6b9dd4bc4ff2c0cf8139b13aea26e3244 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 Aug 2025 00:49:44 +0000 Subject: [PATCH 01/19] Initial plan From 3fb57734dc5121bc4bd2667f55d60474a2a2d265 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 Aug 2025 01:01:27 +0000 Subject: [PATCH 02/19] Initial exploration: Understand Sequential Thinking MCP display issue Co-authored-by: thedotmack <683968+thedotmack@users.noreply.github.com> --- package-lock.json | 260 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 246 insertions(+), 14 deletions(-) diff --git a/package-lock.json b/package-lock.json index eed2169fc..79f387813 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "framer-motion": "^12.0.0-alpha.1", "html2canvas": "^1.4.1", "lucide-react": "^0.468.0", + "posthog-js": "^1.258.3", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.54.2", @@ -52,7 +53,7 @@ "zustand": "^5.0.6" }, "devDependencies": { - "@tauri-apps/cli": "^2", + "@tauri-apps/cli": "^2.7.1", "@types/node": "^22.15.30", "@types/react": "^18.3.1", "@types/react-dom": "^18.3.1", @@ -1436,7 +1437,9 @@ } }, "node_modules/@tauri-apps/cli": { - "version": "2.5.0", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.7.1.tgz", + "integrity": "sha512-RcGWR4jOUEl92w3uvI0h61Llkfj9lwGD1iwvDRD2isMrDhOzjeeeVn9aGzeW1jubQ/kAbMYfydcA4BA0Cy733Q==", "dev": true, "license": "Apache-2.0 OR MIT", "bin": { @@ -1450,21 +1453,23 @@ "url": "https://opencollective.com/tauri" }, "optionalDependencies": { - "@tauri-apps/cli-darwin-arm64": "2.5.0", - "@tauri-apps/cli-darwin-x64": "2.5.0", - "@tauri-apps/cli-linux-arm-gnueabihf": "2.5.0", - "@tauri-apps/cli-linux-arm64-gnu": "2.5.0", - "@tauri-apps/cli-linux-arm64-musl": "2.5.0", - "@tauri-apps/cli-linux-riscv64-gnu": "2.5.0", - "@tauri-apps/cli-linux-x64-gnu": "2.5.0", - "@tauri-apps/cli-linux-x64-musl": "2.5.0", - "@tauri-apps/cli-win32-arm64-msvc": "2.5.0", - "@tauri-apps/cli-win32-ia32-msvc": "2.5.0", - "@tauri-apps/cli-win32-x64-msvc": "2.5.0" + "@tauri-apps/cli-darwin-arm64": "2.7.1", + "@tauri-apps/cli-darwin-x64": "2.7.1", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.7.1", + "@tauri-apps/cli-linux-arm64-gnu": "2.7.1", + "@tauri-apps/cli-linux-arm64-musl": "2.7.1", + "@tauri-apps/cli-linux-riscv64-gnu": "2.7.1", + "@tauri-apps/cli-linux-x64-gnu": "2.7.1", + "@tauri-apps/cli-linux-x64-musl": "2.7.1", + "@tauri-apps/cli-win32-arm64-msvc": "2.7.1", + "@tauri-apps/cli-win32-ia32-msvc": "2.7.1", + "@tauri-apps/cli-win32-x64-msvc": "2.7.1" } }, "node_modules/@tauri-apps/cli-darwin-arm64": { - "version": "2.5.0", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.7.1.tgz", + "integrity": "sha512-j2NXQN6+08G03xYiyKDKqbCV2Txt+hUKg0a8hYr92AmoCU8fgCjHyva/p16lGFGUG3P2Yu0xiNe1hXL9ZuRMzA==", "cpu": [ "arm64" ], @@ -1478,6 +1483,176 @@ "node": ">= 10" } }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.7.1.tgz", + "integrity": "sha512-CdYAefeM35zKsc91qIyKzbaO7FhzTyWKsE8hj7tEJ1INYpoh1NeNNyL/NSEA3Nebi5ilugioJ5tRK8ZXG8y3gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.7.1.tgz", + "integrity": "sha512-dnvyJrTA1UJxJjQ8q1N/gWomjP8Twij1BUQu2fdcT3OPpqlrbOk5R1yT0oD/721xoKNjroB5BXCsmmlykllxNg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.7.1.tgz", + "integrity": "sha512-FtBW6LJPNRTws3qyUc294AqCWU91l/H0SsFKq6q4Q45MSS4x6wxLxou8zB53tLDGEPx3JSoPLcDaSfPlSbyujQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.7.1.tgz", + "integrity": "sha512-/HXY0t4FHkpFzjeYS5c16mlA6z0kzn5uKLWptTLTdFSnYpr8FCnOP4Sdkvm2TDQPF2ERxXtNCd+WR/jQugbGnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.7.1.tgz", + "integrity": "sha512-GeW5lVI2GhhnaYckiDzstG2j2Jwlud5d2XefRGwlOK+C/bVGLT1le8MNPYK8wgRlpeK8fG1WnJJYD6Ke7YQ8bg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.7.1.tgz", + "integrity": "sha512-DprxKQkPxIPYwUgg+cscpv2lcIUhn2nxEPlk0UeaiV9vATxCXyytxr1gLcj3xgjGyNPlM0MlJyYaPy1JmRg1cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.7.1.tgz", + "integrity": "sha512-KLlq3kOK7OUyDR757c0zQjPULpGZpLhNB0lZmZpHXvoOUcqZoCXJHh4dT/mryWZJp5ilrem5l8o9ngrDo0X1AA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.7.1.tgz", + "integrity": "sha512-dH7KUjKkSypCeWPiainHyXoES3obS+JIZVoSwSZfKq2gWgs48FY3oT0hQNYrWveE+VR4VoR3b/F3CPGbgFvksA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.7.1.tgz", + "integrity": "sha512-1oeibfyWQPVcijOrTg709qhbXArjX3x1MPjrmA5anlygwrbByxLBcLXvotcOeULFcnH2FYUMMLLant8kgvwE5A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.7.1.tgz", + "integrity": "sha512-D7Q9kDObutuirCNLxYQ7KAg2Xxg99AjcdYz/KuMw5HvyEPbkC9Q7JL0vOrQOrHEHxIQ2lYzFOZvKKoC2yyqXcg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@tauri-apps/plugin-dialog": { "version": "2.2.2", "license": "MIT OR Apache-2.0", @@ -2149,6 +2324,17 @@ "dev": true, "license": "MIT" }, + "node_modules/core-js": { + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.0.tgz", + "integrity": "sha512-c2KZL9lP4DjkN3hk/an4pWn5b5ZefhRJnAc42n6LJ19kSnbeRbdQZE5dSeE2LBol1OwJD3X1BQvFTAsa8ReeDA==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/css-line-break": { "version": "2.1.0", "license": "MIT", @@ -2499,6 +2685,12 @@ } } }, + "node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==", + "license": "MIT" + }, "node_modules/fill-range": { "version": "7.1.1", "license": "MIT", @@ -4162,6 +4354,40 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/posthog-js": { + "version": "1.259.0", + "resolved": "https://registry.npmjs.org/posthog-js/-/posthog-js-1.259.0.tgz", + "integrity": "sha512-6usLnJshky8fQ82ask7PIJh4BSFOU0VkRbFg8Zanm/HIlYMG1VOdRWlToA63JXeO7Bzm9TuREq1wFm5U2VEVCg==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "core-js": "^3.38.1", + "fflate": "^0.4.8", + "preact": "^10.19.3", + "web-vitals": "^4.2.4" + }, + "peerDependencies": { + "@rrweb/types": "2.0.0-alpha.17", + "rrweb-snapshot": "2.0.0-alpha.17" + }, + "peerDependenciesMeta": { + "@rrweb/types": { + "optional": true + }, + "rrweb-snapshot": { + "optional": true + } + } + }, + "node_modules/preact": { + "version": "10.27.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.27.0.tgz", + "integrity": "sha512-/DTYoB6mwwgPytiqQTh/7SFRL98ZdiD8Sk8zIUVOxtwq4oWcwrcd1uno9fE/zZmUaUrFNYzbH14CPebOz9tZQw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/prismjs": { "version": "1.30.0", "license": "MIT", @@ -5332,6 +5558,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "license": "Apache-2.0" + }, "node_modules/xtend": { "version": "4.0.2", "license": "MIT", From cea5d33a3b5f78b990b2db1198b2f786f5ad93dc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 Aug 2025 01:13:03 +0000 Subject: [PATCH 03/19] Implement SequentialThinkingWidget with smart UX improvements Co-authored-by: thedotmack <683968+thedotmack@users.noreply.github.com> --- package-lock.json | 3847 ++++++++++++++++++++++++------ src/components/StreamMessage.tsx | 69 + src/components/ToolWidgets.tsx | 138 ++ 3 files changed, 3320 insertions(+), 734 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79f387813..0ad5256e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -66,6 +66,8 @@ }, "node_modules/@ampproject/remapping": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -77,6 +79,8 @@ }, "node_modules/@babel/code-frame": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", "dependencies": { @@ -89,7 +93,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.27.5", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", "dev": true, "license": "MIT", "engines": { @@ -97,20 +103,22 @@ } }, "node_modules/@babel/core": { - "version": "7.27.4", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", + "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", - "@babel/helpers": "^7.27.4", - "@babel/parser": "^7.27.4", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.27.4", - "@babel/types": "^7.27.3", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -125,23 +133,17 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@babel/generator": { - "version": "7.27.5", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.5", - "@babel/types": "^7.27.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -150,6 +152,8 @@ }, "node_modules/@babel/helper-compilation-targets": { "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { @@ -163,16 +167,20 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { @@ -185,6 +193,8 @@ }, "node_modules/@babel/helper-module-transforms": { "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", "dev": true, "license": "MIT", "dependencies": { @@ -201,6 +211,8 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -209,6 +221,8 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -217,6 +231,8 @@ }, "node_modules/@babel/helper-validator-identifier": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, "license": "MIT", "engines": { @@ -225,6 +241,8 @@ }, "node_modules/@babel/helper-validator-option": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -232,23 +250,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.27.6", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", - "@babel/types": "^7.27.6" + "@babel/types": "^7.28.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.27.5", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.3" + "@babel/types": "^7.28.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -259,6 +281,8 @@ }, "node_modules/@babel/plugin-transform-react-jsx-self": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "dev": true, "license": "MIT", "dependencies": { @@ -273,6 +297,8 @@ }, "node_modules/@babel/plugin-transform-react-jsx-source": { "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "dev": true, "license": "MIT", "dependencies": { @@ -286,7 +312,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.6", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", + "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -294,6 +322,8 @@ }, "node_modules/@babel/template": { "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { @@ -306,24 +336,28 @@ } }, "node_modules/@babel/traverse": { - "version": "7.27.4", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.27.3", - "@babel/parser": "^7.27.4", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", - "@babel/types": "^7.27.3", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/types": "^7.28.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.27.6", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", "dev": true, "license": "MIT", "dependencies": { @@ -334,8 +368,84 @@ "node": ">=6.9.0" } }, + "node_modules/@emnapi/runtime": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.5", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", "cpu": [ "arm64" ], @@ -348,148 +458,1142 @@ "node": ">=18" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.1", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@floating-ui/utils": "^0.2.9" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.1", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.1", - "@floating-ui/utils": "^0.2.9" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.3", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@floating-ui/dom": "^1.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.9", - "license": "MIT" + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@hookform/resolvers": { - "version": "3.10.0", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "peerDependencies": { - "react-hook-form": "^7.0.0" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.1.0", + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", "cpu": [ "arm64" ], - "dev": true, - "license": "LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "darwin" + "netbsd" ], - "funding": { - "url": "https://opencollective.com/libvips" + "engines": { + "node": ">=18" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=18.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.3.tgz", + "integrity": "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.5.tgz", + "integrity": "sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.3" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@hookform/resolvers": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.10.0.tgz", + "integrity": "sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==", + "license": "MIT", + "peerDependencies": { + "react-hook-form": "^7.0.0" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz", + "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "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.0" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz", + "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "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.0" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz", + "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz", + "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz", + "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz", + "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz", + "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz", + "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz", + "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz", + "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz", + "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz", + "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "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.0" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz", + "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "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.0" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz", + "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "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-ppc64": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz", + "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "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-s390x": "1.2.0" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz", + "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "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.0" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz", + "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "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.0" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz", + "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "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.0" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz", + "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.4.4" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz", + "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "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-ia32": { + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz", + "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "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.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz", + "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.30", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", + "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher": { + "node_modules/@parcel/watcher-win32-arm64": { "version": "2.5.1", - "hasInstallScript": true, + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">= 10.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" } }, - "node_modules/@parcel/watcher-darwin-arm64": { + "node_modules/@parcel/watcher-win32-ia32": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", "cpu": [ - "arm64" + "ia32" ], "license": "MIT", "optional": true, "os": [ - "darwin" + "win32" ], "engines": { "node": ">= 10.0.0" @@ -499,26 +1603,42 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher/node_modules/detect-libc": { - "version": "1.0.3", - "license": "Apache-2.0", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=0.10" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/@radix-ui/number": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", "license": "MIT" }, "node_modules/@radix-ui/primitive": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -540,6 +1660,8 @@ }, "node_modules/@radix-ui/react-collection": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -564,6 +1686,8 @@ }, "node_modules/@radix-ui/react-compose-refs": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -577,6 +1701,8 @@ }, "node_modules/@radix-ui/react-context": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -590,6 +1716,8 @@ }, "node_modules/@radix-ui/react-dialog": { "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz", + "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -624,6 +1752,8 @@ }, "node_modules/@radix-ui/react-direction": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -637,6 +1767,8 @@ }, "node_modules/@radix-ui/react-dismissable-layer": { "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", + "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -662,6 +1794,8 @@ }, "node_modules/@radix-ui/react-dropdown-menu": { "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz", + "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -689,6 +1823,8 @@ }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -702,6 +1838,8 @@ }, "node_modules/@radix-ui/react-focus-scope": { "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -725,6 +1863,8 @@ }, "node_modules/@radix-ui/react-id": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -741,6 +1881,8 @@ }, "node_modules/@radix-ui/react-label": { "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -762,6 +1904,8 @@ }, "node_modules/@radix-ui/react-menu": { "version": "2.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz", + "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -800,6 +1944,8 @@ }, "node_modules/@radix-ui/react-popover": { "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.14.tgz", + "integrity": "sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -835,6 +1981,8 @@ }, "node_modules/@radix-ui/react-popper": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", + "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", @@ -865,6 +2013,8 @@ }, "node_modules/@radix-ui/react-portal": { "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3", @@ -887,6 +2037,8 @@ }, "node_modules/@radix-ui/react-presence": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", @@ -909,6 +2061,8 @@ }, "node_modules/@radix-ui/react-primitive": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { "@radix-ui/react-slot": "1.2.3" @@ -930,6 +2084,8 @@ }, "node_modules/@radix-ui/react-radio-group": { "version": "1.3.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.7.tgz", + "integrity": "sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -960,6 +2116,8 @@ }, "node_modules/@radix-ui/react-roving-focus": { "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz", + "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -989,6 +2147,8 @@ }, "node_modules/@radix-ui/react-select": { "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.5.tgz", + "integrity": "sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==", "license": "MIT", "dependencies": { "@radix-ui/number": "1.1.1", @@ -1030,6 +2190,8 @@ }, "node_modules/@radix-ui/react-slot": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" @@ -1046,6 +2208,8 @@ }, "node_modules/@radix-ui/react-switch": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.5.tgz", + "integrity": "sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -1073,6 +2237,8 @@ }, "node_modules/@radix-ui/react-tabs": { "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.12.tgz", + "integrity": "sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -1101,6 +2267,8 @@ }, "node_modules/@radix-ui/react-toast": { "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.14.tgz", + "integrity": "sha512-nAP5FBxBJGQ/YfUB+r+O6USFVkWq3gAInkxyEnmvEV5jtSbfDhfa4hwX8CraCnbjMLsE7XSf/K75l9xXY7joWg==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -1133,6 +2301,8 @@ }, "node_modules/@radix-ui/react-tooltip": { "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz", + "integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.2", @@ -1165,6 +2335,8 @@ }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1178,6 +2350,8 @@ }, "node_modules/@radix-ui/react-use-controllable-state": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", "license": "MIT", "dependencies": { "@radix-ui/react-use-effect-event": "0.0.2", @@ -1195,6 +2369,8 @@ }, "node_modules/@radix-ui/react-use-effect-event": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1211,6 +2387,8 @@ }, "node_modules/@radix-ui/react-use-escape-keydown": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", "license": "MIT", "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.1" @@ -1227,6 +2405,8 @@ }, "node_modules/@radix-ui/react-use-layout-effect": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1240,6 +2420,8 @@ }, "node_modules/@radix-ui/react-use-previous": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -1253,6 +2435,8 @@ }, "node_modules/@radix-ui/react-use-rect": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", "license": "MIT", "dependencies": { "@radix-ui/rect": "1.1.1" @@ -1269,6 +2453,8 @@ }, "node_modules/@radix-ui/react-use-size": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", "license": "MIT", "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" @@ -1285,6 +2471,8 @@ }, "node_modules/@radix-ui/react-visually-hidden": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -1304,44 +2492,301 @@ } } }, - "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "license": "MIT" + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.11", - "dev": true, - "license": "MIT" + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.43.0", + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, "os": [ - "darwin" + "win32" ] }, "node_modules/@tailwindcss/cli": { - "version": "4.1.10", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.11.tgz", + "integrity": "sha512-7RAFOrVaXCFz5ooEG36Kbh+sMJiI2j4+Ozp71smgjnLfBRu7DTfoq8DsTvzse2/6nDeo2M3vS/FGaxfDgr3rtQ==", "license": "MIT", "dependencies": { "@parcel/watcher": "^2.5.1", - "@tailwindcss/node": "4.1.10", - "@tailwindcss/oxide": "4.1.10", + "@tailwindcss/node": "4.1.11", + "@tailwindcss/oxide": "4.1.11", "enhanced-resolve": "^5.18.1", "mri": "^1.2.0", "picocolors": "^1.1.1", - "tailwindcss": "4.1.10" + "tailwindcss": "4.1.11" }, "bin": { "tailwindcss": "dist/index.mjs" } }, "node_modules/@tailwindcss/node": { - "version": "4.1.10", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz", + "integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -1350,11 +2795,13 @@ "lightningcss": "1.30.1", "magic-string": "^0.30.17", "source-map-js": "^1.2.1", - "tailwindcss": "4.1.10" + "tailwindcss": "4.1.11" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.1.10", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.11.tgz", + "integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -1365,22 +2812,40 @@ "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.10", - "@tailwindcss/oxide-darwin-arm64": "4.1.10", - "@tailwindcss/oxide-darwin-x64": "4.1.10", - "@tailwindcss/oxide-freebsd-x64": "4.1.10", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.10", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.10", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.10", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.10", - "@tailwindcss/oxide-linux-x64-musl": "4.1.10", - "@tailwindcss/oxide-wasm32-wasi": "4.1.10", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.10", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.10" + "@tailwindcss/oxide-android-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-x64": "4.1.11", + "@tailwindcss/oxide-freebsd-x64": "4.1.11", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-x64-musl": "4.1.11", + "@tailwindcss/oxide-wasm32-wasi": "4.1.11", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz", + "integrity": "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.10", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz", + "integrity": "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==", "cpu": [ "arm64" ], @@ -1393,23 +2858,209 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz", + "integrity": "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz", + "integrity": "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz", + "integrity": "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz", + "integrity": "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz", + "integrity": "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz", + "integrity": "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz", + "integrity": "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz", + "integrity": "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.11", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz", + "integrity": "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz", + "integrity": "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/@tailwindcss/vite": { - "version": "4.1.10", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.11.tgz", + "integrity": "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==", "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.1.10", - "@tailwindcss/oxide": "4.1.10", - "tailwindcss": "4.1.10" + "@tailwindcss/node": "4.1.11", + "@tailwindcss/oxide": "4.1.11", + "tailwindcss": "4.1.11" }, "peerDependencies": { - "vite": "^5.2.0 || ^6" + "vite": "^5.2.0 || ^6 || ^7" } }, "node_modules/@tanstack/react-virtual": { - "version": "3.13.10", + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.12.tgz", + "integrity": "sha512-Gd13QdxPSukP8ZrkbgS2RwoZseTTbQPLnQEn7HY/rqtM+8Zt95f7xKC7N0EsKs7aoz0WzZ+fditZux+F8EzYxA==", "license": "MIT", "dependencies": { - "@tanstack/virtual-core": "3.13.10" + "@tanstack/virtual-core": "3.13.12" }, "funding": { "type": "github", @@ -1421,7 +3072,9 @@ } }, "node_modules/@tanstack/virtual-core": { - "version": "3.13.10", + "version": "3.13.12", + "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.12.tgz", + "integrity": "sha512-1YBOJfRHV4sXUmWsFSf5rQor4Ss82G8dQWLRbnk3GA4jeP8hQt1hxXh0tmflpC0dz3VgEv/1+qwPyLeWkQuPFA==", "license": "MIT", "funding": { "type": "github", @@ -1429,7 +3082,9 @@ } }, "node_modules/@tauri-apps/api": { - "version": "2.5.0", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.7.0.tgz", + "integrity": "sha512-v7fVE8jqBl8xJFOcBafDzXFc8FnicoH3j8o8DNNs0tHuEBmXUDqrCOAzMRX0UkfpwqZLqvrvK0GNQ45DfnoVDg==", "license": "Apache-2.0 OR MIT", "funding": { "type": "opencollective", @@ -1654,35 +3309,45 @@ } }, "node_modules/@tauri-apps/plugin-dialog": { - "version": "2.2.2", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.3.2.tgz", + "integrity": "sha512-cNLo9YeQSC0MF4IgXnotHsqEgJk72MBZLXmQPrLA95qTaaWiiaFQ38hIMdZ6YbGUNkr3oni3EhU+AD5jLHcdUA==", "license": "MIT OR Apache-2.0", "dependencies": { - "@tauri-apps/api": "^2.0.0" + "@tauri-apps/api": "^2.6.0" } }, "node_modules/@tauri-apps/plugin-global-shortcut": { - "version": "2.2.1", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-global-shortcut/-/plugin-global-shortcut-2.3.0.tgz", + "integrity": "sha512-WbAz0ElhpP+0kzQZRScdCC7UQ7OPH8PAn//fsBNu7+ywihsnVSVOg1L9YhieAtLNtAlnmFI69Yl5AGaA3ge5IQ==", "license": "MIT OR Apache-2.0", "dependencies": { - "@tauri-apps/api": "^2.0.0" + "@tauri-apps/api": "^2.6.0" } }, "node_modules/@tauri-apps/plugin-opener": { - "version": "2.3.0", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.4.0.tgz", + "integrity": "sha512-43VyN8JJtvKWJY72WI/KNZszTpDpzHULFxQs0CJBIYUdCRowQ6Q1feWTDb979N7nldqSuDOaBupZ6wz2nvuWwQ==", "license": "MIT OR Apache-2.0", "dependencies": { - "@tauri-apps/api": "^2.0.0" + "@tauri-apps/api": "^2.6.0" } }, "node_modules/@tauri-apps/plugin-shell": { - "version": "2.2.2", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-shell/-/plugin-shell-2.3.0.tgz", + "integrity": "sha512-6GIRxO2z64uxPX4CCTuhQzefvCC0ew7HjdBhMALiGw74vFBDY95VWueAHOHgNOMV4UOUAFupyidN9YulTe5xlA==", "license": "MIT OR Apache-2.0", "dependencies": { - "@tauri-apps/api": "^2.0.0" + "@tauri-apps/api": "^2.6.0" } }, "node_modules/@types/babel__core": { "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "license": "MIT", "dependencies": { @@ -1695,6 +3360,8 @@ }, "node_modules/@types/babel__generator": { "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "dev": true, "license": "MIT", "dependencies": { @@ -1703,6 +3370,8 @@ }, "node_modules/@types/babel__template": { "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "license": "MIT", "dependencies": { @@ -1711,27 +3380,37 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.7", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/d3-array": { "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==", "license": "MIT" }, "node_modules/@types/d3-color": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", "license": "MIT" }, "node_modules/@types/d3-ease": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", "license": "MIT" }, "node_modules/@types/d3-interpolate": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", "license": "MIT", "dependencies": { "@types/d3-color": "*" @@ -1739,10 +3418,14 @@ }, "node_modules/@types/d3-path": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", "license": "MIT" }, "node_modules/@types/d3-scale": { "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", "license": "MIT", "dependencies": { "@types/d3-time": "*" @@ -1750,6 +3433,8 @@ }, "node_modules/@types/d3-shape": { "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", "license": "MIT", "dependencies": { "@types/d3-path": "*" @@ -1757,14 +3442,20 @@ }, "node_modules/@types/d3-time": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", "license": "MIT" }, "node_modules/@types/d3-timer": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "@types/ms": "*" @@ -1772,6 +3463,8 @@ }, "node_modules/@types/diff": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/diff/-/diff-8.0.0.tgz", + "integrity": "sha512-o7jqJM04gfaYrdCecCVMbZhNdG6T1MHg/oQoRFdERLV+4d+V7FijhiEAbFu0Usww84Yijk9yH58U4Jk4HbtzZw==", "deprecated": "This is a stub types definition. diff provides its own type definitions, so you do not need this installed.", "license": "MIT", "dependencies": { @@ -1779,11 +3472,15 @@ } }, "node_modules/@types/estree": { - "version": "1.0.7", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "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==", "license": "MIT", "dependencies": { "@types/estree": "*" @@ -1791,6 +3488,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -1798,6 +3497,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/unist": "*" @@ -1805,10 +3506,14 @@ }, "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==", "license": "MIT" }, "node_modules/@types/node": { - "version": "22.15.32", + "version": "22.17.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.1.tgz", + "integrity": "sha512-y3tBaz+rjspDTylNjAX37jEC3TETEFGNJL6uQDxwF9/8GLLIjW1rvVHlynyuUKMnMr1Roq8jOv3vkopBjC4/VA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -1817,14 +3522,20 @@ }, "node_modules/@types/prismjs": { "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", "license": "MIT" }, "node_modules/@types/prop-types": { "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.23", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.23.tgz", + "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -1833,6 +3544,8 @@ }, "node_modules/@types/react-dom": { "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", "devOptional": true, "license": "MIT", "peerDependencies": { @@ -1841,6 +3554,8 @@ }, "node_modules/@types/react-syntax-highlighter": { "version": "15.5.13", + "resolved": "https://registry.npmjs.org/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.13.tgz", + "integrity": "sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==", "license": "MIT", "dependencies": { "@types/react": "*" @@ -1848,6 +3563,8 @@ }, "node_modules/@types/sharp": { "version": "0.32.0", + "resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.32.0.tgz", + "integrity": "sha512-OOi3kL+FZDnPhVzsfD37J88FNeZh6gQsGcLc95NbeURRGvmSjeXiDcyWzF2o3yh/gQAUn2uhh/e+CPCa5nwAxw==", "deprecated": "This is a stub types definition. sharp provides its own type definitions, so you do not need this installed.", "dev": true, "license": "MIT", @@ -1857,17 +3574,23 @@ }, "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==", "license": "MIT" }, "node_modules/@uiw/copy-to-clipboard": { "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@uiw/copy-to-clipboard/-/copy-to-clipboard-1.0.17.tgz", + "integrity": "sha512-O2GUHV90Iw2VrSLVLK0OmNIMdZ5fgEg4NhvtwINsX+eZ/Wf6DWD0TdsK9xwV7dNRnK/UI2mQtl0a2/kRgm1m1A==", "license": "MIT", "funding": { "url": "https://jaywcjlove.github.io/#/sponsor" } }, "node_modules/@uiw/react-markdown-preview": { - "version": "5.1.4", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@uiw/react-markdown-preview/-/react-markdown-preview-5.1.5.tgz", + "integrity": "sha512-DNOqx1a6gJR7Btt57zpGEKTfHRlb7rWbtctMRO2f82wWcuoJsxPBrM+JWebDdOD0LfD8oe2CQvW2ICQJKHQhZg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.17.2", @@ -1892,69 +3615,38 @@ "react-dom": ">=16.8.0" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/react-markdown": { - "version": "9.0.3", + "node_modules/@uiw/react-markdown-preview/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==", + "license": "MIT" + }, + "node_modules/@uiw/react-markdown-preview/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", "license": "MIT", "dependencies": { - "@types/hast": "^3.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" + "@types/hast": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" - }, - "peerDependencies": { - "@types/react": ">=18", - "react": ">=18" - } - }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus": { - "version": "2.0.0", - "license": "MIT", - "dependencies": { - "hast-util-to-string": "^3.0.0", - "parse-numeric-range": "^1.3.0", - "refractor": "^4.8.0", - "rehype-parse": "^9.0.0", - "unist-util-filter": "^5.0.0", - "unist-util-visit": "^5.0.0" - } - }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor": { - "version": "4.9.0", - "license": "MIT", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/prismjs": "^1.0.0", - "hastscript": "^7.0.0", - "parse-entities": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/@types/hast": { + "node_modules/@uiw/react-markdown-preview/node_modules/hast-util-parse-selector/node_modules/@types/hast": { "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "license": "MIT", "dependencies": { "@types/unist": "^2" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/@types/hast/node_modules/@types/unist": { - "version": "2.0.11", - "license": "MIT" - }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/hastscript": { + "node_modules/@uiw/react-markdown-preview/node_modules/hastscript": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", "license": "MIT", "dependencies": { "@types/hast": "^2.0.0", @@ -1968,100 +3660,94 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/hastscript/node_modules/hast-util-parse-selector": { - "version": "3.1.1", + "node_modules/@uiw/react-markdown-preview/node_modules/hastscript/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "@types/unist": "^2" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/hastscript/node_modules/property-information": { + "node_modules/@uiw/react-markdown-preview/node_modules/property-information": { "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities": { - "version": "4.0.2", - "license": "MIT", - "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/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "license": "MIT" - }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/character-entities-legacy": { - "version": "3.0.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/character-reference-invalid": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-alphanumerical": { - "version": "2.0.1", + "node_modules/@uiw/react-markdown-preview/node_modules/react-markdown": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.0.3.tgz", + "integrity": "sha512-Yk7Z94dbgYTOrdk41Z74GoKA7rThnsbbqBTRYuxoe08qvfQ9tJVhmAKw6BJS/ZORG7kTy/s1QvYzSuaoBA1qfw==", "license": "MIT", "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" + "@types/hast": "^3.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": "github", - "url": "https://github.com/sponsors/wooorm" + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-alphanumerical/node_modules/is-alphabetical": { - "version": "2.0.1", + "node_modules/@uiw/react-markdown-preview/node_modules/refractor": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-4.9.0.tgz", + "integrity": "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og==", "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prismjs": "^1.0.0", + "hastscript": "^7.0.0", + "parse-entities": "^4.0.0" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-decimal": { - "version": "2.0.1", + "node_modules/@uiw/react-markdown-preview/node_modules/refractor/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "@types/unist": "^2" } }, - "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-hexadecimal": { - "version": "2.0.1", + "node_modules/@uiw/react-markdown-preview/node_modules/rehype-prism-plus": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz", + "integrity": "sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ==", "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "dependencies": { + "hast-util-to-string": "^3.0.0", + "parse-numeric-range": "^1.3.0", + "refractor": "^4.8.0", + "rehype-parse": "^9.0.0", + "unist-util-filter": "^5.0.0", + "unist-util-visit": "^5.0.0" } }, "node_modules/@uiw/react-md-editor": { - "version": "4.0.7", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@uiw/react-md-editor/-/react-md-editor-4.0.8.tgz", + "integrity": "sha512-S3mOzZeGmJNhzdXJxRTCwsFMDp8nBWeQUf59cK3L6QHzDUHnRoHpcmWpfVRyKGKSg8zaI2+meU5cYWf8kYn3mQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.14.6", @@ -2079,17 +3765,21 @@ }, "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==", "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.5.2", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.27.4", + "@babel/core": "^7.28.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.11", + "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "^7.20.5", "react-refresh": "^0.17.0" }, @@ -2097,11 +3787,13 @@ "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/ansi-to-html": { "version": "0.7.2", + "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", + "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", "license": "MIT", "dependencies": { "entities": "^2.2.0" @@ -2115,6 +3807,8 @@ }, "node_modules/aria-hidden": { "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -2125,6 +3819,8 @@ }, "node_modules/bail": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", "license": "MIT", "funding": { "type": "github", @@ -2133,6 +3829,8 @@ }, "node_modules/base64-arraybuffer": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", "license": "MIT", "engines": { "node": ">= 0.6.0" @@ -2140,6 +3838,8 @@ }, "node_modules/bcp-47-match": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz", + "integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==", "license": "MIT", "funding": { "type": "github", @@ -2148,10 +3848,14 @@ }, "node_modules/boolbase": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, "node_modules/braces": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -2161,7 +3865,9 @@ } }, "node_modules/browserslist": { - "version": "4.25.0", + "version": "4.25.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.2.tgz", + "integrity": "sha512-0si2SJK3ooGzIawRu61ZdPCO1IncZwS8IzuX73sPZsXW6EQ/w/DAfPyKI8l1ETTCr2MnvqWitmlCUxgdul45jA==", "dev": true, "funding": [ { @@ -2179,8 +3885,8 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001718", - "electron-to-chromium": "^1.5.160", + "caniuse-lite": "^1.0.30001733", + "electron-to-chromium": "^1.5.199", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.3" }, @@ -2192,7 +3898,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001723", + "version": "1.0.30001734", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001734.tgz", + "integrity": "sha512-uhE1Ye5vgqju6OI71HTQqcBCZrvHugk0MjLak7Q+HfoBgoq5Bi+5YnwjP4fjDgrtYr/l8MVRBvzz9dPD4KyK0A==", "dev": true, "funding": [ { @@ -2212,6 +3920,8 @@ }, "node_modules/ccount": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "license": "MIT", "funding": { "type": "github", @@ -2219,7 +3929,9 @@ } }, "node_modules/character-entities": { - "version": "1.2.4", + "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==", "license": "MIT", "funding": { "type": "github", @@ -2228,6 +3940,8 @@ }, "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==", "license": "MIT", "funding": { "type": "github", @@ -2235,7 +3949,9 @@ } }, "node_modules/character-entities-legacy": { - "version": "1.1.4", + "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==", "license": "MIT", "funding": { "type": "github", @@ -2243,7 +3959,9 @@ } }, "node_modules/character-reference-invalid": { - "version": "1.1.4", + "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==", "license": "MIT", "funding": { "type": "github", @@ -2252,6 +3970,8 @@ }, "node_modules/chownr": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "license": "BlueOak-1.0.0", "engines": { "node": ">=18" @@ -2259,6 +3979,8 @@ }, "node_modules/class-variance-authority": { "version": "0.7.1", + "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", + "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", "license": "Apache-2.0", "dependencies": { "clsx": "^2.1.1" @@ -2269,6 +3991,8 @@ }, "node_modules/clsx": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", "license": "MIT", "engines": { "node": ">=6" @@ -2276,6 +4000,8 @@ }, "node_modules/color": { "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", "dev": true, "license": "MIT", "dependencies": { @@ -2288,6 +4014,8 @@ }, "node_modules/color-convert": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2299,11 +4027,15 @@ }, "node_modules/color-name": { "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, "node_modules/color-string": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -2313,6 +4045,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==", "license": "MIT", "funding": { "type": "github", @@ -2321,6 +4055,8 @@ }, "node_modules/convert-source-map": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true, "license": "MIT" }, @@ -2337,13 +4073,17 @@ }, "node_modules/css-line-break": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", "license": "MIT", "dependencies": { "utrie": "^1.0.2" } }, "node_modules/css-selector-parser": { - "version": "3.1.2", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/css-selector-parser/-/css-selector-parser-3.1.3.tgz", + "integrity": "sha512-gJMigczVZqYAk0hPVzx/M4Hm1D9QOtqkdQk9005TNzDIUGzo5cnHEDiKUT7jGPximL/oYb+LIitcHFQ4aKupxg==", "funding": [ { "type": "github", @@ -2358,10 +4098,14 @@ }, "node_modules/csstype": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, "node_modules/d3-array": { "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "license": "ISC", "dependencies": { "internmap": "1 - 2" @@ -2372,6 +4116,8 @@ }, "node_modules/d3-color": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "license": "ISC", "engines": { "node": ">=12" @@ -2379,6 +4125,8 @@ }, "node_modules/d3-ease": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", "license": "BSD-3-Clause", "engines": { "node": ">=12" @@ -2386,6 +4134,8 @@ }, "node_modules/d3-format": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", "license": "ISC", "engines": { "node": ">=12" @@ -2393,6 +4143,8 @@ }, "node_modules/d3-interpolate": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "license": "ISC", "dependencies": { "d3-color": "1 - 3" @@ -2403,6 +4155,8 @@ }, "node_modules/d3-path": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "license": "ISC", "engines": { "node": ">=12" @@ -2410,6 +4164,8 @@ }, "node_modules/d3-scale": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", "license": "ISC", "dependencies": { "d3-array": "2.10.0 - 3", @@ -2424,6 +4180,8 @@ }, "node_modules/d3-shape": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", "license": "ISC", "dependencies": { "d3-path": "^3.1.0" @@ -2434,6 +4192,8 @@ }, "node_modules/d3-time": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "license": "ISC", "dependencies": { "d3-array": "2 - 3" @@ -2444,6 +4204,8 @@ }, "node_modules/d3-time-format": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", "license": "ISC", "dependencies": { "d3-time": "1 - 3" @@ -2454,6 +4216,8 @@ }, "node_modules/d3-timer": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", "license": "ISC", "engines": { "node": ">=12" @@ -2461,6 +4225,8 @@ }, "node_modules/date-fns": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", "license": "MIT", "funding": { "type": "github", @@ -2469,6 +4235,8 @@ }, "node_modules/debug": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2484,10 +4252,14 @@ }, "node_modules/decimal.js-light": { "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", "license": "MIT" }, "node_modules/decode-named-character-reference": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", "license": "MIT", "dependencies": { "character-entities": "^2.0.0" @@ -2497,34 +4269,37 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decode-named-character-reference/node_modules/character-entities": { - "version": "2.0.2", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/dequal": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/detect-libc": { - "version": "2.0.4", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, "engines": { - "node": ">=8" + "node": ">=0.10" } }, "node_modules/detect-node-es": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, "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==", "license": "MIT", "dependencies": { "dequal": "^2.0.0" @@ -2536,6 +4311,8 @@ }, "node_modules/diff": { "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -2543,6 +4320,8 @@ }, "node_modules/direction": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/direction/-/direction-2.0.1.tgz", + "integrity": "sha512-9S6m9Sukh1cZNknO1CWAr2QAWsbKLafQiyM5gZ7VgXHeuaoUwffKN4q6NC4A/Mf9iiPlOXQEKW/Mv/mh9/3YFA==", "license": "MIT", "bin": { "direction": "cli.js" @@ -2554,6 +4333,8 @@ }, "node_modules/dom-helpers": { "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.7", @@ -2561,12 +4342,16 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.169", + "version": "1.5.200", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.200.tgz", + "integrity": "sha512-rFCxROw7aOe4uPTfIAx+rXv9cEcGx+buAF4npnhtTqCJk5KDFRnh3+KYj7rdVh6lsFt5/aPs+Irj9rZ33WMA7w==", "dev": true, "license": "ISC" }, "node_modules/enhanced-resolve": { - "version": "5.18.1", + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -2578,13 +4363,17 @@ }, "node_modules/entities": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/esbuild": { - "version": "0.25.5", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.9.tgz", + "integrity": "sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -2594,35 +4383,38 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.5", - "@esbuild/android-arm": "0.25.5", - "@esbuild/android-arm64": "0.25.5", - "@esbuild/android-x64": "0.25.5", - "@esbuild/darwin-arm64": "0.25.5", - "@esbuild/darwin-x64": "0.25.5", - "@esbuild/freebsd-arm64": "0.25.5", - "@esbuild/freebsd-x64": "0.25.5", - "@esbuild/linux-arm": "0.25.5", - "@esbuild/linux-arm64": "0.25.5", - "@esbuild/linux-ia32": "0.25.5", - "@esbuild/linux-loong64": "0.25.5", - "@esbuild/linux-mips64el": "0.25.5", - "@esbuild/linux-ppc64": "0.25.5", - "@esbuild/linux-riscv64": "0.25.5", - "@esbuild/linux-s390x": "0.25.5", - "@esbuild/linux-x64": "0.25.5", - "@esbuild/netbsd-arm64": "0.25.5", - "@esbuild/netbsd-x64": "0.25.5", - "@esbuild/openbsd-arm64": "0.25.5", - "@esbuild/openbsd-x64": "0.25.5", - "@esbuild/sunos-x64": "0.25.5", - "@esbuild/win32-arm64": "0.25.5", - "@esbuild/win32-ia32": "0.25.5", - "@esbuild/win32-x64": "0.25.5" + "@esbuild/aix-ppc64": "0.25.9", + "@esbuild/android-arm": "0.25.9", + "@esbuild/android-arm64": "0.25.9", + "@esbuild/android-x64": "0.25.9", + "@esbuild/darwin-arm64": "0.25.9", + "@esbuild/darwin-x64": "0.25.9", + "@esbuild/freebsd-arm64": "0.25.9", + "@esbuild/freebsd-x64": "0.25.9", + "@esbuild/linux-arm": "0.25.9", + "@esbuild/linux-arm64": "0.25.9", + "@esbuild/linux-ia32": "0.25.9", + "@esbuild/linux-loong64": "0.25.9", + "@esbuild/linux-mips64el": "0.25.9", + "@esbuild/linux-ppc64": "0.25.9", + "@esbuild/linux-riscv64": "0.25.9", + "@esbuild/linux-s390x": "0.25.9", + "@esbuild/linux-x64": "0.25.9", + "@esbuild/netbsd-arm64": "0.25.9", + "@esbuild/netbsd-x64": "0.25.9", + "@esbuild/openbsd-arm64": "0.25.9", + "@esbuild/openbsd-x64": "0.25.9", + "@esbuild/openharmony-arm64": "0.25.9", + "@esbuild/sunos-x64": "0.25.9", + "@esbuild/win32-arm64": "0.25.9", + "@esbuild/win32-ia32": "0.25.9", + "@esbuild/win32-x64": "0.25.9" } }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -2631,6 +4423,8 @@ }, "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==", "license": "MIT", "engines": { "node": ">=12" @@ -2641,6 +4435,8 @@ }, "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==", "license": "MIT", "funding": { "type": "opencollective", @@ -2649,14 +4445,20 @@ }, "node_modules/eventemitter3": { "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, "node_modules/extend": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, "node_modules/fast-equals": { "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", + "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", "license": "MIT", "engines": { "node": ">=6.0.0" @@ -2664,6 +4466,8 @@ }, "node_modules/fault": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", "license": "MIT", "dependencies": { "format": "^0.2.0" @@ -2673,18 +4477,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/fdir": { - "version": "6.4.6", - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/fflate": { "version": "0.4.8", "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", @@ -2693,6 +4485,8 @@ }, "node_modules/fill-range": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -2703,16 +4497,20 @@ }, "node_modules/format": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", "engines": { "node": ">=0.4.x" } }, "node_modules/framer-motion": { - "version": "12.18.1", + "version": "12.23.12", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.12.tgz", + "integrity": "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==", "license": "MIT", "dependencies": { - "motion-dom": "^12.18.1", - "motion-utils": "^12.18.1", + "motion-dom": "^12.23.12", + "motion-utils": "^12.23.6", "tslib": "^2.4.0" }, "peerDependencies": { @@ -2734,6 +4532,9 @@ }, "node_modules/fsevents": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -2745,6 +4546,8 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "license": "MIT", "engines": { @@ -2753,6 +4556,8 @@ }, "node_modules/get-nonce": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", "license": "MIT", "engines": { "node": ">=6" @@ -2760,22 +4565,20 @@ }, "node_modules/github-slugger": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==", "license": "ISC" }, - "node_modules/globals": { - "version": "11.12.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, "node_modules/hast-util-from-html": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.3.tgz", + "integrity": "sha512-CUSRHXyKjzHov8yKsQjGOElXy/3EKpyX56ELnkHH34vDVw1N1XSQ1ZcAvTyAPtGqLTuKP/uxM+aLkSPqF/EtMw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -2792,6 +4595,8 @@ }, "node_modules/hast-util-from-parse5": { "version": "8.0.3", + "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.3.tgz", + "integrity": "sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -2808,26 +4613,30 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/hastscript": { - "version": "9.0.1", + "node_modules/hast-util-from-parse5/node_modules/hast-util-parse-selector": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", + "integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==", "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^4.0.0", - "property-information": "^7.0.0", - "space-separated-tokens": "^2.0.0" + "@types/hast": "^3.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/hast-util-from-parse5/node_modules/hastscript/node_modules/hast-util-parse-selector": { - "version": "4.0.0", + "node_modules/hast-util-from-parse5/node_modules/hastscript": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.1.tgz", + "integrity": "sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==", "license": "MIT", "dependencies": { - "@types/hast": "^3.0.0" + "@types/hast": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^4.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0" }, "funding": { "type": "opencollective", @@ -2836,6 +4645,8 @@ }, "node_modules/hast-util-has-property": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-3.0.0.tgz", + "integrity": "sha512-MNilsvEKLFpV604hwfhVStK0usFY/QmM5zX16bo7EjnAEGofr5YyI37kzopBlZJkHD4t887i+q/C8/tr5Q94cA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -2847,6 +4658,8 @@ }, "node_modules/hast-util-heading-rank": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -2858,6 +4671,8 @@ }, "node_modules/hast-util-is-element": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -2869,6 +4684,8 @@ }, "node_modules/hast-util-parse-selector": { "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", "license": "MIT", "funding": { "type": "opencollective", @@ -2877,6 +4694,8 @@ }, "node_modules/hast-util-raw": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-9.1.0.tgz", + "integrity": "sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -2900,6 +4719,8 @@ }, "node_modules/hast-util-select": { "version": "6.0.4", + "resolved": "https://registry.npmjs.org/hast-util-select/-/hast-util-select-6.0.4.tgz", + "integrity": "sha512-RqGS1ZgI0MwxLaKLDxjprynNzINEkRHY2i8ln4DDjgv9ZhcYVIHN9rlpiYsqtFwrgpYU361SyWDQcGNIBVu3lw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -2925,6 +4746,8 @@ }, "node_modules/hast-util-to-html": { "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -2946,6 +4769,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", @@ -2971,6 +4796,8 @@ }, "node_modules/hast-util-to-parse5": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz", + "integrity": "sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -2988,6 +4815,8 @@ }, "node_modules/hast-util-to-parse5/node_modules/property-information": { "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", "license": "MIT", "funding": { "type": "github", @@ -2996,6 +4825,8 @@ }, "node_modules/hast-util-to-string": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -3007,6 +4838,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" @@ -3018,6 +4851,8 @@ }, "node_modules/hastscript": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", "license": "MIT", "dependencies": { "@types/hast": "^2.0.0", @@ -3033,17 +4868,23 @@ }, "node_modules/hastscript/node_modules/@types/hast": { "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "license": "MIT", "dependencies": { "@types/unist": "^2" } }, - "node_modules/hastscript/node_modules/@types/hast/node_modules/@types/unist": { + "node_modules/hastscript/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==", "license": "MIT" }, "node_modules/hastscript/node_modules/comma-separated-tokens": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", "license": "MIT", "funding": { "type": "github", @@ -3052,6 +4893,8 @@ }, "node_modules/hastscript/node_modules/property-information": { "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", "license": "MIT", "dependencies": { "xtend": "^4.0.0" @@ -3063,6 +4906,8 @@ }, "node_modules/hastscript/node_modules/space-separated-tokens": { "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", "license": "MIT", "funding": { "type": "github", @@ -3071,6 +4916,8 @@ }, "node_modules/highlight.js": { "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", "license": "BSD-3-Clause", "engines": { "node": "*" @@ -3078,10 +4925,14 @@ }, "node_modules/highlightjs-vue": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", "license": "CC0-1.0" }, "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==", "license": "MIT", "funding": { "type": "opencollective", @@ -3090,6 +4941,8 @@ }, "node_modules/html-void-elements": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", "license": "MIT", "funding": { "type": "github", @@ -3098,6 +4951,8 @@ }, "node_modules/html2canvas": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", "license": "MIT", "dependencies": { "css-line-break": "^2.1.0", @@ -3109,17 +4964,23 @@ }, "node_modules/inline-style-parser": { "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", "license": "MIT" }, "node_modules/internmap": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/is-alphabetical": { - "version": "1.0.4", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", "license": "MIT", "funding": { "type": "github", @@ -3127,11 +4988,13 @@ } }, "node_modules/is-alphanumerical": { - "version": "1.0.4", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", "license": "MIT", "dependencies": { - "is-alphabetical": "^1.0.0", - "is-decimal": "^1.0.0" + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" }, "funding": { "type": "github", @@ -3140,11 +5003,15 @@ }, "node_modules/is-arrayish": { "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "dev": true, "license": "MIT" }, "node_modules/is-decimal": { - "version": "1.0.4", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", "license": "MIT", "funding": { "type": "github", @@ -3153,6 +5020,8 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -3160,6 +5029,8 @@ }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -3169,7 +5040,9 @@ } }, "node_modules/is-hexadecimal": { - "version": "1.0.4", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", "license": "MIT", "funding": { "type": "github", @@ -3178,89 +5051,285 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=0.12.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "license": "MIT", + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/jiti": { - "version": "2.4.2", - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/json5": { - "version": "2.2.3", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/lightningcss": { + "node_modules/lightningcss-win32-arm64-msvc": { "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">= 12.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.30.1", - "lightningcss-darwin-x64": "1.30.1", - "lightningcss-freebsd-x64": "1.30.1", - "lightningcss-linux-arm-gnueabihf": "1.30.1", - "lightningcss-linux-arm64-gnu": "1.30.1", - "lightningcss-linux-arm64-musl": "1.30.1", - "lightningcss-linux-x64-gnu": "1.30.1", - "lightningcss-linux-x64-musl": "1.30.1", - "lightningcss-win32-arm64-msvc": "1.30.1", - "lightningcss-win32-x64-msvc": "1.30.1" } }, - "node_modules/lightningcss-darwin-arm64": { + "node_modules/lightningcss-win32-x64-msvc": { "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", "cpu": [ - "arm64" + "x64" ], "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "win32" ], "engines": { "node": ">= 12.0.0" @@ -3270,12 +5339,25 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, "node_modules/lodash": { "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "license": "MIT" }, "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==", "license": "MIT", "funding": { "type": "github", @@ -3284,6 +5366,8 @@ }, "node_modules/loose-envify": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -3294,6 +5378,8 @@ }, "node_modules/lowlight": { "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", "license": "MIT", "dependencies": { "fault": "^1.0.0", @@ -3306,19 +5392,18 @@ }, "node_modules/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, "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, - "node_modules/lru-cache/node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, "node_modules/lucide-react": { "version": "0.468.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.468.0.tgz", + "integrity": "sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==", "license": "ISC", "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" @@ -3326,6 +5411,8 @@ }, "node_modules/magic-string": { "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" @@ -3333,6 +5420,8 @@ }, "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==", "license": "MIT", "funding": { "type": "github", @@ -3341,6 +5430,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3355,6 +5446,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3377,6 +5470,8 @@ }, "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==", "license": "MIT", "dependencies": { "mdast-util-from-markdown": "^2.0.0", @@ -3394,6 +5489,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3409,6 +5506,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3424,6 +5523,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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3437,6 +5538,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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3452,6 +5555,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3466,6 +5571,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==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -3482,6 +5589,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==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -3502,81 +5611,10 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities": { - "version": "4.0.2", - "license": "MIT", - "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/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "license": "MIT" - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/character-entities-legacy": { - "version": "3.0.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/character-reference-invalid": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/is-alphanumerical": { - "version": "2.0.1", - "license": "MIT", - "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/is-alphanumerical/node_modules/is-alphabetical": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/is-decimal": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/mdast-util-mdx-jsx/node_modules/parse-entities/node_modules/is-hexadecimal": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "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==", "license": "MIT", "dependencies": { "@types/estree-jsx": "^1.0.0", @@ -3593,6 +5631,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3605,6 +5645,8 @@ }, "node_modules/mdast-util-to-hast": { "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -3624,6 +5666,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -3643,6 +5687,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0" @@ -3654,6 +5700,8 @@ }, "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", @@ -3687,6 +5735,8 @@ }, "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", @@ -3719,6 +5769,8 @@ }, "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==", "license": "MIT", "dependencies": { "micromark-extension-gfm-autolink-literal": "^2.0.0", @@ -3737,6 +5789,8 @@ }, "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==", "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", @@ -3751,6 +5805,8 @@ }, "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==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -3769,6 +5825,8 @@ }, "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==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -3785,6 +5843,8 @@ }, "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==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -3800,6 +5860,8 @@ }, "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==", "license": "MIT", "dependencies": { "micromark-util-types": "^2.0.0" @@ -3811,6 +5873,8 @@ }, "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==", "license": "MIT", "dependencies": { "devlop": "^1.0.0", @@ -3826,6 +5890,8 @@ }, "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", @@ -3845,6 +5911,8 @@ }, "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", @@ -3865,6 +5933,8 @@ }, "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", @@ -3883,6 +5953,8 @@ }, "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", @@ -3903,6 +5975,8 @@ }, "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", @@ -3923,6 +5997,8 @@ }, "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", @@ -3941,6 +6017,8 @@ }, "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", @@ -3958,6 +6036,8 @@ }, "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", @@ -3977,6 +6057,8 @@ }, "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", @@ -3995,6 +6077,8 @@ }, "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", @@ -4012,6 +6096,8 @@ }, "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", @@ -4032,6 +6118,8 @@ }, "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", @@ -4046,6 +6134,8 @@ }, "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", @@ -4060,6 +6150,8 @@ }, "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", @@ -4077,6 +6169,8 @@ }, "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", @@ -4094,6 +6188,8 @@ }, "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", @@ -4113,6 +6209,8 @@ }, "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", @@ -4133,6 +6231,8 @@ }, "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", @@ -4147,6 +6247,8 @@ }, "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", @@ -4161,6 +6263,8 @@ }, "node_modules/micromatch": { "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -4170,18 +6274,10 @@ "node": ">=8.6" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/minipass": { "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -4189,6 +6285,8 @@ }, "node_modules/minizlib": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", "license": "MIT", "dependencies": { "minipass": "^7.1.2" @@ -4199,6 +6297,8 @@ }, "node_modules/mkdirp": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "license": "MIT", "bin": { "mkdirp": "dist/cjs/src/bin.js" @@ -4211,18 +6311,24 @@ } }, "node_modules/motion-dom": { - "version": "12.18.1", + "version": "12.23.12", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.12.tgz", + "integrity": "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==", "license": "MIT", "dependencies": { - "motion-utils": "^12.18.1" + "motion-utils": "^12.23.6" } }, "node_modules/motion-utils": { - "version": "12.18.1", + "version": "12.23.6", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", + "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", "license": "MIT" }, "node_modules/mri": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "license": "MIT", "engines": { "node": ">=4" @@ -4230,19 +6336,45 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/node-addon-api": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, "license": "MIT" }, "node_modules/nth-check": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" @@ -4253,33 +6385,48 @@ }, "node_modules/object-assign": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/parse-entities": { - "version": "2.0.0", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", "license": "MIT", "dependencies": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" + "@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==", + "license": "MIT" + }, "node_modules/parse-numeric-range": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz", + "integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==", "license": "ISC" }, "node_modules/parse5": { "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -4290,6 +6437,8 @@ }, "node_modules/parse5/node_modules/entities": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -4300,13 +6449,17 @@ }, "node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.2", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -4314,6 +6467,8 @@ }, "node_modules/postcss": { "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -4331,27 +6486,11 @@ "license": "MIT", "dependencies": { "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.11", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^10 || ^12 || >=14" } }, "node_modules/posthog-js": { @@ -4390,6 +6529,8 @@ }, "node_modules/prismjs": { "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", "license": "MIT", "engines": { "node": ">=6" @@ -4397,6 +6538,8 @@ }, "node_modules/prop-types": { "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -4406,10 +6549,14 @@ }, "node_modules/prop-types/node_modules/react-is": { "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, "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==", "license": "MIT", "funding": { "type": "github", @@ -4418,6 +6565,8 @@ }, "node_modules/react": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -4428,6 +6577,8 @@ }, "node_modules/react-dom": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -4438,7 +6589,9 @@ } }, "node_modules/react-hook-form": { - "version": "7.58.1", + "version": "7.62.0", + "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.62.0.tgz", + "integrity": "sha512-7KWFejc98xqG/F4bAxpL41NB3o1nnvQO1RWZT3TqRZYL8RryQETGfEdVnJN2fy1crCiBLLjkRBVK05j24FxJGA==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -4453,10 +6606,14 @@ }, "node_modules/react-is": { "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "license": "MIT" }, "node_modules/react-markdown": { "version": "9.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.1.0.tgz", + "integrity": "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4482,6 +6639,8 @@ }, "node_modules/react-refresh": { "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", "dev": true, "license": "MIT", "engines": { @@ -4490,6 +6649,8 @@ }, "node_modules/react-remove-scroll": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", "license": "MIT", "dependencies": { "react-remove-scroll-bar": "^2.3.7", @@ -4513,6 +6674,8 @@ }, "node_modules/react-remove-scroll-bar": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", "dependencies": { "react-style-singleton": "^2.2.2", @@ -4533,6 +6696,8 @@ }, "node_modules/react-smooth": { "version": "4.0.4", + "resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-4.0.4.tgz", + "integrity": "sha512-gnGKTpYwqL0Iii09gHobNolvX4Kiq4PKx6eWBCYYix+8cdw+cGo3do906l1NBPKkSWx1DghC1dlWG9L2uGd61Q==", "license": "MIT", "dependencies": { "fast-equals": "^5.0.1", @@ -4546,6 +6711,8 @@ }, "node_modules/react-style-singleton": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", "dependencies": { "get-nonce": "^1.0.0", @@ -4566,6 +6733,8 @@ }, "node_modules/react-syntax-highlighter": { "version": "15.6.1", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.1.tgz", + "integrity": "sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.3.1", @@ -4581,6 +6750,8 @@ }, "node_modules/react-transition-group": { "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.5.5", @@ -4594,7 +6765,9 @@ } }, "node_modules/recharts": { - "version": "2.15.3", + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-2.15.4.tgz", + "integrity": "sha512-UT/q6fwS3c1dHbXv2uFgYJ9BMFHu3fwnd7AYZaEQhXuYQ4hgsxLvsUXzGdKeZrW5xopzDCvuA2N41WJ88I7zIw==", "license": "MIT", "dependencies": { "clsx": "^2.0.0", @@ -4616,6 +6789,8 @@ }, "node_modules/recharts-scale": { "version": "0.4.5", + "resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz", + "integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==", "license": "MIT", "dependencies": { "decimal.js-light": "^2.4.1" @@ -4623,6 +6798,8 @@ }, "node_modules/refractor": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", "license": "MIT", "dependencies": { "hastscript": "^6.0.0", @@ -4634,8 +6811,102 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/refractor/node_modules/character-entities": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", + "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/character-entities-legacy": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", + "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/character-reference-invalid": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", + "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/is-alphabetical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", + "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/is-alphanumerical": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", + "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/is-decimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", + "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/is-hexadecimal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", + "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/parse-entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", + "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", + "license": "MIT", + "dependencies": { + "character-entities": "^1.0.0", + "character-entities-legacy": "^1.0.0", + "character-reference-invalid": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0", + "is-hexadecimal": "^1.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/refractor/node_modules/prismjs": { "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", "license": "MIT", "engines": { "node": ">=6" @@ -4643,6 +6914,8 @@ }, "node_modules/rehype": { "version": "13.0.2", + "resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.2.tgz", + "integrity": "sha512-j31mdaRFrwFRUIlxGeuPXXKWQxet52RBQRvCmzl5eCefn/KGbomK5GMHNMsOJf55fgo3qw5tST5neDuarDYR2A==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4657,6 +6930,8 @@ }, "node_modules/rehype-attr": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/rehype-attr/-/rehype-attr-3.0.3.tgz", + "integrity": "sha512-Up50Xfra8tyxnkJdCzLBIBtxOcB2M1xdeKe1324U06RAvSjYm7ULSeoM+b/nYPQPVd7jsXJ9+39IG1WAJPXONw==", "license": "MIT", "dependencies": { "unified": "~11.0.0", @@ -4671,6 +6946,8 @@ }, "node_modules/rehype-autolink-headings": { "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", + "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4687,6 +6964,8 @@ }, "node_modules/rehype-ignore": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/rehype-ignore/-/rehype-ignore-2.0.2.tgz", + "integrity": "sha512-BpAT/3lU9DMJ2siYVD/dSR0A/zQgD6Fb+fxkJd4j+wDVy6TYbYpK+FZqu8eM9EuNKGvi4BJR7XTZ/+zF02Dq8w==", "license": "MIT", "dependencies": { "hast-util-select": "^6.0.0", @@ -4702,6 +6981,8 @@ }, "node_modules/rehype-parse": { "version": "9.0.1", + "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", + "integrity": "sha512-ksCzCD0Fgfh7trPDxr2rSylbwq9iYDkSn8TCDmEJ49ljEUBxDVCzCHv7QNzZOfODanX4+bWQ4WZqLCRWYLfhag==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4715,6 +6996,8 @@ }, "node_modules/rehype-prism-plus": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.1.tgz", + "integrity": "sha512-Wglct0OW12tksTUseAPyWPo3srjBOY7xKlql/DPKi7HbsdZTyaLCAoO58QBKSczFQxElTsQlOY3JDOFzB/K++Q==", "license": "MIT", "dependencies": { "hast-util-to-string": "^3.0.0", @@ -4725,140 +7008,81 @@ "unist-util-visit": "^5.0.0" } }, - "node_modules/rehype-prism-plus/node_modules/refractor": { - "version": "4.9.0", - "license": "MIT", - "dependencies": { - "@types/hast": "^2.0.0", - "@types/prismjs": "^1.0.0", - "hastscript": "^7.0.0", - "parse-entities": "^4.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/@types/hast": { + "node_modules/rehype-prism-plus/node_modules/@types/hast": { "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "license": "MIT", "dependencies": { "@types/unist": "^2" } }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/@types/hast/node_modules/@types/unist": { + "node_modules/rehype-prism-plus/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==", "license": "MIT" }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/hastscript": { - "version": "7.2.0", + "node_modules/rehype-prism-plus/node_modules/hast-util-parse-selector": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz", + "integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0", - "comma-separated-tokens": "^2.0.0", - "hast-util-parse-selector": "^3.0.0", - "property-information": "^6.0.0", - "space-separated-tokens": "^2.0.0" + "@types/hast": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/hastscript/node_modules/hast-util-parse-selector": { - "version": "3.1.1", + "node_modules/rehype-prism-plus/node_modules/hastscript": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz", + "integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==", "license": "MIT", "dependencies": { - "@types/hast": "^2.0.0" + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-parse-selector": "^3.0.0", + "property-information": "^6.0.0", + "space-separated-tokens": "^2.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/hastscript/node_modules/property-information": { + "node_modules/rehype-prism-plus/node_modules/property-information": { "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities": { - "version": "4.0.2", - "license": "MIT", - "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/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/@types/unist": { - "version": "2.0.11", - "license": "MIT" - }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/character-entities-legacy": { - "version": "3.0.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/character-reference-invalid": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-alphanumerical": { - "version": "2.0.1", + "node_modules/rehype-prism-plus/node_modules/refractor": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-4.9.0.tgz", + "integrity": "sha512-nEG1SPXFoGGx+dcjftjv8cAjEusIh6ED1xhf5DG3C0x/k+rmZ2duKnc3QLpt6qeHv5fPb8uwN3VWN2BT7fr3Og==", "license": "MIT", "dependencies": { - "is-alphabetical": "^2.0.0", - "is-decimal": "^2.0.0" + "@types/hast": "^2.0.0", + "@types/prismjs": "^1.0.0", + "hastscript": "^7.0.0", + "parse-entities": "^4.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-alphanumerical/node_modules/is-alphabetical": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-decimal": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, - "node_modules/rehype-prism-plus/node_modules/refractor/node_modules/parse-entities/node_modules/is-hexadecimal": { - "version": "2.0.1", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/rehype-raw": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz", + "integrity": "sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4872,6 +7096,8 @@ }, "node_modules/rehype-rewrite": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rehype-rewrite/-/rehype-rewrite-4.0.2.tgz", + "integrity": "sha512-rjLJ3z6fIV11phwCqHp/KRo8xuUCO8o9bFJCNw5o6O2wlLk6g8r323aRswdGBQwfXPFYeSuZdAjp4tzo6RGqEg==", "license": "MIT", "dependencies": { "hast-util-select": "^6.0.0", @@ -4887,6 +7113,8 @@ }, "node_modules/rehype-slug": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4902,6 +7130,8 @@ }, "node_modules/rehype-stringify": { "version": "10.0.1", + "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", + "integrity": "sha512-k9ecfXHmIPuFVI61B9DeLPN0qFHfawM6RsuX48hoqlaKSF61RskNjSm1lI8PhBEM0MRdLxVVm4WmTqJQccH9mA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4915,6 +7145,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4931,6 +7163,8 @@ }, "node_modules/remark-github-blockquote-alert": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/remark-github-blockquote-alert/-/remark-github-blockquote-alert-1.3.1.tgz", + "integrity": "sha512-OPNnimcKeozWN1w8KVQEuHOxgN3L4rah8geMOLhA5vN9wITqU4FWD+G26tkEsCGHiOVDbISx+Se5rGZ+D1p0Jg==", "license": "MIT", "dependencies": { "unist-util-visit": "^5.0.0" @@ -4944,6 +7178,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4958,6 +7194,8 @@ }, "node_modules/remark-rehype": { "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -4973,6 +7211,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/mdast": "^4.0.0", @@ -4985,10 +7225,12 @@ } }, "node_modules/rollup": { - "version": "4.43.0", + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", "license": "MIT", "dependencies": { - "@types/estree": "1.0.7" + "@types/estree": "1.0.8" }, "bin": { "rollup": "dist/bin/rollup" @@ -4998,49 +7240,52 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.43.0", - "@rollup/rollup-android-arm64": "4.43.0", - "@rollup/rollup-darwin-arm64": "4.43.0", - "@rollup/rollup-darwin-x64": "4.43.0", - "@rollup/rollup-freebsd-arm64": "4.43.0", - "@rollup/rollup-freebsd-x64": "4.43.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.43.0", - "@rollup/rollup-linux-arm-musleabihf": "4.43.0", - "@rollup/rollup-linux-arm64-gnu": "4.43.0", - "@rollup/rollup-linux-arm64-musl": "4.43.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.43.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-gnu": "4.43.0", - "@rollup/rollup-linux-riscv64-musl": "4.43.0", - "@rollup/rollup-linux-s390x-gnu": "4.43.0", - "@rollup/rollup-linux-x64-gnu": "4.43.0", - "@rollup/rollup-linux-x64-musl": "4.43.0", - "@rollup/rollup-win32-arm64-msvc": "4.43.0", - "@rollup/rollup-win32-ia32-msvc": "4.43.0", - "@rollup/rollup-win32-x64-msvc": "4.43.0", + "@rollup/rollup-android-arm-eabi": "4.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", "fsevents": "~2.3.2" } }, "node_modules/scheduler": { "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" } }, "node_modules/semver": { - "version": "7.7.2", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" } }, "node_modules/sharp": { - "version": "0.34.2", + "version": "0.34.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz", + "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -5056,52 +7301,57 @@ "url": "https://opencollective.com/libvips" }, "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.34.2", - "@img/sharp-darwin-x64": "0.34.2", - "@img/sharp-libvips-darwin-arm64": "1.1.0", - "@img/sharp-libvips-darwin-x64": "1.1.0", - "@img/sharp-libvips-linux-arm": "1.1.0", - "@img/sharp-libvips-linux-arm64": "1.1.0", - "@img/sharp-libvips-linux-ppc64": "1.1.0", - "@img/sharp-libvips-linux-s390x": "1.1.0", - "@img/sharp-libvips-linux-x64": "1.1.0", - "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", - "@img/sharp-libvips-linuxmusl-x64": "1.1.0", - "@img/sharp-linux-arm": "0.34.2", - "@img/sharp-linux-arm64": "0.34.2", - "@img/sharp-linux-s390x": "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-wasm32": "0.34.2", - "@img/sharp-win32-arm64": "0.34.2", - "@img/sharp-win32-ia32": "0.34.2", - "@img/sharp-win32-x64": "0.34.2" - } - }, - "node_modules/sharp/node_modules/@img/sharp-darwin-arm64": { - "version": "0.34.2", - "cpu": [ - "arm64" - ], + "@img/sharp-darwin-arm64": "0.34.3", + "@img/sharp-darwin-x64": "0.34.3", + "@img/sharp-libvips-darwin-arm64": "1.2.0", + "@img/sharp-libvips-darwin-x64": "1.2.0", + "@img/sharp-libvips-linux-arm": "1.2.0", + "@img/sharp-libvips-linux-arm64": "1.2.0", + "@img/sharp-libvips-linux-ppc64": "1.2.0", + "@img/sharp-libvips-linux-s390x": "1.2.0", + "@img/sharp-libvips-linux-x64": "1.2.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.0", + "@img/sharp-libvips-linuxmusl-x64": "1.2.0", + "@img/sharp-linux-arm": "0.34.3", + "@img/sharp-linux-arm64": "0.34.3", + "@img/sharp-linux-ppc64": "0.34.3", + "@img/sharp-linux-s390x": "0.34.3", + "@img/sharp-linux-x64": "0.34.3", + "@img/sharp-linuxmusl-arm64": "0.34.3", + "@img/sharp-linuxmusl-x64": "0.34.3", + "@img/sharp-wasm32": "0.34.3", + "@img/sharp-win32-arm64": "0.34.3", + "@img/sharp-win32-ia32": "0.34.3", + "@img/sharp-win32-x64": "0.34.3" + } + }, + "node_modules/sharp/node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=8" + } + }, + "node_modules/sharp/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.1.0" + "engines": { + "node": ">=10" } }, "node_modules/simple-swizzle": { "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", "dev": true, "license": "MIT", "dependencies": { @@ -5110,6 +7360,8 @@ }, "node_modules/source-map-js": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -5117,6 +7369,8 @@ }, "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==", "license": "MIT", "funding": { "type": "github", @@ -5125,6 +7379,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==", "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", @@ -5135,16 +7391,10 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/stringify-entities/node_modules/character-entities-legacy": { - "version": "3.0.0", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/style-to-js": { "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", "license": "MIT", "dependencies": { "style-to-object": "1.0.9" @@ -5152,6 +7402,8 @@ }, "node_modules/style-to-object": { "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", "license": "MIT", "dependencies": { "inline-style-parser": "0.2.4" @@ -5159,6 +7411,8 @@ }, "node_modules/tailwind-merge": { "version": "2.6.0", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.0.tgz", + "integrity": "sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==", "license": "MIT", "funding": { "type": "github", @@ -5166,11 +7420,15 @@ } }, "node_modules/tailwindcss": { - "version": "4.1.10", + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", + "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==", "license": "MIT" }, "node_modules/tapable": { "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "license": "MIT", "engines": { "node": ">=6" @@ -5178,6 +7436,8 @@ }, "node_modules/tar": { "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "license": "ISC", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", @@ -5191,8 +7451,19 @@ "node": ">=18" } }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/text-segmentation": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", "license": "MIT", "dependencies": { "utrie": "^1.0.2" @@ -5200,10 +7471,14 @@ }, "node_modules/tiny-invariant": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, "node_modules/tinyglobby": { "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "license": "MIT", "dependencies": { "fdir": "^6.4.4", @@ -5216,8 +7491,36 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -5228,6 +7531,8 @@ }, "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==", "license": "MIT", "funding": { "type": "github", @@ -5236,6 +7541,8 @@ }, "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==", "license": "MIT", "funding": { "type": "github", @@ -5244,10 +7551,14 @@ }, "node_modules/tslib": { "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/typescript": { "version": "5.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", + "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5260,11 +7571,15 @@ }, "node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "devOptional": 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==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -5282,6 +7597,8 @@ }, "node_modules/unist-util-filter": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-5.0.1.tgz", + "integrity": "sha512-pHx7D4Zt6+TsfwylH9+lYhBhzyhEnCXs/lbq/Hstxno5z4gVdyc2WEW0asfjGKPyG4pEKrnBv5hdkO6+aRnQJw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -5291,6 +7608,8 @@ }, "node_modules/unist-util-is": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -5302,6 +7621,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -5313,6 +7634,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" @@ -5324,6 +7647,8 @@ }, "node_modules/unist-util-visit": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -5337,6 +7662,8 @@ }, "node_modules/unist-util-visit-parents": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -5349,6 +7676,8 @@ }, "node_modules/update-browserslist-db": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -5378,6 +7707,8 @@ }, "node_modules/use-callback-ref": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", "dependencies": { "tslib": "^2.0.0" @@ -5397,6 +7728,8 @@ }, "node_modules/use-sidecar": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", "license": "MIT", "dependencies": { "detect-node-es": "^1.1.0", @@ -5417,6 +7750,8 @@ }, "node_modules/utrie": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", "license": "MIT", "dependencies": { "base64-arraybuffer": "^1.0.2" @@ -5424,6 +7759,8 @@ }, "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==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -5436,6 +7773,8 @@ }, "node_modules/vfile-location": { "version": "5.0.3", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.3.tgz", + "integrity": "sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -5447,7 +7786,9 @@ } }, "node_modules/vfile-message": { - "version": "4.0.2", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", @@ -5460,6 +7801,8 @@ }, "node_modules/victory-vendor": { "version": "36.9.2", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.9.2.tgz", + "integrity": "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==", "license": "MIT AND ISC", "dependencies": { "@types/d3-array": "^3.0.3", @@ -5480,6 +7823,8 @@ }, "node_modules/vite": { "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "license": "MIT", "dependencies": { "esbuild": "^0.25.0", @@ -5550,8 +7895,36 @@ } } }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/web-namespaces": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", "license": "MIT", "funding": { "type": "github", @@ -5566,29 +7939,33 @@ }, "node_modules/xtend": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "license": "MIT", "engines": { "node": ">=0.4" } }, "node_modules/yallist": { - "version": "5.0.0", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, "node_modules/zod": { - "version": "3.25.67", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zustand": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.6.tgz", - "integrity": "sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.7.tgz", + "integrity": "sha512-Ot6uqHDW/O2VdYsKLLU8GQu8sCOM1LcoE8RwvLv9uuRT9s6SOHCKs0ZEOhxg+I1Ld+A1Q5lwx+UlKXXUoCZITg==", "license": "MIT", "engines": { "node": ">=12.20.0" @@ -5616,6 +7993,8 @@ }, "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==", "license": "MIT", "funding": { "type": "github", diff --git a/src/components/StreamMessage.tsx b/src/components/StreamMessage.tsx index ae43a5934..1e1bd5467 100644 --- a/src/components/StreamMessage.tsx +++ b/src/components/StreamMessage.tsx @@ -37,6 +37,7 @@ import { TaskWidget, LSResultWidget, ThinkingWidget, + SequentialThinkingWidget, WebSearchWidget, WebFetchWidget } from "./ToolWidgets"; @@ -202,6 +203,74 @@ const StreamMessageComponent: React.FC = ({ message, classNa // MCP tools (starting with mcp__) if (content.name?.startsWith("mcp__")) { renderedSomething = true; + + // Check if this is Sequential Thinking data + let sequentialThinkingData = null; + if (toolResult) { + try { + // Try to parse the tool result content as JSON + // toolResult comes from getToolResult and has the structure from tool_result content + let contentToParse = toolResult.content; + + // Handle different content structures similar to other tools + if (typeof contentToParse === 'string') { + // Try to parse as JSON first + try { + contentToParse = JSON.parse(contentToParse); + } catch (jsonError) { + // If not JSON, skip Sequential Thinking detection + contentToParse = null; + } + } else if (contentToParse && typeof contentToParse === 'object') { + // Handle object with text property similar to line 439 + if (contentToParse.text) { + try { + contentToParse = JSON.parse(contentToParse.text); + } catch (jsonError) { + contentToParse = null; + } + } else if (Array.isArray(contentToParse)) { + // Handle array of content blocks - try first text item + const firstText = contentToParse.find((c: any) => c.text); + if (firstText?.text) { + try { + contentToParse = JSON.parse(firstText.text); + } catch (jsonError) { + contentToParse = null; + } + } else { + contentToParse = null; + } + } + // If it's already an object, check if it's Sequential Thinking data directly + } + + // Check if it has Sequential Thinking properties + if (contentToParse && + typeof contentToParse.thought === 'string' && + (contentToParse.thoughtNumber !== undefined || + contentToParse.nextThoughtNeeded !== undefined || + contentToParse.totalThoughts !== undefined)) { + sequentialThinkingData = contentToParse; + } + } catch (e) { + // Not Sequential Thinking data, fall back to regular MCP widget + } + } + + // Use SequentialThinkingWidget if we detected the right data format + if (sequentialThinkingData) { + return ( + + ); + } + + // Fall back to regular MCP widget return ; } diff --git a/src/components/ToolWidgets.tsx b/src/components/ToolWidgets.tsx index fdb00e814..741c75ca6 100644 --- a/src/components/ToolWidgets.tsx +++ b/src/components/ToolWidgets.tsx @@ -2312,6 +2312,144 @@ export const ThinkingWidget: React.FC<{ ); }; +/** + * Widget for Sequential Thinking MCP server - displays thoughts in a thought bubble design + */ +export const SequentialThinkingWidget: React.FC<{ + thought: string; + thoughtNumber?: number; + totalThoughts?: number; + nextThoughtNeeded?: boolean; +}> = ({ thought, thoughtNumber, totalThoughts, nextThoughtNeeded }) => { + const [isExpanded, setIsExpanded] = useState(false); + + // Convert \n to actual line breaks and clean up the text + const formattedThought = (thought || '') + .replace(/\\n/g, '\n') + .trim(); + + // Determine emoji based on progress and state + const getThinkingEmoji = () => { + if (!thoughtNumber || !totalThoughts || totalThoughts <= 0) return 'šŸ¤”'; + + const progress = thoughtNumber / totalThoughts; + + if (progress <= 0.2) return 'šŸ¤”'; // Just starting to think + if (progress <= 0.4) return 'šŸ’­'; // Developing thoughts + if (progress <= 0.6) return '🤨'; // Analyzing/questioning + if (progress <= 0.8) return '🧐'; // Deep analysis + if (progress < 1.0) return 'šŸ’”'; // Getting close to solution + return nextThoughtNeeded ? '😣' : 'šŸ’”'; // Struggling or eureka moment + }; + + const emoji = getThinkingEmoji(); + const progressText = thoughtNumber && totalThoughts + ? `${thoughtNumber}/${totalThoughts}` + : ''; + + // Determine if content is long and should be collapsible + const isLongThought = formattedThought.length > 300 || formattedThought.split('\n').length > 5; + + return ( +
+ {/* Header */} +
setIsExpanded(!isExpanded) : undefined} + > +
+
+
+ {emoji} + + Sequential Thinking + +
+ {progressText && ( +
+ + Step {progressText} + + {nextThoughtNeeded && ( + + Continuing... + + )} +
+ )} +
+ {isLongThought && ( + + )} +
+
+ + {/* Thought Content */} +
+
+
+
+ {formattedThought || ( + + Thinking... + + )} +
+
+ + {/* Gradient fade for collapsed long thoughts */} + {!isExpanded && isLongThought && ( +
+ )} +
+ + {/* Expand/collapse button for long thoughts */} + {!isExpanded && isLongThought && ( +
+ +
+ )} + + {isExpanded && isLongThought && ( +
+ +
+ )} +
+
+ ); +}; + /** * Widget for WebFetch tool - displays URL fetching with optional prompts */ From e387077c5a06f255e3060655853682b47e1acad7 Mon Sep 17 00:00:00 2001 From: Alex Newman Date: Tue, 12 Aug 2025 21:55:38 -0400 Subject: [PATCH 04/19] Refactor session store and improve error handling - Updated sessionStore.ts to enhance code readability and maintainability by standardizing quotes and formatting. - Improved error handling in fetch functions to provide clearer messages. - Added logic to handle session updates and outputs more efficiently. - Adjusted CSS styles for better consistency and readability. - Standardized quotes in hooks and configuration files for consistency. - Improved Vite configuration for better code splitting and chunk management. --- .github/workflows/build-linux.yml | 20 +- .github/workflows/build-macos.yml | 96 +- .github/workflows/build-test.yml | 30 +- .github/workflows/claude-code-review.yml | 21 +- .github/workflows/claude.yml | 13 +- .github/workflows/release.yml | 28 +- CONTRIBUTING.md | 8 +- README.md | 45 +- cc_agents/README.md | 20 +- src-tauri/capabilities/default.json | 2 +- src-tauri/tauri.conf.json | 16 +- src-tauri/tests/TESTS_COMPLETE.md | 9 + src/App.tsx | 167 +- src/assets/shimmer.css | 19 +- src/components/AgentExecution.tsx | 694 ++++--- src/components/AgentExecutionDemo.tsx | 115 +- src/components/AgentRunOutputViewer.tsx | 569 ++++-- src/components/AgentRunView.tsx | 118 +- src/components/AgentRunsList.tsx | 67 +- src/components/Agents.tsx | 325 +-- src/components/AgentsModal.tsx | 623 +++--- src/components/AnalyticsConsent.tsx | 98 +- src/components/AnalyticsErrorBoundary.tsx | 20 +- src/components/App.cleaned.tsx | 73 +- src/components/CCAgents.tsx | 102 +- src/components/CheckpointSettings.tsx | 92 +- src/components/ClaudeBinaryDialog.tsx | 78 +- .../ClaudeCodeSession.refactored.tsx | 170 +- src/components/ClaudeCodeSession.tsx | 1654 ++++++++------- src/components/ClaudeFileEditor.tsx | 46 +- src/components/ClaudeMemoriesDropdown.tsx | 22 +- src/components/ClaudeVersionSelector.tsx | 166 +- src/components/CreateAgent.tsx | 175 +- src/components/CustomTitlebar.tsx | 371 ++-- src/components/ErrorBoundary.tsx | 17 +- src/components/ExecutionControlBar.tsx | 12 +- src/components/FilePicker.optimized.tsx | 751 +++---- src/components/FilePicker.tsx | 228 ++- src/components/FloatingPromptInput.tsx | 1206 ++++++----- src/components/GitHubAgentBrowser.tsx | 97 +- src/components/HooksEditor.tsx | 736 ++++--- src/components/IconPicker.tsx | 23 +- src/components/ImagePreview.tsx | 47 +- src/components/MCPAddServer.tsx | 136 +- src/components/MCPImportExport.tsx | 78 +- src/components/MCPManager.tsx | 45 +- src/components/MCPServerList.tsx | 136 +- src/components/MarkdownEditor.tsx | 31 +- src/components/NFOCredits.tsx | 113 +- src/components/PreviewPromptDialog.tsx | 25 +- src/components/ProjectList.tsx | 225 +- src/components/ProjectSettings.tsx | 110 +- src/components/ProxySettings.tsx | 77 +- src/components/RunningClaudeSessions.tsx | 57 +- src/components/SessionList.optimized.tsx | 209 +- src/components/SessionList.tsx | 199 +- src/components/SessionOutputViewer.tsx | 437 ++-- src/components/Settings.tsx | 1572 ++++++++------ src/components/SlashCommandPicker.tsx | 368 ++-- src/components/SlashCommandsManager.tsx | 287 ++- src/components/StorageTab.tsx | 130 +- src/components/StreamMessage.tsx | 1275 +++++++----- src/components/TabContent.tsx | 535 +++-- src/components/TabManager.tsx | 226 ++- src/components/TimelineNavigator.tsx | 285 ++- src/components/TokenCounter.tsx | 6 +- src/components/ToolWidgets.new.tsx | 2 +- src/components/ToolWidgets.tsx | 1806 ++++++++++------- src/components/Topbar.tsx | 42 +- src/components/UsageDashboard.original.tsx | 761 ++++--- src/components/UsageDashboard.tsx | 840 +++++--- src/components/WebviewPreview.tsx | 75 +- .../claude-code-session/MessageList.tsx | 274 +-- .../claude-code-session/PromptQueue.tsx | 134 +- .../claude-code-session/SessionHeader.tsx | 288 +-- .../claude-code-session/useCheckpoints.ts | 184 +- .../claude-code-session/useClaudeMessages.ts | 134 +- src/components/index.ts | 8 +- src/components/ui/badge.tsx | 14 +- src/components/ui/button.tsx | 8 +- src/components/ui/card.tsx | 18 +- src/components/ui/dialog.tsx | 52 +- src/components/ui/dropdown-menu.tsx | 80 +- src/components/ui/input.tsx | 10 +- src/components/ui/label.tsx | 8 +- src/components/ui/pagination.tsx | 12 +- src/components/ui/popover.tsx | 36 +- src/components/ui/radio-group.tsx | 4 +- src/components/ui/scroll-area.tsx | 6 +- src/components/ui/select.tsx | 19 +- src/components/ui/split-pane.tsx | 99 +- src/components/ui/switch.tsx | 16 +- src/components/ui/tabs.tsx | 108 +- src/components/ui/textarea.tsx | 16 +- src/components/ui/toast.tsx | 18 +- src/components/ui/tooltip-modern.tsx | 38 +- src/components/ui/tooltip.tsx | 22 +- src/components/widgets/BashWidget.tsx | 47 +- src/components/widgets/LSWidget.tsx | 179 +- src/components/widgets/TodoWidget.tsx | 37 +- src/components/widgets/index.ts | 8 +- src/contexts/TabContext.tsx | 289 +-- src/contexts/ThemeContext.tsx | 217 +- src/hooks/index.ts | 32 +- src/hooks/useAnalytics.ts | 648 +++--- src/hooks/useApiCall.ts | 31 +- src/hooks/useDebounce.ts | 26 +- src/hooks/useLoadingState.ts | 11 +- src/hooks/usePagination.ts | 33 +- src/hooks/usePerformanceMonitor.ts | 47 +- src/hooks/useTabState.ts | 369 ++-- src/hooks/useTheme.ts | 12 +- src/lib/analytics/consent.ts | 77 +- src/lib/analytics/events.ts | 411 ++-- src/lib/analytics/index.ts | 215 +- src/lib/analytics/resourceMonitor.ts | 93 +- src/lib/analytics/types.ts | 171 +- src/lib/api-tracker.ts | 53 +- src/lib/api.ts | 402 ++-- src/lib/claudeSyntaxTheme.ts | 297 +-- src/lib/date-utils.ts | 70 +- src/lib/hooksManager.ts | 153 +- src/lib/linkDetector.tsx | 46 +- src/lib/outputCache.tsx | 159 +- src/lib/utils.ts | 6 +- src/main.tsx | 5 +- src/services/sessionPersistence.ts | 62 +- src/services/tabPersistence.ts | 96 +- src/stores/README.md | 10 +- src/stores/agentStore.ts | 428 ++-- src/stores/sessionStore.ts | 320 +-- src/styles.css | 155 +- src/types/hooks.ts | 106 +- vite.config.ts | 26 +- 134 files changed, 15241 insertions(+), 10989 deletions(-) diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index f94d980eb..3cd29c149 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -10,10 +10,10 @@ jobs: build: name: Build Linux x86_64 runs-on: ubuntu-latest - + steps: - uses: actions/checkout@v4 - + - name: Install system dependencies run: | sudo apt-get update @@ -24,36 +24,36 @@ jobs: libssl-dev \ libayatana-appindicator3-dev \ librsvg2-dev - + - name: Setup Rust uses: dtolnay/rust-toolchain@stable with: targets: x86_64-unknown-linux-gnu - + - name: Setup Rust cache uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri - + - name: Setup Bun uses: oven-sh/setup-bun@v2 - + - name: Install dependencies run: bun install - + - name: Build Tauri app run: bun run tauri build --target x86_64-unknown-linux-gnu - + - name: Create artifacts directory run: | mkdir -p dist/linux-x86_64 cp src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/deb/*.deb dist/linux-x86_64/ || true cp src-tauri/target/x86_64-unknown-linux-gnu/release/bundle/appimage/*.AppImage dist/linux-x86_64/ || true - + # Generate checksums cd dist/linux-x86_64 sha256sum * > checksums.txt - + - name: Upload artifacts uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/build-macos.yml b/.github/workflows/build-macos.yml index f17380565..c378e271b 100644 --- a/.github/workflows/build-macos.yml +++ b/.github/workflows/build-macos.yml @@ -20,12 +20,12 @@ on: workflow_dispatch: inputs: skip_build: - description: 'Skip build and use artifacts from a previous run' + description: "Skip build and use artifacts from a previous run" required: false default: false type: boolean run_id: - description: 'Run ID to download artifacts from (leave empty for latest)' + description: "Run ID to download artifacts from (leave empty for latest)" required: false type: string push: @@ -39,30 +39,30 @@ jobs: strategy: matrix: include: - - os: macos-13 # Intel + - os: macos-13 # Intel target: x86_64-apple-darwin arch: x86_64 - - os: macos-14 # Apple Silicon + - os: macos-14 # Apple Silicon target: aarch64-apple-darwin arch: aarch64 - + steps: - uses: actions/checkout@v4 - + - name: Setup Rust uses: dtolnay/rust-toolchain@stable - + - name: Setup Rust cache uses: Swatinem/rust-cache@v2 with: workspaces: src-tauri - + - name: Setup Bun uses: oven-sh/setup-bun@v2 - + - name: Install dependencies run: bun install - + - name: Import Apple certificates env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} @@ -72,25 +72,25 @@ jobs: # Create variables CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - + # Import certificate from secrets echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH - + # Create temporary keychain security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - + # Import certificate to keychain security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH - + - name: Build native env: CI: true run: bun run tauri build - + - name: Upload architecture-specific artifacts uses: actions/upload-artifact@v4 with: @@ -99,7 +99,7 @@ jobs: src-tauri/target/release/bundle/macos/Claudia.app src-tauri/target/release/bundle/dmg/*.dmg retention-days: 1 - + universal: name: Create Universal Binary needs: [build] @@ -107,14 +107,14 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 - + - name: Download artifacts from current workflow if: ${{ !inputs.skip_build }} uses: actions/download-artifact@v4 with: pattern: macos-* path: artifacts - + - name: Download artifacts from specific run if: ${{ inputs.skip_build && inputs.run_id != '' }} uses: dawidd6/action-download-artifact@v3 @@ -123,7 +123,7 @@ jobs: run_id: ${{ inputs.run_id }} name: macos-* path: artifacts - + - name: Download artifacts from latest run if: ${{ inputs.skip_build && inputs.run_id == '' }} uses: dawidd6/action-download-artifact@v3 @@ -132,7 +132,7 @@ jobs: workflow_conclusion: success name: macos-* path: artifacts - + - name: List downloaded artifacts run: | echo "šŸ“ Artifact structure:" @@ -142,7 +142,7 @@ jobs: ls -la artifacts/ ls -la artifacts/macos-aarch64/ || echo "macos-aarch64 directory not found" ls -la artifacts/macos-x86_64/ || echo "macos-x86_64 directory not found" - + - name: Import Apple certificates env: APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} @@ -152,65 +152,65 @@ jobs: # Create variables CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - + # Import certificate from secrets echo -n "$APPLE_CERTIFICATE" | base64 --decode -o $CERTIFICATE_PATH - + # Create temporary keychain security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security set-keychain-settings -lut 21600 $KEYCHAIN_PATH security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH - + # Import certificate to keychain security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH security list-keychain -d user -s $KEYCHAIN_PATH - + - name: Create universal app run: | # Create temp directory mkdir -p dmg_temp - + # Extract zip files if they exist if [ -f "artifacts/macos-aarch64.zip" ]; then echo "šŸ“¦ Extracting macos-aarch64.zip..." unzip -q artifacts/macos-aarch64.zip -d artifacts/macos-aarch64/ fi - + if [ -f "artifacts/macos-x86_64.zip" ]; then echo "šŸ“¦ Extracting macos-x86_64.zip..." unzip -q artifacts/macos-x86_64.zip -d artifacts/macos-x86_64/ fi - + # Find the actual app paths AARCH64_APP=$(find artifacts/macos-aarch64 -name "Claudia.app" -type d | head -1) X86_64_APP=$(find artifacts/macos-x86_64 -name "Claudia.app" -type d | head -1) - + if [ -z "$AARCH64_APP" ] || [ -z "$X86_64_APP" ]; then echo "āŒ Could not find app bundles" echo "AARCH64_APP: $AARCH64_APP" echo "X86_64_APP: $X86_64_APP" exit 1 fi - + echo "āœ… Found app bundles:" echo " ARM64: $AARCH64_APP" echo " x86_64: $X86_64_APP" - + # Copy ARM64 app as base cp -R "$AARCH64_APP" dmg_temp/ - + # Create universal binary using lipo lipo -create -output dmg_temp/Claudia.app/Contents/MacOS/claudia \ "$AARCH64_APP/Contents/MacOS/claudia" \ "$X86_64_APP/Contents/MacOS/claudia" - + # Ensure executable permissions are set chmod +x dmg_temp/Claudia.app/Contents/MacOS/claudia - + echo "āœ… Universal binary created" lipo -info dmg_temp/Claudia.app/Contents/MacOS/claudia - + - name: Sign app bundle env: APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} @@ -222,13 +222,13 @@ jobs: --deep \ --entitlements src-tauri/entitlements.plist \ dmg_temp/Claudia.app - + - name: Create DMG run: | hdiutil create -volname "Claudia Installer" \ -srcfolder dmg_temp \ -ov -format UDZO Claudia.dmg - + - name: Sign DMG env: APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} @@ -236,7 +236,7 @@ jobs: codesign --sign "$APPLE_SIGNING_IDENTITY" \ --timestamp \ --force Claudia.dmg - + - name: Notarize DMG env: APPLE_ID: ${{ secrets.APPLE_ID }} @@ -248,47 +248,47 @@ jobs: --apple-id "$APPLE_ID" \ --team-id "$APPLE_TEAM_ID" \ --password "$APPLE_PASSWORD" - + # Submit for notarization xcrun notarytool submit Claudia.dmg \ --keychain-profile "notarytool-profile" \ --wait - + - name: Staple notarization run: xcrun stapler staple Claudia.dmg - + - name: Verify DMG run: | spctl -a -t open -vvv --context context:primary-signature Claudia.dmg echo "āœ… DMG verification complete" - + - name: Create artifacts directory run: | mkdir -p dist/macos-universal cp Claudia.dmg dist/macos-universal/ - + # Also save the app bundle using ditto to preserve permissions and signatures ditto -c -k --sequesterRsrc --keepParent \ dmg_temp/Claudia.app dist/macos-universal/Claudia.app.zip - + # Generate checksum shasum -a 256 dist/macos-universal/* > dist/macos-universal/checksums.txt - + - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: macos-universal path: dist/macos-universal/* - + - name: Cleanup if: always() run: | echo "🧹 Cleaning up temporary directories..." rm -rf dmg_temp temp_x86 artifacts - + # Clean up keychain if [ -n "$RUNNER_TEMP" ] && [ -f "$RUNNER_TEMP/app-signing.keychain-db" ]; then security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" || true fi - + echo "āœ… Cleanup complete" diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 9a65d94e1..f8f7a5316 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -3,9 +3,9 @@ name: Build Test # Trigger on every push and pull request on: push: - branches: [ main, develop, 'release/**', 'feature/**' ] + branches: [main, develop, "release/**", "feature/**"] pull_request: - branches: [ main, develop ] + branches: [main, develop] types: [opened, synchronize, reopened] # Cancel in-progress workflows when a new commit is pushed @@ -20,7 +20,7 @@ env: jobs: build-test: name: Build Test (${{ matrix.platform.name }}) - + strategy: fail-fast: false matrix: @@ -37,9 +37,9 @@ jobs: - name: macOS os: macos-latest rust-target: x86_64-apple-darwin - + runs-on: ${{ matrix.platform.os }} - + steps: # Checkout the repository - name: Checkout repository @@ -75,9 +75,9 @@ jobs: - name: Cache Rust dependencies uses: Swatinem/rust-cache@v2 with: - workspaces: './src-tauri -> target' + workspaces: "./src-tauri -> target" key: ${{ matrix.platform.os }}-rust-${{ hashFiles('**/Cargo.lock') }} - + # Setup Bun - name: Setup Bun uses: oven-sh/setup-bun@v2 @@ -94,7 +94,7 @@ jobs: key: ${{ matrix.platform.os }}-bun-${{ hashFiles('bun.lockb', 'package.json') }} restore-keys: | ${{ matrix.platform.os }}-bun- - + # Install frontend dependencies - name: Install frontend dependencies run: bun install --frozen-lockfile @@ -127,7 +127,7 @@ jobs: runs-on: ubuntu-latest needs: [build-test] if: always() - + steps: - name: Check build results run: | @@ -149,21 +149,21 @@ jobs: const result = '${{ needs.build-test.result }}'; const emoji = result === 'success' ? 'āœ…' : 'āŒ'; const status = result === 'success' ? 'All build tests passed!' : 'Build tests failed'; - + // Create a comment summarizing the build status const comment = `## ${emoji} Build Test Results - + **Status**: ${status} **Commit**: ${{ github.event.pull_request.head.sha || github.sha }} - + | Platform | Status | |----------|--------| | Linux | ${{ contains(needs.build-test.result, 'success') && 'āœ…' || 'āŒ' }} | | Windows | ${{ contains(needs.build-test.result, 'success') && 'āœ…' || 'āŒ' }} | | macOS | ${{ contains(needs.build-test.result, 'success') && 'āœ…' || 'āŒ' }} | - + [View full workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`; - + // Only post comment if it's a PR if (context.eventName === 'pull_request') { await github.rest.issues.createComment({ @@ -172,4 +172,4 @@ jobs: issue_number: context.issue.number, body: comment }); - } + } diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index ecd27d0a5..e9ebc818a 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -17,14 +17,14 @@ jobs: # github.event.pull_request.user.login == 'external-contributor' || # github.event.pull_request.user.login == 'new-developer' || # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' - + runs-on: ubuntu-latest permissions: contents: read pull-requests: read issues: read id-token: write - + steps: - name: Checkout repository uses: actions/checkout@v4 @@ -36,10 +36,10 @@ jobs: uses: anthropics/claude-code-action@beta with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - + # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4) # model: "claude-opus-4-20250514" - + # Direct prompt for automated review (no @claude mention needed) direct_prompt: | Please review this pull request and provide feedback on: @@ -48,9 +48,9 @@ jobs: - Performance considerations - Security concerns - Test coverage - + Be constructive and helpful in your feedback. - + # Optional: Customize review based on file types # direct_prompt: | # Review this PR focusing on: @@ -58,18 +58,17 @@ jobs: # - For API endpoints: Security, input validation, and error handling # - For React components: Performance, accessibility, and best practices # - For tests: Coverage, edge cases, and test quality - + # Optional: Different prompts for different authors # direct_prompt: | - # ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' && + # ${{ github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' && # 'Welcome! Please review this PR from a first-time contributor. Be encouraging and provide detailed explanations for any suggestions.' || # 'Please provide a thorough code review focusing on our coding standards and best practices.' }} - + # Optional: Add specific tools for running tests or linting # allowed_tools: "Bash(npm run test),Bash(npm run lint),Bash(npm run typecheck)" - + # Optional: Skip review for certain conditions # if: | # !contains(github.event.pull_request.title, '[skip-review]') && # !contains(github.event.pull_request.title, '[WIP]') - diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 40088f80f..692b45a45 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -34,26 +34,25 @@ jobs: uses: anthropics/claude-code-action@beta with: anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }} - + # Optional: Specify model (defaults to Claude Sonnet 4, uncomment for Claude Opus 4) model: "claude-opus-4-20250514" - + # Optional: Customize the trigger phrase (default: @claude) # trigger_phrase: "/claude" - + # Optional: Trigger when specific user is assigned to an issue # assignee_trigger: "claude-bot" - + # Optional: Allow Claude to run specific commands # allowed_tools: "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)" - + # Optional: Add custom instructions for Claude to customize its behavior for your project # custom_instructions: | # Follow our coding standards # Ensure all new code has tests # Use TypeScript for new files - + # Optional: Custom environment variables for Claude # claude_env: | # NODE_ENV: test - diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f991092c1..ee2f88db1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,11 +3,11 @@ name: Release on: push: tags: - - 'v*' + - "v*" workflow_dispatch: inputs: version: - description: 'Version to release (e.g., v1.0.0)' + description: "Version to release (e.g., v1.0.0)" required: true type: string @@ -19,21 +19,20 @@ jobs: build-linux: uses: ./.github/workflows/build-linux.yml secrets: inherit - + build-macos: uses: ./.github/workflows/build-macos.yml secrets: inherit - # Create release after all builds complete create-release: name: Create Release needs: [build-linux, build-macos] runs-on: ubuntu-latest - + steps: - uses: actions/checkout@v4 - + - name: Determine version id: version run: | @@ -44,36 +43,36 @@ jobs: fi echo "version=$VERSION" >> $GITHUB_OUTPUT echo "Version: $VERSION" - + - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - + - name: Prepare release assets run: | mkdir -p release-assets - + # Linux artifacts if [ -d "artifacts/linux-x86_64" ]; then cp artifacts/linux-x86_64/*.deb release-assets/Claudia_${{ steps.version.outputs.version }}_linux_x86_64.deb || true cp artifacts/linux-x86_64/*.AppImage release-assets/Claudia_${{ steps.version.outputs.version }}_linux_x86_64.AppImage || true fi - + # macOS artifacts if [ -d "artifacts/macos-universal" ]; then cp artifacts/macos-universal/Claudia.dmg release-assets/Claudia_${{ steps.version.outputs.version }}_macos_universal.dmg || true cp artifacts/macos-universal/Claudia.app.zip release-assets/Claudia_${{ steps.version.outputs.version }}_macos_universal.app.tar.gz || true fi - + # Create source code archives # Clean version without 'v' prefix for archive names CLEAN_VERSION="${{ steps.version.outputs.version }}" CLEAN_VERSION="${CLEAN_VERSION#v}" - + # Create source code archives (excluding .git and other unnecessary files) echo "Creating source code archives..." - + # Create a clean export of the repository git archive --format=tar.gz --prefix=claudia-${CLEAN_VERSION}/ -o release-assets/claudia-${CLEAN_VERSION}.tar.gz HEAD git archive --format=zip --prefix=claudia-${CLEAN_VERSION}/ -o release-assets/claudia-${CLEAN_VERSION}.zip HEAD @@ -86,7 +85,7 @@ jobs: fi done cd .. - + - name: Create Release uses: softprops/action-gh-release@v1 with: @@ -117,4 +116,3 @@ jobs: - macOS: Open the `.dmg` and drag Claudia to Applications. - Linux: `chmod +x` the `.AppImage` and run it, or install the `.deb` on Debian/Ubuntu. - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 570d4b4d2..27711d6f6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,7 @@ To contribute, please follow these steps: When submitting a pull request, please follow these guidelines: 1. **Title**: Please include following prefixes: + - `Feature:` for new features - `Fix:` for bug fixes - `Docs:` for documentation changes @@ -24,6 +25,7 @@ When submitting a pull request, please follow these guidelines: - `Other:` for other changes For example: + - `Feature: added custom agent timeout configuration` - `Fix: resolved session list scrolling issue` @@ -40,12 +42,14 @@ When submitting a pull request, please follow these guidelines: ## Coding Standards ### Frontend (React/TypeScript) + - Use TypeScript for all new code - Follow functional components with hooks - Use Tailwind CSS for styling - Add JSDoc comments for exported functions and components ### Backend (Rust) + - Follow Rust standard conventions - Use `cargo fmt` for formatting - Use `cargo clippy` for linting @@ -53,15 +57,17 @@ When submitting a pull request, please follow these guidelines: - Add comprehensive documentation with `///` comments ### Security Requirements + - Validate all inputs from the frontend - Use prepared statements for database operations - Never log sensitive data (tokens, passwords, etc.) - Use secure defaults for all configurations ## Testing + - Add tests for new functionality - Ensure all existing tests pass - Run `cargo test` for Rust code - Test the application manually before submitting -Please adhere to the coding conventions, maintain clear documentation, and provide thorough testing for your contributions. +Please adhere to the coding conventions, maintain clear documentation, and provide thorough testing for your contributions. diff --git a/README.md b/README.md index a7f4d669f..a78d8d669 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@
Claudia Logo -

Claudia

- +

Claudia

+

A powerful GUI app and Toolkit for Claude Code

@@ -22,8 +22,7 @@ https://github.com/user-attachments/assets/bf0bdf9d-ba91-45af-9ac4-7274f57075cf -> [!TIP] -> **⭐ Star the repo and follow [@getAsterisk](https://x.com/getAsterisk) on X for early access to `asteria-swe-v0`**. +> [!TIP] > **⭐ Star the repo and follow [@getAsterisk](https://x.com/getAsterisk) on X for early access to `asteria-swe-v0`**. ## 🌟 Overview @@ -35,13 +34,14 @@ Think of Claudia as your command center for Claude Code - bridging the gap betwe - [🌟 Overview](#-overview) - [✨ Features](#-features) + - [šŸ—‚ļø Project & Session Management](#ļø-project--session-management) - [šŸ¤– CC Agents](#-cc-agents) - - [šŸ“Š Usage Analytics Dashboard](#-usage-analytics-dashboard) - [šŸ”Œ MCP Server Management](#-mcp-server-management) - [ā° Timeline & Checkpoints](#-timeline--checkpoints) - [šŸ“ CLAUDE.md Management](#-claudemd-management) + - [šŸ“– Usage](#-usage) - [Getting Started](#getting-started) - [Managing Projects](#managing-projects) @@ -59,32 +59,35 @@ Think of Claudia as your command center for Claude Code - bridging the gap betwe ## ✨ Features ### šŸ—‚ļø **Project & Session Management** + - **Visual Project Browser**: Navigate through all your Claude Code projects in `~/.claude/projects/` - **Session History**: View and resume past coding sessions with full context - **Smart Search**: Find projects and sessions quickly with built-in search - **Session Insights**: See first messages, timestamps, and session metadata at a glance ### šŸ¤– **CC Agents** + - **Custom AI Agents**: Create specialized agents with custom system prompts and behaviors - **Agent Library**: Build a collection of purpose-built agents for different tasks - **Background Execution**: Run agents in separate processes for non-blocking operations - **Execution History**: Track all agent runs with detailed logs and performance metrics - - ### šŸ“Š **Usage Analytics Dashboard** + - **Cost Tracking**: Monitor your Claude API usage and costs in real-time - **Token Analytics**: Detailed breakdown by model, project, and time period - **Visual Charts**: Beautiful charts showing usage trends and patterns - **Export Data**: Export usage data for accounting and analysis ### šŸ”Œ **MCP Server Management** + - **Server Registry**: Manage Model Context Protocol servers from a central UI - **Easy Configuration**: Add servers via UI or import from existing configs - **Connection Testing**: Verify server connectivity before use - **Claude Desktop Import**: Import server configurations from Claude Desktop ### ā° **Timeline & Checkpoints** + - **Session Versioning**: Create checkpoints at any point in your coding session - **Visual Timeline**: Navigate through your session history with a branching timeline - **Instant Restore**: Jump back to any checkpoint with one click @@ -92,6 +95,7 @@ Think of Claudia as your command center for Claude Code - bridging the gap betwe - **Diff Viewer**: See exactly what changed between checkpoints ### šŸ“ **CLAUDE.md Management** + - **Built-in Editor**: Edit CLAUDE.md files directly within the app - **Live Preview**: See your markdown rendered in real-time - **Project Scanner**: Find all CLAUDE.md files in your projects @@ -169,18 +173,21 @@ Before building Claudia from source, ensure you have the following installed: #### Required Tools 1. **Rust** (1.70.0 or later) + ```bash # Install via rustup curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` 2. **Bun** (latest version) + ```bash # Install bun curl -fsSL https://bun.sh/install | bash ``` 3. **Git** + ```bash # Usually pre-installed, but if not: # Ubuntu/Debian: sudo apt install git @@ -195,6 +202,7 @@ Before building Claudia from source, ensure you have the following installed: #### Platform-Specific Dependencies **Linux (Ubuntu/Debian)** + ```bash # Install system dependencies sudo apt update @@ -215,6 +223,7 @@ sudo apt install -y \ ``` **macOS** + ```bash # Install Xcode Command Line Tools xcode-select --install @@ -224,34 +233,39 @@ brew install pkg-config ``` **Windows** + - Install [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) - Install [WebView2](https://developer.microsoft.com/microsoft-edge/webview2/) (usually pre-installed on Windows 11) ### Build Steps 1. **Clone the Repository** + ```bash git clone https://github.com/getAsterisk/claudia.git cd claudia ``` 2. **Install Frontend Dependencies** + ```bash bun install ``` 3. **Build the Application** - + **For Development (with hot reload)** + ```bash bun run tauri dev ``` - + **For Production Build** + ```bash # Build the application bun run tauri build - + # The built executable will be in: # - Linux: src-tauri/target/release/ # - macOS: src-tauri/target/release/ @@ -259,13 +273,15 @@ brew install pkg-config ``` 4. **Platform-Specific Build Options** - + **Debug Build (faster compilation, larger binary)** + ```bash bun run tauri build --debug ``` - + **Universal Binary for macOS (Intel + Apple Silicon)** + ```bash bun run tauri build --target universal-apple-darwin ``` @@ -275,18 +291,22 @@ brew install pkg-config #### Common Issues 1. **"cargo not found" error** + - Ensure Rust is installed and `~/.cargo/bin` is in your PATH - Run `source ~/.cargo/env` or restart your terminal 2. **Linux: "webkit2gtk not found" error** + - Install the webkit2gtk development packages listed above - On newer Ubuntu versions, you might need `libwebkit2gtk-4.0-dev` 3. **Windows: "MSVC not found" error** + - Install Visual Studio Build Tools with C++ support - Restart your terminal after installation 4. **"claude command not found" error** + - Ensure Claude Code CLI is installed and in your PATH - Test with `claude --version` @@ -412,7 +432,6 @@ This project is licensed under the AGPL License - see the [LICENSE](LICENSE) fil

- ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=getAsterisk/claudia&type=Date)](https://www.star-history.com/#getAsterisk/claudia&Date) diff --git a/cc_agents/README.md b/cc_agents/README.md index f380e9636..9a0a66ccd 100644 --- a/cc_agents/README.md +++ b/cc_agents/README.md @@ -16,15 +16,16 @@ ## šŸ“¦ Available Agents -| Agent | Model | Description | Default Task | -|-------|-------|-------------|--------------| -| **šŸŽÆ Git Commit Bot**
šŸ¤– `bot` | Sonnet | **Automate your Git workflow with intelligent commit messages**

Analyzes Git repository changes, generates detailed commit messages following Conventional Commits specification, and pushes changes to remote repository. | "Push all changes." | -| **šŸ›”ļø Security Scanner**
šŸ›”ļø `shield` | Opus | **Advanced AI-powered Static Application Security Testing (SAST)**

Performs comprehensive security audits by spawning specialized sub-agents for: codebase intelligence gathering, threat modeling (STRIDE), vulnerability scanning (OWASP Top 10, CWE), exploit validation, remediation design, and professional report generation. | "Review the codebase for security issues." | -| **🧪 Unit Tests Bot**
šŸ’» `code` | Opus | **Automated comprehensive unit test generation for any codebase**

Analyzes codebase and generates comprehensive unit tests by: analyzing code structure, creating test plans, writing tests matching your style, verifying execution, optimizing coverage (>80% overall, 100% critical paths), and generating documentation. | "Generate unit tests for this codebase." | +| Agent | Model | Description | Default Task | +| --------------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | +| **šŸŽÆ Git Commit Bot**
šŸ¤– `bot` | Sonnet | **Automate your Git workflow with intelligent commit messages**

Analyzes Git repository changes, generates detailed commit messages following Conventional Commits specification, and pushes changes to remote repository. | "Push all changes." | +| **šŸ›”ļø Security Scanner**
šŸ›”ļø `shield` | Opus | **Advanced AI-powered Static Application Security Testing (SAST)**

Performs comprehensive security audits by spawning specialized sub-agents for: codebase intelligence gathering, threat modeling (STRIDE), vulnerability scanning (OWASP Top 10, CWE), exploit validation, remediation design, and professional report generation. | "Review the codebase for security issues." | +| **🧪 Unit Tests Bot**
šŸ’» `code` | Opus | **Automated comprehensive unit test generation for any codebase**

Analyzes codebase and generates comprehensive unit tests by: analyzing code structure, creating test plans, writing tests matching your style, verifying execution, optimizing coverage (>80% overall, 100% critical paths), and generating documentation. | "Generate unit tests for this codebase." | ### Available Icons Choose from these icon options when creating agents: + - `bot` - šŸ¤– General purpose - `shield` - šŸ›”ļø Security related - `code` - šŸ’» Development @@ -88,13 +89,15 @@ All agents are stored in `.claudia.json` format with the following structure: The agent import/export system is built on a robust architecture: #### Backend (Rust/Tauri) + - **Storage**: SQLite database stores agent configurations - **Export**: Serializes agent data to JSON with version control - **Import**: Validates and deduplicates agents on import - **GitHub Integration**: Fetches agents via GitHub API #### Frontend (React/TypeScript) -- **UI Components**: + +- **UI Components**: - `CCAgents.tsx` - Main agent management interface - `GitHubAgentBrowser.tsx` - GitHub repository browser - `CreateAgent.tsx` - Agent creation/editing form @@ -113,12 +116,15 @@ The agent import/export system is built on a robust architecture: We welcome agent contributions! Here's how to add your agent: ### 1. Create Your Agent + Design and test your agent in Claudia with a clear, focused purpose. ### 2. Export Your Agent + Export your agent to a `.claudia.json` file with a descriptive name. ### 3. Submit a Pull Request + 1. Fork this repository 2. Add your `.claudia.json` file to the `cc_agents` directory 3. Update this README with your agent's details @@ -139,4 +145,4 @@ These agents are provided under the same license as the Claudia project. See the
Built with ā¤ļø by the Claudia community -
+
diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index 5e231dacf..867b6877e 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -52,7 +52,7 @@ "updater:default", "core:window:allow-minimize", "core:window:allow-maximize", - "core:window:allow-unmaximize", + "core:window:allow-unmaximize", "core:window:allow-close", "core:window:allow-is-maximized", "core:window:allow-start-dragging" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 45094bc91..fd6f36ddb 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -28,17 +28,13 @@ "csp": "default-src 'self'; img-src 'self' asset: https://asset.localhost blob: data:; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-eval' https://app.posthog.com https://*.posthog.com https://*.i.posthog.com https://*.assets.i.posthog.com; connect-src 'self' ipc: https://ipc.localhost https://app.posthog.com https://*.posthog.com https://*.i.posthog.com", "assetProtocol": { "enable": true, - "scope": [ - "**" - ] + "scope": ["**"] } } }, "plugins": { "fs": { - "scope": [ - "$HOME/**" - ], + "scope": ["$HOME/**"], "allow": [ "readFile", "writeFile", @@ -57,13 +53,7 @@ }, "bundle": { "active": true, - "targets": [ - "deb", - "rpm", - "appimage", - "app", - "dmg" - ], + "targets": ["deb", "rpm", "appimage", "app", "dmg"], "icon": [ "icons/32x32.png", "icons/128x128.png", diff --git a/src-tauri/tests/TESTS_COMPLETE.md b/src-tauri/tests/TESTS_COMPLETE.md index 4276a668b..3cc71d93a 100644 --- a/src-tauri/tests/TESTS_COMPLETE.md +++ b/src-tauri/tests/TESTS_COMPLETE.md @@ -5,16 +5,19 @@ ### Key Changes from Original Task: 1. **Replaced MockClaude with Real Claude Execution** āœ… + - Removed all mock Claude implementations - Tests now execute actual `claude` command with `--dangerously-skip-permissions` - Added proper timeout handling for macOS/Linux compatibility 2. **Real Claude Test Implementation** āœ… + - Created `claude_real.rs` with helper functions for executing real Claude - Tests use actual Claude CLI with test prompts - Proper handling of stdout/stderr/exit codes 3. **Test Suite Results:** + ``` test result: ok. 58 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ``` @@ -22,18 +25,22 @@ test result: ok. 58 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out ### Implementation Details: #### Real Claude Execution: + - `execute_claude_task()` - Executes Claude with specified task and captures output - Supports timeout handling (gtimeout on macOS, timeout on Linux) - Returns structured output with stdout, stderr, exit code, and duration - Helper methods for checking operation results #### Test Tasks: + - Simple, focused prompts that execute quickly - Example: "Read the file ./test.txt in the current directory and show its contents" - 20-second timeout to allow Claude sufficient time to respond #### Key Test Updates: + 1. **Agent Tests**: + - Test agent execution with various permission configurations - Test agent execution in different project contexts - Control tests for baseline behavior @@ -43,12 +50,14 @@ test result: ok. 58 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out - Test Claude execution with custom configurations ### Benefits of Real Claude Testing: + - **Authenticity**: Tests validate actual Claude behavior, not mocked responses - **Integration**: Ensures the system works with real Claude execution - **End-to-End**: Complete validation from command invocation to output parsing - **No External Dependencies**: Uses `--dangerously-skip-permissions` flag ### Notes: + - All tests use real Claude CLI commands - No ignored tests - No TODOs in test code diff --git a/src/App.tsx b/src/App.tsx index f798dbc33..bb99bd279 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,18 +19,18 @@ import { MCPManager } from "@/components/MCPManager"; import { NFOCredits } from "@/components/NFOCredits"; import { ClaudeBinaryDialog } from "@/components/ClaudeBinaryDialog"; import { Toast, ToastContainer } from "@/components/ui/toast"; -import { ProjectSettings } from '@/components/ProjectSettings'; +import { ProjectSettings } from "@/components/ProjectSettings"; import { TabManager } from "@/components/TabManager"; import { TabContent } from "@/components/TabContent"; import { useTabState } from "@/hooks/useTabState"; import { AnalyticsConsentBanner } from "@/components/AnalyticsConsent"; import { useAppLifecycle, useTrackEvent } from "@/hooks"; -type View = - | "welcome" - | "projects" - | "editor" - | "claude-file-editor" +type View = + | "welcome" + | "projects" + | "editor" + | "claude-file-editor" | "settings" | "cc-agents" | "create-agent" @@ -47,37 +47,49 @@ type View = */ function AppContent() { const [view, setView] = useState("tabs"); - const { createClaudeMdTab, createSettingsTab, createUsageTab, createMCPTab, createAgentsTab } = useTabState(); + const { + createClaudeMdTab, + createSettingsTab, + createUsageTab, + createMCPTab, + createAgentsTab, + } = useTabState(); const [projects, setProjects] = useState([]); const [selectedProject, setSelectedProject] = useState(null); const [sessions, setSessions] = useState([]); - const [editingClaudeFile, setEditingClaudeFile] = useState(null); + const [editingClaudeFile, setEditingClaudeFile] = + useState(null); const [loading, setLoading] = useState(true); const [_error, setError] = useState(null); const [showNFO, setShowNFO] = useState(false); const [showClaudeBinaryDialog, setShowClaudeBinaryDialog] = useState(false); const [showProjectPicker, setShowProjectPicker] = useState(false); - const [homeDirectory, setHomeDirectory] = useState('/'); - const [toast, setToast] = useState<{ message: string; type: "success" | "error" | "info" } | null>(null); - const [projectForSettings, setProjectForSettings] = useState(null); + const [homeDirectory, setHomeDirectory] = useState("/"); + const [toast, setToast] = useState<{ + message: string; + type: "success" | "error" | "info"; + } | null>(null); + const [projectForSettings, setProjectForSettings] = useState( + null, + ); const [previousView] = useState("welcome"); - + // Initialize analytics lifecycle tracking useAppLifecycle(); const trackEvent = useTrackEvent(); - + // Track user journey milestones const [hasTrackedFirstChat] = useState(false); // const [hasTrackedFirstAgent] = useState(false); - + // Track when user reaches different journey stages useEffect(() => { if (view === "projects" && projects.length > 0 && !hasTrackedFirstChat) { // User has projects - they're past onboarding trackEvent.journeyMilestone({ - journey_stage: 'onboarding', - milestone_reached: 'projects_created', - time_to_milestone_ms: Date.now() - performance.timing.navigationStart + journey_stage: "onboarding", + milestone_reached: "projects_created", + time_to_milestone_ms: Date.now() - performance.timing.navigationStart, }); } }, [view, projects.length, hasTrackedFirstChat, trackEvent]); @@ -95,43 +107,47 @@ function AppContent() { // Keyboard shortcuts for tab navigation useEffect(() => { if (view !== "tabs") return; - + const handleKeyDown = (e: KeyboardEvent) => { - const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0; + const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0; const modKey = isMac ? e.metaKey : e.ctrlKey; - + if (modKey) { switch (e.key) { - case 't': + case "t": e.preventDefault(); - window.dispatchEvent(new CustomEvent('create-chat-tab')); + window.dispatchEvent(new CustomEvent("create-chat-tab")); break; - case 'w': + case "w": e.preventDefault(); - window.dispatchEvent(new CustomEvent('close-current-tab')); + window.dispatchEvent(new CustomEvent("close-current-tab")); break; - case 'Tab': + case "Tab": e.preventDefault(); if (e.shiftKey) { - window.dispatchEvent(new CustomEvent('switch-to-previous-tab')); + window.dispatchEvent(new CustomEvent("switch-to-previous-tab")); } else { - window.dispatchEvent(new CustomEvent('switch-to-next-tab')); + window.dispatchEvent(new CustomEvent("switch-to-next-tab")); } break; default: // Handle number keys 1-9 - if (e.key >= '1' && e.key <= '9') { + if (e.key >= "1" && e.key <= "9") { e.preventDefault(); const index = parseInt(e.key) - 1; - window.dispatchEvent(new CustomEvent('switch-to-tab-by-index', { detail: { index } })); + window.dispatchEvent( + new CustomEvent("switch-to-tab-by-index", { + detail: { index }, + }), + ); } break; } } }; - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); }, [view]); // Listen for Claude not found events @@ -140,9 +156,15 @@ function AppContent() { setShowClaudeBinaryDialog(true); }; - window.addEventListener('claude-not-found', handleClaudeNotFound as EventListener); + window.addEventListener( + "claude-not-found", + handleClaudeNotFound as EventListener, + ); return () => { - window.removeEventListener('claude-not-found', handleClaudeNotFound as EventListener); + window.removeEventListener( + "claude-not-found", + handleClaudeNotFound as EventListener, + ); }; }, []); @@ -157,7 +179,9 @@ function AppContent() { setProjects(projectList); } catch (err) { console.error("Failed to load projects:", err); - setError("Failed to load projects. Please ensure ~/.claude directory exists."); + setError( + "Failed to load projects. Please ensure ~/.claude directory exists.", + ); } finally { setLoading(false); } @@ -225,12 +249,14 @@ function AppContent() { */ // Project settings navigation handled via `projectForSettings` state when needed - const renderContent = () => { switch (view) { case "welcome": return ( -
+
{/* Welcome Header */} - handleViewChange("cc-agents")} > @@ -270,7 +296,7 @@ function AppContent() { animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.15, delay: 0.1 }} > - handleViewChange("projects")} > @@ -280,18 +306,13 @@ function AppContent() {
-
); case "cc-agents": - return ( - handleViewChange("welcome")} - /> - ); + return handleViewChange("welcome")} />; case "editor": return ( @@ -299,10 +320,10 @@ function AppContent() { handleViewChange("welcome")} /> ); - + case "settings": return handleViewChange("welcome")} />; - + case "projects": if (selectedProject) { return ( @@ -321,7 +342,7 @@ function AppContent() { loading={loading} /> ); - + case "claude-file-editor": return editingClaudeFile ? ( ) : null; - + case "tabs": return (
@@ -339,17 +360,13 @@ function AppContent() {
); - + case "usage-dashboard": - return ( - handleViewChange("welcome")} /> - ); - + return handleViewChange("welcome")} />; + case "mcp": - return ( - handleViewChange("welcome")} /> - ); - + return handleViewChange("welcome")} />; + case "project-settings": if (projectForSettings) { return ( @@ -363,7 +380,7 @@ function AppContent() { ); } break; - + default: return null; } @@ -380,7 +397,7 @@ function AppContent() { onSettingsClick={() => createSettingsTab()} onInfoClick={() => setShowNFO(true)} /> - + {/* Topbar - Commented out since navigation moved to titlebar */} {/* createClaudeMdTab()} @@ -390,25 +407,25 @@ function AppContent() { onInfoClick={() => setShowNFO(true)} onAgentsClick={() => setShowAgentsModal(true)} /> */} - + {/* Analytics Consent Banner */} - + {/* Main Content */} -
- {renderContent()} -
- +
{renderContent()}
+ {/* NFO Credits Modal */} {showNFO && setShowNFO(false)} />} - - + {/* Claude Binary Dialog */} { - setToast({ message: "Claude binary path saved successfully", type: "success" }); + setToast({ + message: "Claude binary path saved successfully", + type: "success", + }); // Trigger a refresh of the Claude version check window.location.reload(); }} @@ -430,8 +447,10 @@ function AppContent() { await loadProjects(); await handleProjectClick(project); } catch (err) { - console.error('Failed to create project:', err); - setError('Failed to create project for the selected directory.'); + console.error("Failed to create project:", err); + setError( + "Failed to create project for the selected directory.", + ); } } }} @@ -440,7 +459,7 @@ function AppContent() { )} - + {/* Toast Container */} {toast && ( @@ -468,8 +487,10 @@ function AppContent() { // Load sessions for the selected project await handleProjectClick(project); } catch (err) { - console.error('Failed to create project:', err); - setError('Failed to create project for the selected directory.'); + console.error("Failed to create project:", err); + setError( + "Failed to create project for the selected directory.", + ); } } }} diff --git a/src/assets/shimmer.css b/src/assets/shimmer.css index d41a94d44..bf917baea 100644 --- a/src/assets/shimmer.css +++ b/src/assets/shimmer.css @@ -45,7 +45,8 @@ 95% { background-position: 200% center; } - 96%, 100% { + 96%, + 100% { background-position: 200% center; -webkit-text-fill-color: currentColor; background: none; @@ -54,27 +55,27 @@ @keyframes symbol-rotate { 0% { - content: '◐'; + content: "◐"; opacity: 1; transform: translateY(0) scale(1); } 25% { - content: 'ā—“'; + content: "ā—“"; opacity: 1; transform: translateY(0) scale(1); } 50% { - content: 'ā—‘'; + content: "ā—‘"; opacity: 1; transform: translateY(0) scale(1); } 75% { - content: 'ā—’'; + content: "ā—’"; opacity: 1; transform: translateY(0) scale(1); } 100% { - content: '◐'; + content: "◐"; opacity: 1; transform: translateY(0) scale(1); } @@ -112,7 +113,7 @@ } .rotating-symbol::before { - content: '◐'; + content: "◐"; display: inline-block; animation: symbol-rotate 2s linear infinite; font-size: inherit; @@ -126,7 +127,7 @@ } .shimmer-hover::before { - content: ''; + content: ""; position: absolute; top: -50%; left: 0; @@ -153,4 +154,4 @@ .shimmer-hover:hover::before { animation: shimmer 1s ease-out; -} \ No newline at end of file +} diff --git a/src/components/AgentExecution.tsx b/src/components/AgentExecution.tsx index 41fbb1fd7..c16a0ac97 100644 --- a/src/components/AgentExecution.tsx +++ b/src/components/AgentExecution.tsx @@ -1,9 +1,9 @@ import React, { useState, useEffect, useRef } from "react"; import { motion, AnimatePresence } from "framer-motion"; -import { - ArrowLeft, - Play, - StopCircle, +import { + ArrowLeft, + Play, + StopCircle, Terminal, AlertCircle, Loader2, @@ -11,7 +11,7 @@ import { ChevronDown, Maximize2, X, - Settings2 + Settings2, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -32,7 +32,11 @@ import { ExecutionControlBar } from "./ExecutionControlBar"; import { ErrorBoundary } from "./ErrorBoundary"; import { useVirtualizer } from "@tanstack/react-virtual"; import { HooksEditor } from "./HooksEditor"; -import { useTrackEvent, useComponentMetrics, useFeatureAdoptionTracking } from "@/hooks"; +import { + useTrackEvent, + useComponentMetrics, + useFeatureAdoptionTracking, +} from "@/hooks"; import { useTabState } from "@/hooks/useTabState"; interface AgentExecutionProps { @@ -77,7 +81,7 @@ export interface ClaudeStreamMessage { /** * AgentExecution component for running CC agents - * + * * @example * setView('list')} /> */ @@ -92,30 +96,34 @@ export const AgentExecution: React.FC = ({ const [task, setTask] = useState(agent.default_task || ""); const [model, setModel] = useState(agent.model || "sonnet"); const [isRunning, setIsRunning] = useState(false); - + // Get tab state functions const { updateTabStatus } = useTabState(); const [messages, setMessages] = useState([]); const [rawJsonlOutput, setRawJsonlOutput] = useState([]); const [error, setError] = useState(null); const [copyPopoverOpen, setCopyPopoverOpen] = useState(false); - + // Analytics tracking const trackEvent = useTrackEvent(); - useComponentMetrics('AgentExecution'); - const agentFeatureTracking = useFeatureAdoptionTracking(`agent_${agent.name || 'custom'}`); - + useComponentMetrics("AgentExecution"); + const agentFeatureTracking = useFeatureAdoptionTracking( + `agent_${agent.name || "custom"}`, + ); + // Hooks configuration state const [isHooksDialogOpen, setIsHooksDialogOpen] = useState(false); const [activeHooksTab, setActiveHooksTab] = useState("project"); // Execution stats - const [executionStartTime, setExecutionStartTime] = useState(null); + const [executionStartTime, setExecutionStartTime] = useState( + null, + ); const [totalTokens, setTotalTokens] = useState(0); const [elapsedTime, setElapsedTime] = useState(0); const [hasUserScrolled, setHasUserScrolled] = useState(false); const [isFullscreenModalOpen, setIsFullscreenModalOpen] = useState(false); - + const messagesEndRef = useRef(null); const messagesContainerRef = useRef(null); const scrollContainerRef = useRef(null); @@ -136,12 +144,15 @@ export const AgentExecution: React.FC = ({ // Skip empty user messages if (message.type === "user" && message.message) { if (message.isMeta) return false; - + const msg = message.message; - if (!msg.content || (Array.isArray(msg.content) && msg.content.length === 0)) { + if ( + !msg.content || + (Array.isArray(msg.content) && msg.content.length === 0) + ) { return false; } - + // Check if user message has visible content by checking its parts if (Array.isArray(msg.content)) { let hasVisibleContent = false; @@ -156,17 +167,33 @@ export const AgentExecution: React.FC = ({ // Look for the matching tool_use in previous assistant messages for (let i = index - 1; i >= 0; i--) { const prevMsg = messages[i]; - if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) { - const toolUse = prevMsg.message.content.find((c: any) => - c.type === 'tool_use' && c.id === content.tool_use_id + if ( + prevMsg.type === "assistant" && + prevMsg.message?.content && + Array.isArray(prevMsg.message.content) + ) { + const toolUse = prevMsg.message.content.find( + (c: any) => + c.type === "tool_use" && c.id === content.tool_use_id, ); if (toolUse) { const toolName = toolUse.name?.toLowerCase(); const toolsWithWidgets = [ - 'task', 'edit', 'multiedit', 'todowrite', 'ls', 'read', - 'glob', 'bash', 'write', 'grep' + "task", + "edit", + "multiedit", + "todowrite", + "ls", + "read", + "glob", + "bash", + "write", + "grep", ]; - if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) { + if ( + toolsWithWidgets.includes(toolName) || + toolUse.name?.startsWith("mcp__") + ) { willBeSkipped = true; } break; @@ -174,14 +201,14 @@ export const AgentExecution: React.FC = ({ } } } - + if (!willBeSkipped) { hasVisibleContent = true; break; } } } - + if (!hasVisibleContent) { return false; } @@ -210,7 +237,7 @@ export const AgentExecution: React.FC = ({ useEffect(() => { // Clean up listeners on unmount return () => { - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); if (elapsedTimeIntervalRef.current) { clearInterval(elapsedTimeIntervalRef.current); } @@ -219,7 +246,9 @@ export const AgentExecution: React.FC = ({ // Check if user is at the very bottom of the scrollable container const isAtBottom = () => { - const container = isFullscreenModalOpen ? fullscreenScrollRef.current : scrollContainerRef.current; + const container = isFullscreenModalOpen + ? fullscreenScrollRef.current + : scrollContainerRef.current; if (container) { const { scrollTop, scrollHeight, clientHeight } = container; const distanceFromBottom = scrollHeight - scrollTop - clientHeight; @@ -236,12 +265,24 @@ export const AgentExecution: React.FC = ({ if (shouldAutoScroll) { if (isFullscreenModalOpen) { - fullscreenRowVirtualizer.scrollToIndex(displayableMessages.length - 1, { align: "end", behavior: "smooth" }); + fullscreenRowVirtualizer.scrollToIndex(displayableMessages.length - 1, { + align: "end", + behavior: "smooth", + }); } else { - rowVirtualizer.scrollToIndex(displayableMessages.length - 1, { align: "end", behavior: "smooth" }); + rowVirtualizer.scrollToIndex(displayableMessages.length - 1, { + align: "end", + behavior: "smooth", + }); } } - }, [displayableMessages.length, hasUserScrolled, isFullscreenModalOpen, rowVirtualizer, fullscreenRowVirtualizer]); + }, [ + displayableMessages.length, + hasUserScrolled, + isFullscreenModalOpen, + rowVirtualizer, + fullscreenRowVirtualizer, + ]); // Update elapsed time while running useEffect(() => { @@ -254,7 +295,7 @@ export const AgentExecution: React.FC = ({ clearInterval(elapsedTimeIntervalRef.current); } } - + return () => { if (elapsedTimeIntervalRef.current) { clearInterval(elapsedTimeIntervalRef.current); @@ -266,7 +307,11 @@ export const AgentExecution: React.FC = ({ useEffect(() => { const tokens = messages.reduce((total, msg) => { if (msg.message?.usage) { - return total + msg.message.usage.input_tokens + msg.message.usage.output_tokens; + return ( + total + + msg.message.usage.input_tokens + + msg.message.usage.output_tokens + ); } if (msg.usage) { return total + msg.usage.input_tokens + msg.usage.output_tokens; @@ -276,7 +321,6 @@ export const AgentExecution: React.FC = ({ setTotalTokens(tokens); }, [messages]); - // Project path selection is handled upstream when opening an execution tab const handleOpenHooksDialog = async () => { @@ -287,99 +331,133 @@ export const AgentExecution: React.FC = ({ try { setIsRunning(true); // Update tab status to running - console.log('Setting tab status to running for tab:', tabId); + console.log("Setting tab status to running for tab:", tabId); if (tabId) { - updateTabStatus(tabId, 'running'); + updateTabStatus(tabId, "running"); } setExecutionStartTime(Date.now()); setMessages([]); setRawJsonlOutput([]); setRunId(null); - + // Clear any existing listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // Execute the agent and get the run ID - const executionRunId = await api.executeAgent(agent.id!, projectPath, task, model); + const executionRunId = await api.executeAgent( + agent.id!, + projectPath, + task, + model, + ); console.log("Agent execution started with run ID:", executionRunId); setRunId(executionRunId); - + // Track agent execution start trackEvent.agentStarted({ - agent_type: agent.name || 'custom', + agent_type: agent.name || "custom", agent_name: agent.name, - has_custom_prompt: task !== agent.default_task + has_custom_prompt: task !== agent.default_task, }); - + // Track feature adoption agentFeatureTracking.trackUsage(); - - // Set up event listeners with run ID isolation - const outputUnlisten = await listen(`agent-output:${executionRunId}`, (event) => { - try { - // Store raw JSONL - setRawJsonlOutput(prev => [...prev, event.payload]); - - // Parse and display - const message = JSON.parse(event.payload) as ClaudeStreamMessage; - setMessages(prev => [...prev, message]); - } catch (err) { - console.error("Failed to parse message:", err, event.payload); - } - }); - const errorUnlisten = await listen(`agent-error:${executionRunId}`, (event) => { - console.error("Agent error:", event.payload); - setError(event.payload); - - // Track agent error - trackEvent.agentError({ - error_type: 'runtime_error', - error_stage: 'execution', - retry_count: 0, - agent_type: agent.name || 'custom' - }); - }); + // Set up event listeners with run ID isolation + const outputUnlisten = await listen( + `agent-output:${executionRunId}`, + (event) => { + try { + // Store raw JSONL + setRawJsonlOutput((prev) => [...prev, event.payload]); - const completeUnlisten = await listen(`agent-complete:${executionRunId}`, (event) => { - setIsRunning(false); - const duration = executionStartTime ? Date.now() - executionStartTime : undefined; - setExecutionStartTime(null); - if (!event.payload) { - setError("Agent execution failed"); - // Update tab status to error - if (tabId) { - updateTabStatus(tabId, 'error'); + // Parse and display + const message = JSON.parse(event.payload) as ClaudeStreamMessage; + setMessages((prev) => [...prev, message]); + } catch (err) { + console.error("Failed to parse message:", err, event.payload); } - // Track both the old event for compatibility and the new error event - trackEvent.agentExecuted(agent.name || 'custom', false, agent.name, duration); + }, + ); + + const errorUnlisten = await listen( + `agent-error:${executionRunId}`, + (event) => { + console.error("Agent error:", event.payload); + setError(event.payload); + + // Track agent error trackEvent.agentError({ - error_type: 'execution_failed', - error_stage: 'completion', + error_type: "runtime_error", + error_stage: "execution", retry_count: 0, - agent_type: agent.name || 'custom' + agent_type: agent.name || "custom", }); - } else { - // Update tab status to complete on success - if (tabId) { - updateTabStatus(tabId, 'complete'); + }, + ); + + const completeUnlisten = await listen( + `agent-complete:${executionRunId}`, + (event) => { + setIsRunning(false); + const duration = executionStartTime + ? Date.now() - executionStartTime + : undefined; + setExecutionStartTime(null); + if (!event.payload) { + setError("Agent execution failed"); + // Update tab status to error + if (tabId) { + updateTabStatus(tabId, "error"); + } + // Track both the old event for compatibility and the new error event + trackEvent.agentExecuted( + agent.name || "custom", + false, + agent.name, + duration, + ); + trackEvent.agentError({ + error_type: "execution_failed", + error_stage: "completion", + retry_count: 0, + agent_type: agent.name || "custom", + }); + } else { + // Update tab status to complete on success + if (tabId) { + updateTabStatus(tabId, "complete"); + } + trackEvent.agentExecuted( + agent.name || "custom", + true, + agent.name, + duration, + ); } - trackEvent.agentExecuted(agent.name || 'custom', true, agent.name, duration); - } - }); + }, + ); - const cancelUnlisten = await listen(`agent-cancelled:${executionRunId}`, () => { - setIsRunning(false); - setExecutionStartTime(null); - setError("Agent execution was cancelled"); - // Update tab status to idle when cancelled - if (tabId) { - updateTabStatus(tabId, 'idle'); - } - }); + const cancelUnlisten = await listen( + `agent-cancelled:${executionRunId}`, + () => { + setIsRunning(false); + setExecutionStartTime(null); + setError("Agent execution was cancelled"); + // Update tab status to idle when cancelled + if (tabId) { + updateTabStatus(tabId, "idle"); + } + }, + ); - unlistenRefs.current = [outputUnlisten, errorUnlisten, completeUnlisten, cancelUnlisten]; + unlistenRefs.current = [ + outputUnlisten, + errorUnlisten, + completeUnlisten, + cancelUnlisten, + ]; } catch (err) { console.error("Failed to execute agent:", err); setIsRunning(false); @@ -387,20 +465,23 @@ export const AgentExecution: React.FC = ({ setRunId(null); // Update tab status to error if (tabId) { - updateTabStatus(tabId, 'error'); + updateTabStatus(tabId, "error"); } // Show error in messages - setMessages(prev => [...prev, { - type: "result", - subtype: "error", - is_error: true, - result: `Failed to execute agent: ${err instanceof Error ? err.message : 'Unknown error'}`, - duration_ms: 0, - usage: { - input_tokens: 0, - output_tokens: 0 - } - }]); + setMessages((prev) => [ + ...prev, + { + type: "result", + subtype: "error", + is_error: true, + result: `Failed to execute agent: ${err instanceof Error ? err.message : "Unknown error"}`, + duration_ms: 0, + usage: { + input_tokens: 0, + output_tokens: 0, + }, + }, + ]); } }; @@ -413,37 +494,42 @@ export const AgentExecution: React.FC = ({ // Call the API to kill the agent session const success = await api.killAgentSession(runId); - + if (success) { console.log(`Successfully stopped agent session ${runId}`); } else { - console.warn(`Failed to stop agent session ${runId} - it may have already finished`); + console.warn( + `Failed to stop agent session ${runId} - it may have already finished`, + ); } - + // Update UI state setIsRunning(false); setExecutionStartTime(null); // Update tab status to idle when stopped if (tabId) { - updateTabStatus(tabId, 'idle'); + updateTabStatus(tabId, "idle"); } - + // Clean up listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // Add a message indicating execution was stopped - setMessages(prev => [...prev, { - type: "result", - subtype: "error", - is_error: true, - result: "Execution stopped by user", - duration_ms: elapsedTime * 1000, - usage: { - input_tokens: totalTokens, - output_tokens: 0 - } - }]); + setMessages((prev) => [ + ...prev, + { + type: "result", + subtype: "error", + is_error: true, + result: "Execution stopped by user", + duration_ms: elapsedTime * 1000, + usage: { + input_tokens: totalTokens, + output_tokens: 0, + }, + }, + ]); } catch (err) { console.error("Failed to stop agent:", err); // Still update UI state even if the backend call failed @@ -451,21 +537,24 @@ export const AgentExecution: React.FC = ({ setExecutionStartTime(null); // Update tab status to idle if (tabId) { - updateTabStatus(tabId, 'idle'); + updateTabStatus(tabId, "idle"); } - + // Show error message - setMessages(prev => [...prev, { - type: "result", - subtype: "error", - is_error: true, - result: `Failed to stop execution: ${err instanceof Error ? err.message : 'Unknown error'}`, - duration_ms: elapsedTime * 1000, - usage: { - input_tokens: totalTokens, - output_tokens: 0 - } - }]); + setMessages((prev) => [ + ...prev, + { + type: "result", + subtype: "error", + is_error: true, + result: `Failed to stop execution: ${err instanceof Error ? err.message : "Unknown error"}`, + duration_ms: elapsedTime * 1000, + usage: { + input_tokens: totalTokens, + output_tokens: 0, + }, + }, + ]); } }; @@ -473,23 +562,23 @@ export const AgentExecution: React.FC = ({ if (isRunning) { // Show confirmation dialog before navigating away during execution const shouldLeave = window.confirm( - "An agent is currently running. If you navigate away, the agent will continue running in the background. You can view running sessions in the 'Running Sessions' tab within CC Agents.\n\nDo you want to continue?" + "An agent is currently running. If you navigate away, the agent will continue running in the background. You can view running sessions in the 'Running Sessions' tab within CC Agents.\n\nDo you want to continue?", ); if (!shouldLeave) { return; } } - + // Clean up listeners but don't stop the actual agent process - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // Navigate back onBack(); }; const handleCopyAsJsonl = async () => { - const jsonl = rawJsonlOutput.join('\n'); + const jsonl = rawJsonlOutput.join("\n"); await navigator.clipboard.writeText(jsonl); setCopyPopoverOpen(false); }; @@ -497,17 +586,17 @@ export const AgentExecution: React.FC = ({ const handleCopyAsMarkdown = async () => { let markdown = `# Agent Execution: ${agent.name}\n\n`; markdown += `**Task:** ${task}\n`; - markdown += `**Model:** ${model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}\n`; + markdown += `**Model:** ${model === "opus" ? "Claude 4 Opus" : "Claude 4 Sonnet"}\n`; markdown += `**Date:** ${new Date().toISOString()}\n\n`; markdown += `---\n\n`; for (const msg of messages) { if (msg.type === "system" && msg.subtype === "init") { markdown += `## System Initialization\n\n`; - markdown += `- Session ID: \`${msg.session_id || 'N/A'}\`\n`; - markdown += `- Model: \`${msg.model || 'default'}\`\n`; + markdown += `- Session ID: \`${msg.session_id || "N/A"}\`\n`; + markdown += `- Model: \`${msg.model || "default"}\`\n`; if (msg.cwd) markdown += `- Working Directory: \`${msg.cwd}\`\n`; - if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(', ')}\n`; + if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(", ")}\n`; markdown += `\n`; } else if (msg.type === "assistant" && msg.message) { markdown += `## Assistant\n\n`; @@ -560,7 +649,6 @@ export const AgentExecution: React.FC = ({ setCopyPopoverOpen(false); }; - return (
{/* Fixed container that takes full height */} @@ -581,7 +669,12 @@ export const AgentExecution: React.FC = ({

{agent.name}

- {isRunning ? 'Running' : messages.length > 0 ? 'Complete' : 'Ready'} • {model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'} + {isRunning + ? "Running" + : messages.length > 0 + ? "Complete" + : "Ready"}{" "} + • {model === "opus" ? "Claude 4 Opus" : "Claude 4 Sonnet"}

@@ -599,7 +692,7 @@ export const AgentExecution: React.FC = ({ - + {/* Configuration Section */}
@@ -619,7 +712,9 @@ export const AgentExecution: React.FC = ({ {/* Model Selection */}
- +
= ({ transition={{ duration: 0.15 }} className={cn( "flex-1 px-4 py-3 rounded-md border transition-all", - model === "sonnet" - ? "border-primary bg-primary/10 text-primary" + model === "sonnet" + ? "border-primary bg-primary/10 text-primary" : "border-border hover:border-primary/50 hover:bg-accent", - isRunning && "opacity-50 cursor-not-allowed" + isRunning && "opacity-50 cursor-not-allowed", )} disabled={isRunning} >
-
+
{model === "sonnet" && (
)}
-
Claude 4 Sonnet
-
Faster, efficient
+
+ Claude 4 Sonnet +
+
+ Faster, efficient +
- + !isRunning && setModel("opus")} @@ -658,25 +761,33 @@ export const AgentExecution: React.FC = ({ transition={{ duration: 0.15 }} className={cn( "flex-1 px-4 py-3 rounded-md border transition-all", - model === "opus" - ? "border-primary bg-primary/10 text-primary" + model === "opus" + ? "border-primary bg-primary/10 text-primary" : "border-border hover:border-primary/50 hover:bg-accent", - isRunning && "opacity-50 cursor-not-allowed" + isRunning && "opacity-50 cursor-not-allowed", )} disabled={isRunning} >
-
+
{model === "opus" && (
)}
-
Claude 4 Opus
-
More capable
+
+ Claude 4 Opus +
+
+ More capable +
@@ -686,7 +797,9 @@ export const AgentExecution: React.FC = ({ {/* Task Input */}
- + {projectPath && (
{projectPath && (

- Working in: {projectPath.split('/').pop() || projectPath} + Working in:{" "} + + {projectPath.split("/").pop() || projectPath} +

)}
@@ -749,7 +870,7 @@ export const AgentExecution: React.FC = ({ {/* Scrollable Output Display */}
-
{ @@ -757,7 +878,7 @@ export const AgentExecution: React.FC = ({ if (!hasUserScrolled) { setHasUserScrolled(true); } - + // If user scrolls back to bottom, re-enable auto-scroll if (isAtBottom()) { setHasUserScrolled(false); @@ -765,53 +886,60 @@ export const AgentExecution: React.FC = ({ }} >
- {messages.length === 0 && !isRunning && ( -
- -

Ready to Execute

-

- Enter a task to run the agent -

-
- )} + {messages.length === 0 && !isRunning && ( +
+ +

+ Ready to Execute +

+

+ Enter a task to run the agent +

+
+ )} - {isRunning && messages.length === 0 && ( -
-
- - Initializing agent... + {isRunning && messages.length === 0 && ( +
+
+ + + Initializing agent... + +
+ )} + +
+ + {rowVirtualizer.getVirtualItems().map((virtualItem) => { + const message = displayableMessages[virtualItem.index]; + return ( + el && rowVirtualizer.measureElement(el)} + initial={{ opacity: 0, y: 10 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.2 }} + className="absolute inset-x-4 pb-4" + style={{ top: virtualItem.start }} + > + + + + + ); + })} +
- )} -
- - {rowVirtualizer.getVirtualItems().map((virtualItem) => { - const message = displayableMessages[virtualItem.index]; - return ( - el && rowVirtualizer.measureElement(el)} - initial={{ opacity: 0, y: 10 }} - animate={{ opacity: 1, y: 0 }} - transition={{ duration: 0.2 }} - className="absolute inset-x-4 pb-4" - style={{ top: virtualItem.start }} - > - - - - - ); - })} - -
- -
+
@@ -836,7 +964,9 @@ export const AgentExecution: React.FC = ({ {isRunning && (
- Running + + Running +
)}
@@ -891,7 +1021,7 @@ export const AgentExecution: React.FC = ({ {/* Modal Content */}
-
{ @@ -899,7 +1029,7 @@ export const AgentExecution: React.FC = ({ if (!hasUserScrolled) { setHasUserScrolled(true); } - + // If user scrolls back to bottom, re-enable auto-scroll if (isAtBottom()) { setHasUserScrolled(false); @@ -920,38 +1050,49 @@ export const AgentExecution: React.FC = ({
- Initializing agent... + + Initializing agent... +
)}
- {fullscreenRowVirtualizer.getVirtualItems().map((virtualItem) => { - const message = displayableMessages[virtualItem.index]; - return ( - el && fullscreenRowVirtualizer.measureElement(el)} - initial={{ opacity: 0, y: 10 }} - animate={{ opacity: 1, y: 0 }} - transition={{ duration: 0.2 }} - className="absolute inset-x-4 pb-4" - style={{ top: virtualItem.start }} - > - - - - - ); - })} + {fullscreenRowVirtualizer + .getVirtualItems() + .map((virtualItem) => { + const message = displayableMessages[virtualItem.index]; + return ( + + el && fullscreenRowVirtualizer.measureElement(el) + } + initial={{ opacity: 0, y: 10 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.2 }} + className="absolute inset-x-4 pb-4" + style={{ top: virtualItem.start }} + > + + + + + ); + })}
- +
@@ -959,36 +1100,52 @@ export const AgentExecution: React.FC = ({ )} {/* Hooks Configuration Dialog */} - +
- Configure Hooks + + Configure Hooks + Configure hooks that run before, during, and after tool executions
- - + +
- + Project Settings - + Local Settings
- - + +

- Project hooks are stored in .claude/settings.json and - are committed to version control, allowing team members to share configurations. + Project hooks are stored in{" "} + + .claude/settings.json + {" "} + and are committed to version control, allowing team members + to share configurations.

= ({ />
- - + +

- Local hooks are stored in .claude/settings.local.json and - are not committed to version control, perfect for personal preferences. + Local hooks are stored in{" "} + + .claude/settings.local.json + {" "} + and are not committed to version control, perfect for + personal preferences.

{ type: "user", isMeta: true, message: { content: [] }, - timestamp: "2025-06-11T14:08:53.771Z" + timestamp: "2025-06-11T14:08:53.771Z", }, - + // Summary message { leafUuid: "3c5ecb4f-c1f0-40c2-a357-ab7642ad28b8", summary: "JSONL Viewer Model Configuration and Setup", - type: "summary" as any + type: "summary" as any, }, - + // Assistant with Edit tool { type: "assistant", message: { - content: [{ - type: "tool_use", - name: "Edit", - input: { - file_path: "/Users/mufeedvh/dev/jsonl-viewer/script.js", - new_string: "reader.onerror = () => reject(new Error('Failed to read file'));", - old_string: "reader.onerror = e => reject(new Error('Failed to read file'));" - } - }], - usage: { input_tokens: 4, output_tokens: 158 } - } + content: [ + { + type: "tool_use", + name: "Edit", + input: { + file_path: "/Users/mufeedvh/dev/jsonl-viewer/script.js", + new_string: + "reader.onerror = () => reject(new Error('Failed to read file'));", + old_string: + "reader.onerror = e => reject(new Error('Failed to read file'));", + }, + }, + ], + usage: { input_tokens: 4, output_tokens: 158 }, + }, }, - + // User with Edit tool result { type: "user", message: { - content: [{ - type: "tool_result", - content: `The file /Users/mufeedvh/dev/jsonl-viewer/script.js has been updated. Here's the result of running \`cat -n\` on a snippet of the edited file: + content: [ + { + type: "tool_result", + content: `The file /Users/mufeedvh/dev/jsonl-viewer/script.js has been updated. Here's the result of running \`cat -n\` on a snippet of the edited file: 220 readFileAsText(file) { 221 return new Promise((resolve, reject) => { 222 const reader = new FileReader(); @@ -55,45 +60,52 @@ export const AgentExecutionDemo: React.FC = () => { 225 reader.readAsText(file); 226 }); 227 } - 228` - }] - } + 228`, + }, + ], + }, }, - + // Assistant with MCP tool { type: "assistant", message: { - content: [{ - type: "tool_use", - name: "mcp__ide__getDiagnostics", - input: {} - }], - usage: { input_tokens: 4, output_tokens: 37 } - } + content: [ + { + type: "tool_use", + name: "mcp__ide__getDiagnostics", + input: {}, + }, + ], + usage: { input_tokens: 4, output_tokens: 37 }, + }, }, - + // User with empty tool result { type: "user", message: { - content: [{ - type: "tool_result", - content: "" - }] - } + content: [ + { + type: "tool_result", + content: "", + }, + ], + }, }, - + // Assistant with Write tool (large content) { type: "assistant", message: { - content: [{ - type: "tool_use", - name: "Write", - input: { - file_path: "/Users/mufeedvh/dev/jsonl-viewer/styles.css", - content: `/* Reset and Base Styles */ + content: [ + { + type: "tool_use", + name: "Write", + input: { + file_path: "/Users/mufeedvh/dev/jsonl-viewer/styles.css", + content: + `/* Reset and Base Styles */ * { margin: 0; padding: 0; @@ -162,20 +174,23 @@ body { /* ... many more lines of CSS ... */ /* This content is over 1000 characters so it should show the maximize button */ -` + '\n'.repeat(100) + '/* End of very long CSS file */' - } - }] - } - } +` + + "\n".repeat(100) + + "/* End of very long CSS file */", + }, + }, + ], + }, + }, ]; return (

Agent Execution Demo

- + {messages.map((message, idx) => ( ))}
); -}; \ No newline at end of file +}; diff --git a/src/components/AgentRunOutputViewer.tsx b/src/components/AgentRunOutputViewer.tsx index d83fb9317..2db24009e 100644 --- a/src/components/AgentRunOutputViewer.tsx +++ b/src/components/AgentRunOutputViewer.tsx @@ -1,32 +1,32 @@ -import { useState, useEffect, useRef, useMemo } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { - Maximize2, - Minimize2, - Copy, - RefreshCw, - RotateCcw, +import { useState, useEffect, useRef, useMemo } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + Maximize2, + Minimize2, + Copy, + RefreshCw, + RotateCcw, ChevronDown, Bot, Clock, Hash, DollarSign, - StopCircle -} from 'lucide-react'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; -import { Badge } from '@/components/ui/badge'; -import { Toast, ToastContainer } from '@/components/ui/toast'; -import { Popover } from '@/components/ui/popover'; -import { api, type AgentRunWithMetrics } from '@/lib/api'; -import { useOutputCache } from '@/lib/outputCache'; -import { listen, type UnlistenFn } from '@tauri-apps/api/event'; -import { StreamMessage } from './StreamMessage'; -import { ErrorBoundary } from './ErrorBoundary'; -import { formatISOTimestamp } from '@/lib/date-utils'; -import { AGENT_ICONS } from './CCAgents'; -import type { ClaudeStreamMessage } from './AgentExecution'; -import { useTabState } from '@/hooks/useTabState'; + StopCircle, +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Toast, ToastContainer } from "@/components/ui/toast"; +import { Popover } from "@/components/ui/popover"; +import { api, type AgentRunWithMetrics } from "@/lib/api"; +import { useOutputCache } from "@/lib/outputCache"; +import { listen, type UnlistenFn } from "@tauri-apps/api/event"; +import { StreamMessage } from "./StreamMessage"; +import { ErrorBoundary } from "./ErrorBoundary"; +import { formatISOTimestamp } from "@/lib/date-utils"; +import { AGENT_ICONS } from "./CCAgents"; +import type { ClaudeStreamMessage } from "./AgentExecution"; +import { useTabState } from "@/hooks/useTabState"; interface AgentRunOutputViewerProps { /** @@ -45,17 +45,17 @@ interface AgentRunOutputViewerProps { /** * AgentRunOutputViewer - Modal component for viewing agent execution output - * + * * @example * setSelectedRun(null)} * /> */ -export function AgentRunOutputViewer({ - agentRunId, +export function AgentRunOutputViewer({ + agentRunId, tabId, - className + className, }: AgentRunOutputViewerProps) { const { updateTabTitle, updateTabStatus } = useTabState(); const [run, setRun] = useState(null); @@ -64,14 +64,17 @@ export function AgentRunOutputViewer({ const [loading, setLoading] = useState(true); const [isFullscreen, setIsFullscreen] = useState(false); const [refreshing, setRefreshing] = useState(false); - const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null); + const [toast, setToast] = useState<{ + message: string; + type: "success" | "error"; + } | null>(null); const [copyPopoverOpen, setCopyPopoverOpen] = useState(false); const [hasUserScrolled, setHasUserScrolled] = useState(false); - + // Track whether we're in the initial load phase const isInitialLoadRef = useRef(true); const hasSetupListenersRef = useRef(false); - + const scrollAreaRef = useRef(null); const outputEndRef = useRef(null); const fullscreenScrollRef = useRef(null); @@ -81,7 +84,9 @@ export function AgentRunOutputViewer({ // Auto-scroll logic const isAtBottom = () => { - const container = isFullscreen ? fullscreenScrollRef.current : scrollAreaRef.current; + const container = isFullscreen + ? fullscreenScrollRef.current + : scrollAreaRef.current; if (container) { const { scrollTop, scrollHeight, clientHeight } = container; const distanceFromBottom = scrollHeight - scrollTop - clientHeight; @@ -92,9 +97,11 @@ export function AgentRunOutputViewer({ const scrollToBottom = () => { if (!hasUserScrolled) { - const endRef = isFullscreen ? fullscreenMessagesEndRef.current : outputEndRef.current; + const endRef = isFullscreen + ? fullscreenMessagesEndRef.current + : outputEndRef.current; if (endRef) { - endRef.scrollIntoView({ behavior: 'smooth' }); + endRef.scrollIntoView({ behavior: "smooth" }); } } }; @@ -106,16 +113,23 @@ export function AgentRunOutputViewer({ setLoading(true); const agentRun = await api.getAgentRun(parseInt(agentRunId)); setRun(agentRun); - updateTabTitle(tabId, `Agent: ${agentRun.agent_name || 'Unknown'}`); - updateTabStatus(tabId, agentRun.status === 'running' ? 'running' : agentRun.status === 'failed' ? 'error' : 'complete'); + updateTabTitle(tabId, `Agent: ${agentRun.agent_name || "Unknown"}`); + updateTabStatus( + tabId, + agentRun.status === "running" + ? "running" + : agentRun.status === "failed" + ? "error" + : "complete", + ); } catch (error) { - console.error('Failed to load agent run:', error); - updateTabStatus(tabId, 'error'); + console.error("Failed to load agent run:", error); + updateTabStatus(tabId, "error"); } finally { setLoading(false); } }; - + if (agentRunId) { loadAgentRun(); } @@ -124,7 +138,7 @@ export function AgentRunOutputViewer({ // Cleanup on unmount useEffect(() => { return () => { - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; hasSetupListenersRef.current = false; }; @@ -141,11 +155,11 @@ export function AgentRunOutputViewer({ const loadOutput = async (skipCache = false) => { if (!run?.id) return; - console.log('[AgentRunOutputViewer] Loading output for run:', { + console.log("[AgentRunOutputViewer] Loading output for run:", { runId: run.id, status: run.status, sessionId: run.session_id, - skipCache + skipCache, }); try { @@ -153,13 +167,20 @@ export function AgentRunOutputViewer({ if (!skipCache) { const cached = getCachedOutput(run.id); if (cached) { - console.log('[AgentRunOutputViewer] Found cached output'); - const cachedJsonlLines = cached.output.split('\n').filter(line => line.trim()); + console.log("[AgentRunOutputViewer] Found cached output"); + const cachedJsonlLines = cached.output + .split("\n") + .filter((line) => line.trim()); setRawJsonlOutput(cachedJsonlLines); setMessages(cached.messages); // If cache is recent (less than 5 seconds old) and session isn't running, use cache only - if (Date.now() - cached.lastUpdated < 5000 && run.status !== 'running') { - console.log('[AgentRunOutputViewer] Using recent cache, skipping refresh'); + if ( + Date.now() - cached.lastUpdated < 5000 && + run.status !== "running" + ) { + console.log( + "[AgentRunOutputViewer] Using recent cache, skipping refresh", + ); return; } } @@ -168,93 +189,131 @@ export function AgentRunOutputViewer({ setLoading(true); // If we have a session_id, try to load from JSONL file first - if (run.session_id && run.session_id !== '') { - console.log('[AgentRunOutputViewer] Attempting to load from JSONL with session_id:', run.session_id); + if (run.session_id && run.session_id !== "") { + console.log( + "[AgentRunOutputViewer] Attempting to load from JSONL with session_id:", + run.session_id, + ); try { const history = await api.loadAgentSessionHistory(run.session_id); - console.log('[AgentRunOutputViewer] Successfully loaded JSONL history:', history.length, 'messages'); - + console.log( + "[AgentRunOutputViewer] Successfully loaded JSONL history:", + history.length, + "messages", + ); + // Convert history to messages format - const loadedMessages: ClaudeStreamMessage[] = history.map(entry => ({ - ...entry, - type: entry.type || "assistant" - })); - + const loadedMessages: ClaudeStreamMessage[] = history.map( + (entry) => ({ + ...entry, + type: entry.type || "assistant", + }), + ); + setMessages(loadedMessages); - setRawJsonlOutput(history.map(h => JSON.stringify(h))); - + setRawJsonlOutput(history.map((h) => JSON.stringify(h))); + // Update cache setCachedOutput(run.id, { - output: history.map(h => JSON.stringify(h)).join('\n'), + output: history.map((h) => JSON.stringify(h)).join("\n"), messages: loadedMessages, lastUpdated: Date.now(), - status: run.status + status: run.status, }); - + // Set up live event listeners for running sessions - if (run.status === 'running') { - console.log('[AgentRunOutputViewer] Setting up live listeners for running session'); + if (run.status === "running") { + console.log( + "[AgentRunOutputViewer] Setting up live listeners for running session", + ); setupLiveEventListeners(); - + try { await api.streamSessionOutput(run.id); } catch (streamError) { - console.warn('[AgentRunOutputViewer] Failed to start streaming, will poll instead:', streamError); + console.warn( + "[AgentRunOutputViewer] Failed to start streaming, will poll instead:", + streamError, + ); } } - + return; } catch (err) { - console.warn('[AgentRunOutputViewer] Failed to load from JSONL:', err); - console.warn('[AgentRunOutputViewer] Falling back to regular output method'); + console.warn( + "[AgentRunOutputViewer] Failed to load from JSONL:", + err, + ); + console.warn( + "[AgentRunOutputViewer] Falling back to regular output method", + ); } } else { - console.log('[AgentRunOutputViewer] No session_id available, using fallback method'); + console.log( + "[AgentRunOutputViewer] No session_id available, using fallback method", + ); } // Fallback to the original method if JSONL loading fails or no session_id - console.log('[AgentRunOutputViewer] Using getSessionOutput fallback'); + console.log("[AgentRunOutputViewer] Using getSessionOutput fallback"); const rawOutput = await api.getSessionOutput(run.id); - console.log('[AgentRunOutputViewer] Received raw output:', rawOutput.length, 'characters'); - + console.log( + "[AgentRunOutputViewer] Received raw output:", + rawOutput.length, + "characters", + ); + // Parse JSONL output into messages - const jsonlLines = rawOutput.split('\n').filter(line => line.trim()); + const jsonlLines = rawOutput.split("\n").filter((line) => line.trim()); setRawJsonlOutput(jsonlLines); - + const parsedMessages: ClaudeStreamMessage[] = []; for (const line of jsonlLines) { try { const message = JSON.parse(line) as ClaudeStreamMessage; parsedMessages.push(message); } catch (err) { - console.error("[AgentRunOutputViewer] Failed to parse message:", err, line); + console.error( + "[AgentRunOutputViewer] Failed to parse message:", + err, + line, + ); } } - console.log('[AgentRunOutputViewer] Parsed', parsedMessages.length, 'messages from output'); + console.log( + "[AgentRunOutputViewer] Parsed", + parsedMessages.length, + "messages from output", + ); setMessages(parsedMessages); - + // Update cache setCachedOutput(run.id, { output: rawOutput, messages: parsedMessages, lastUpdated: Date.now(), - status: run.status + status: run.status, }); - + // Set up live event listeners for running sessions - if (run.status === 'running') { - console.log('[AgentRunOutputViewer] Setting up live listeners for running session (fallback)'); + if (run.status === "running") { + console.log( + "[AgentRunOutputViewer] Setting up live listeners for running session (fallback)", + ); setupLiveEventListeners(); - + try { await api.streamSessionOutput(run.id); } catch (streamError) { - console.warn('[AgentRunOutputViewer] Failed to start streaming (fallback), will poll instead:', streamError); + console.warn( + "[AgentRunOutputViewer] Failed to start streaming (fallback), will poll instead:", + streamError, + ); } } } catch (error) { - console.error('Failed to load agent output:', error); - setToast({ message: 'Failed to load agent output', type: 'error' }); + console.error("Failed to load agent output:", error); + setToast({ message: "Failed to load agent output", type: "error" }); } finally { setLoading(false); } @@ -263,15 +322,15 @@ export function AgentRunOutputViewer({ // Set up live event listeners for running sessions const setupLiveEventListeners = async () => { if (!run?.id || hasSetupListenersRef.current) return; - + try { // Clean up existing listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; // Mark that we've set up listeners hasSetupListenersRef.current = true; - + // After setup, we're no longer in initial load // Small delay to ensure any pending messages are processed setTimeout(() => { @@ -279,71 +338,100 @@ export function AgentRunOutputViewer({ }, 100); // Set up live event listeners with run ID isolation - const outputUnlisten = await listen(`agent-output:${run!.id}`, (event) => { - try { - // Skip messages during initial load phase - if (isInitialLoadRef.current) { - console.log('[AgentRunOutputViewer] Skipping message during initial load'); - return; - } - - // Store raw JSONL - setRawJsonlOutput(prev => [...prev, event.payload]); - - // Parse and display - const message = JSON.parse(event.payload) as ClaudeStreamMessage; - setMessages(prev => [...prev, message]); - } catch (err) { - console.error("[AgentRunOutputViewer] Failed to parse message:", err, event.payload); - } - }); - - const errorUnlisten = await listen(`agent-error:${run!.id}`, (event) => { - console.error("[AgentRunOutputViewer] Agent error:", event.payload); - setToast({ message: event.payload, type: 'error' }); - }); - - const completeUnlisten = await listen(`agent-complete:${run!.id}`, () => { - setToast({ message: 'Agent execution completed', type: 'success' }); - // Don't set status here as the parent component should handle it - }); - - const cancelUnlisten = await listen(`agent-cancelled:${run!.id}`, () => { - setToast({ message: 'Agent execution was cancelled', type: 'error' }); - }); + const outputUnlisten = await listen( + `agent-output:${run!.id}`, + (event) => { + try { + // Skip messages during initial load phase + if (isInitialLoadRef.current) { + console.log( + "[AgentRunOutputViewer] Skipping message during initial load", + ); + return; + } - unlistenRefs.current = [outputUnlisten, errorUnlisten, completeUnlisten, cancelUnlisten]; + // Store raw JSONL + setRawJsonlOutput((prev) => [...prev, event.payload]); + + // Parse and display + const message = JSON.parse(event.payload) as ClaudeStreamMessage; + setMessages((prev) => [...prev, message]); + } catch (err) { + console.error( + "[AgentRunOutputViewer] Failed to parse message:", + err, + event.payload, + ); + } + }, + ); + + const errorUnlisten = await listen( + `agent-error:${run!.id}`, + (event) => { + console.error("[AgentRunOutputViewer] Agent error:", event.payload); + setToast({ message: event.payload, type: "error" }); + }, + ); + + const completeUnlisten = await listen( + `agent-complete:${run!.id}`, + () => { + setToast({ message: "Agent execution completed", type: "success" }); + // Don't set status here as the parent component should handle it + }, + ); + + const cancelUnlisten = await listen( + `agent-cancelled:${run!.id}`, + () => { + setToast({ message: "Agent execution was cancelled", type: "error" }); + }, + ); + + unlistenRefs.current = [ + outputUnlisten, + errorUnlisten, + completeUnlisten, + cancelUnlisten, + ]; } catch (error) { - console.error('[AgentRunOutputViewer] Failed to set up live event listeners:', error); + console.error( + "[AgentRunOutputViewer] Failed to set up live event listeners:", + error, + ); } }; // Copy functionality const handleCopyAsJsonl = async () => { - const jsonl = rawJsonlOutput.join('\n'); + const jsonl = rawJsonlOutput.join("\n"); await navigator.clipboard.writeText(jsonl); setCopyPopoverOpen(false); - setToast({ message: 'Output copied as JSONL', type: 'success' }); + setToast({ message: "Output copied as JSONL", type: "success" }); }; const handleCopyAsMarkdown = async () => { if (!run) return; let markdown = `# Agent Execution: ${run.agent_name}\n\n`; markdown += `**Task:** ${run.task}\n`; - markdown += `**Model:** ${run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'}\n`; + markdown += `**Model:** ${run.model === "opus" ? "Claude 4 Opus" : "Claude 4 Sonnet"}\n`; markdown += `**Date:** ${formatISOTimestamp(run.created_at)}\n`; - if (run.metrics?.duration_ms) markdown += `**Duration:** ${(run.metrics.duration_ms / 1000).toFixed(2)}s\n`; - if (run.metrics?.total_tokens) markdown += `**Total Tokens:** ${run.metrics.total_tokens}\n`; - if (run.metrics?.cost_usd) markdown += `**Cost:** $${run.metrics.cost_usd.toFixed(4)} USD\n`; + if (run.metrics?.duration_ms) + markdown += `**Duration:** ${(run.metrics.duration_ms / 1000).toFixed(2)}s\n`; + if (run.metrics?.total_tokens) + markdown += `**Total Tokens:** ${run.metrics.total_tokens}\n`; + if (run.metrics?.cost_usd) + markdown += `**Cost:** $${run.metrics.cost_usd.toFixed(4)} USD\n`; markdown += `\n---\n\n`; for (const msg of messages) { if (msg.type === "system" && msg.subtype === "init") { markdown += `## System Initialization\n\n`; - markdown += `- Session ID: \`${msg.session_id || 'N/A'}\`\n`; - markdown += `- Model: \`${msg.model || 'default'}\`\n`; + markdown += `- Session ID: \`${msg.session_id || "N/A"}\`\n`; + markdown += `- Model: \`${msg.model || "default"}\`\n`; if (msg.cwd) markdown += `- Working Directory: \`${msg.cwd}\`\n`; - if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(', ')}\n`; + if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(", ")}\n`; markdown += `\n`; } else if (msg.type === "assistant" && msg.message) { markdown += `## Assistant\n\n`; @@ -381,7 +469,7 @@ export function AgentRunOutputViewer({ await navigator.clipboard.writeText(markdown); setCopyPopoverOpen(false); - setToast({ message: 'Output copied as Markdown', type: 'success' }); + setToast({ message: "Output copied as Markdown", type: "success" }); }; const handleRefresh = async () => { @@ -392,23 +480,25 @@ export function AgentRunOutputViewer({ const handleStop = async () => { if (!run?.id) { - console.error('[AgentRunOutputViewer] No run ID available to stop'); + console.error("[AgentRunOutputViewer] No run ID available to stop"); return; } try { // Call the API to kill the agent session const success = await api.killAgentSession(run.id); - + if (success) { - console.log(`[AgentRunOutputViewer] Successfully stopped agent session ${run.id}`); - setToast({ message: 'Agent execution stopped', type: 'success' }); - + console.log( + `[AgentRunOutputViewer] Successfully stopped agent session ${run.id}`, + ); + setToast({ message: "Agent execution stopped", type: "success" }); + // Clean up listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; hasSetupListenersRef.current = false; - + // Add a message indicating execution was stopped const stopMessage: ClaudeStreamMessage = { type: "result", @@ -418,25 +508,30 @@ export function AgentRunOutputViewer({ duration_ms: 0, usage: { input_tokens: 0, - output_tokens: 0 - } + output_tokens: 0, + }, }; - setMessages(prev => [...prev, stopMessage]); - + setMessages((prev) => [...prev, stopMessage]); + // Update the tab status - updateTabStatus(tabId, 'idle'); - + updateTabStatus(tabId, "idle"); + // Refresh the output to get updated status await loadOutput(true); } else { - console.warn(`[AgentRunOutputViewer] Failed to stop agent session ${run.id} - it may have already finished`); - setToast({ message: 'Failed to stop agent - it may have already finished', type: 'error' }); + console.warn( + `[AgentRunOutputViewer] Failed to stop agent session ${run.id} - it may have already finished`, + ); + setToast({ + message: "Failed to stop agent - it may have already finished", + type: "error", + }); } } catch (err) { - console.error('[AgentRunOutputViewer] Failed to stop agent:', err); - setToast({ - message: `Failed to stop execution: ${err instanceof Error ? err.message : 'Unknown error'}`, - type: 'error' + console.error("[AgentRunOutputViewer] Failed to stop agent:", err); + setToast({ + message: `Failed to stop execution: ${err instanceof Error ? err.message : "Unknown error"}`, + type: "error", }); } }; @@ -451,15 +546,17 @@ export function AgentRunOutputViewer({ // Load output on mount useEffect(() => { if (!run?.id) return; - + // Check cache immediately for instant display const cached = getCachedOutput(run!.id); if (cached) { - const cachedJsonlLines = cached.output.split('\n').filter(line => line.trim()); + const cachedJsonlLines = cached.output + .split("\n") + .filter((line) => line.trim()); setRawJsonlOutput(cachedJsonlLines); setMessages(cached.messages); } - + // Then load fresh data loadOutput(); }, [run?.id]); @@ -472,12 +569,19 @@ export function AgentRunOutputViewer({ if (message.isMeta) return false; const msg = message.message; - if (!msg.content || (Array.isArray(msg.content) && msg.content.length === 0)) return false; + if ( + !msg.content || + (Array.isArray(msg.content) && msg.content.length === 0) + ) + return false; if (Array.isArray(msg.content)) { let hasVisibleContent = false; for (const content of msg.content) { - if (content.type === "text") { hasVisibleContent = true; break; } + if (content.type === "text") { + hasVisibleContent = true; + break; + } if (content.type === "tool_result") { // Check if this tool result will be displayed as a widget let willBeSkipped = false; @@ -485,12 +589,33 @@ export function AgentRunOutputViewer({ // Find the corresponding tool use for (let i = messages.indexOf(message) - 1; i >= 0; i--) { const prevMsg = messages[i]; - if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) { - const toolUse = prevMsg.message.content.find((c: any) => c.type === 'tool_use' && c.id === content.tool_use_id); + if ( + prevMsg.type === "assistant" && + prevMsg.message?.content && + Array.isArray(prevMsg.message.content) + ) { + const toolUse = prevMsg.message.content.find( + (c: any) => + c.type === "tool_use" && c.id === content.tool_use_id, + ); if (toolUse) { const toolName = toolUse.name?.toLowerCase(); - const toolsWithWidgets = ['task','edit','multiedit','todowrite','ls','read','glob','bash','write','grep']; - if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) { + const toolsWithWidgets = [ + "task", + "edit", + "multiedit", + "todowrite", + "ls", + "read", + "glob", + "bash", + "write", + "grep", + ]; + if ( + toolsWithWidgets.includes(toolName) || + toolUse.name?.startsWith("mcp__") + ) { willBeSkipped = true; } break; @@ -498,7 +623,10 @@ export function AgentRunOutputViewer({ } } } - if (!willBeSkipped) { hasVisibleContent = true; break; } + if (!willBeSkipped) { + hasVisibleContent = true; + break; + } } } if (!hasVisibleContent) return false; @@ -543,21 +671,21 @@ export function AgentRunOutputViewer({ return ( <> -
+
- -
+ +
-
- {renderIcon(run.agent_icon)} -
+
{renderIcon(run.agent_icon)}
{run.agent_name} - {run.status === 'running' && ( + {run.status === "running" && (
- Running + + Running +
)}
@@ -566,7 +694,9 @@ export function AgentRunOutputViewer({

- {run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'} + {run.model === "opus" + ? "Claude 4 Opus" + : "Claude 4 Sonnet"}
@@ -593,11 +723,7 @@ export function AgentRunOutputViewer({
+ - {run.status === 'running' && ( + {run.status === "running" && (
-
- - - {loading ? ( +
+ + + {loading ? (
@@ -678,29 +808,34 @@ export function AgentRunOutputViewer({

No output available yet

) : ( -
- {displayableMessages.map((message: ClaudeStreamMessage, index: number) => ( - - - - - - ))} + {displayableMessages.map( + (message: ClaudeStreamMessage, index: number) => ( + + + + + + ), + )}
- )} - + )} +
@@ -718,10 +853,7 @@ export function AgentRunOutputViewer({
+ - {run.status === 'running' && ( + {run.status === "running" && (
-
- {displayableMessages.map((message: ClaudeStreamMessage, index: number) => ( - - - - - - ))} + {displayableMessages.map( + (message: ClaudeStreamMessage, index: number) => ( + + + + + + ), + )}
@@ -826,4 +965,4 @@ export function AgentRunOutputViewer({ ); } -export default AgentRunOutputViewer; \ No newline at end of file +export default AgentRunOutputViewer; diff --git a/src/components/AgentRunView.tsx b/src/components/AgentRunView.tsx index 16ade6c51..f83d7e892 100644 --- a/src/components/AgentRunView.tsx +++ b/src/components/AgentRunView.tsx @@ -1,14 +1,14 @@ import React, { useState, useEffect } from "react"; import { motion } from "framer-motion"; -import { - ArrowLeft, - Copy, - ChevronDown, +import { + ArrowLeft, + Copy, + ChevronDown, Clock, Hash, DollarSign, Bot, - StopCircle + StopCircle, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; @@ -39,7 +39,7 @@ interface AgentRunViewProps { /** * AgentRunView component for viewing past agent execution details - * + * * @example * setView('list')} /> */ @@ -64,30 +64,35 @@ export const AgentRunView: React.FC = ({ setError(null); const runData = await api.getAgentRunWithRealTimeMetrics(runId); setRun(runData); - + // If we have a session_id, try to load from JSONL file first - if (runData.session_id && runData.session_id !== '') { + if (runData.session_id && runData.session_id !== "") { try { const history = await api.loadAgentSessionHistory(runData.session_id); - + // Convert history to messages format - const loadedMessages: ClaudeStreamMessage[] = history.map(entry => ({ - ...entry, - type: entry.type || "assistant" - })); - + const loadedMessages: ClaudeStreamMessage[] = history.map( + (entry) => ({ + ...entry, + type: entry.type || "assistant", + }), + ); + setMessages(loadedMessages); return; } catch (err) { - console.warn('Failed to load from JSONL, falling back to output field:', err); + console.warn( + "Failed to load from JSONL, falling back to output field:", + err, + ); } } - + // Fallback: Parse JSONL output from the output field if (runData.output) { const parsedMessages: ClaudeStreamMessage[] = []; - const lines = runData.output.split('\n').filter(line => line.trim()); - + const lines = runData.output.split("\n").filter((line) => line.trim()); + for (const line of lines) { try { const msg = JSON.parse(line) as ClaudeStreamMessage; @@ -96,7 +101,7 @@ export const AgentRunView: React.FC = ({ console.error("Failed to parse line:", line, err); } } - + setMessages(parsedMessages); } } catch (err) { @@ -115,14 +120,14 @@ export const AgentRunView: React.FC = ({ const handleCopyAsMarkdown = async () => { if (!run) return; - + let markdown = `# Agent Run: ${run.agent_name}\n\n`; markdown += `**Task:** ${run.task}\n`; markdown += `**Model:** ${run.model}\n`; markdown += `**Status:** ${run.status}\n`; if (run.metrics) { - markdown += `**Tokens:** ${run.metrics.total_tokens || 'N/A'}\n`; - markdown += `**Cost:** $${run.metrics.cost_usd?.toFixed(4) || 'N/A'}\n`; + markdown += `**Tokens:** ${run.metrics.total_tokens || "N/A"}\n`; + markdown += `**Cost:** $${run.metrics.cost_usd?.toFixed(4) || "N/A"}\n`; } markdown += `**Date:** ${new Date(run.created_at).toISOString()}\n\n`; markdown += `---\n\n`; @@ -130,10 +135,10 @@ export const AgentRunView: React.FC = ({ for (const msg of messages) { if (msg.type === "system" && msg.subtype === "init") { markdown += `## System Initialization\n\n`; - markdown += `- Session ID: \`${msg.session_id || 'N/A'}\`\n`; - markdown += `- Model: \`${msg.model || 'default'}\`\n`; + markdown += `- Session ID: \`${msg.session_id || "N/A"}\`\n`; + markdown += `- Model: \`${msg.model || "default"}\`\n`; if (msg.cwd) markdown += `- Working Directory: \`${msg.cwd}\`\n`; - if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(', ')}\n`; + if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(", ")}\n`; markdown += `\n`; } else if (msg.type === "assistant" && msg.message) { markdown += `## Assistant\n\n`; @@ -175,22 +180,24 @@ export const AgentRunView: React.FC = ({ const handleStop = async () => { if (!runId) { - console.error('[AgentRunView] No run ID available to stop'); + console.error("[AgentRunView] No run ID available to stop"); return; } try { // Call the API to kill the agent session const success = await api.killAgentSession(runId); - + if (success) { - console.log(`[AgentRunView] Successfully stopped agent session ${runId}`); - + console.log( + `[AgentRunView] Successfully stopped agent session ${runId}`, + ); + // Update the run status locally if (run) { - setRun({ ...run, status: 'cancelled' }); + setRun({ ...run, status: "cancelled" }); } - + // Add a message indicating execution was stopped const stopMessage: ClaudeStreamMessage = { type: "result", @@ -200,20 +207,22 @@ export const AgentRunView: React.FC = ({ duration_ms: 0, usage: { input_tokens: 0, - output_tokens: 0 - } + output_tokens: 0, + }, }; - setMessages(prev => [...prev, stopMessage]); - + setMessages((prev) => [...prev, stopMessage]); + // Reload the run data after a short delay setTimeout(() => { loadRun(); }, 1000); } else { - console.warn(`[AgentRunView] Failed to stop agent session ${runId} - it may have already finished`); + console.warn( + `[AgentRunView] Failed to stop agent session ${runId} - it may have already finished`, + ); } } catch (err) { - console.error('[AgentRunView] Failed to stop agent:', err); + console.error("[AgentRunView] Failed to stop agent:", err); } }; @@ -232,7 +241,12 @@ export const AgentRunView: React.FC = ({ if (error || !run) { return ( -
+

{error || "Run not found"}

@@ -262,13 +276,15 @@ export const AgentRunView: React.FC = ({ {renderIcon(run.agent_icon)}

{run.agent_name}

-

Execution History

+

+ Execution History +

- +
- {run?.status === 'running' && ( + {run?.status === "running" && ( )} - + = ({ />
- + {/* Run Details */}

Task:

-

{run.task}

+

+ {run.task} +

- {run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'} + {run.model === "opus" ? "Claude 4 Opus" : "Claude 4 Sonnet"}
- +
{formatISOTimestamp(run.created_at)}
- + {run.metrics?.duration_ms && (
{(run.metrics.duration_ms / 1000).toFixed(2)}s
)} - + {run.metrics?.total_tokens && (
{run.metrics.total_tokens} tokens
)} - + {run.metrics?.cost_usd && (
@@ -382,4 +400,4 @@ export const AgentRunView: React.FC = ({
); -}; \ No newline at end of file +}; diff --git a/src/components/AgentRunsList.tsx b/src/components/AgentRunsList.tsx index deb403c37..3ccd9e2f1 100644 --- a/src/components/AgentRunsList.tsx +++ b/src/components/AgentRunsList.tsx @@ -29,7 +29,7 @@ const ITEMS_PER_PAGE = 5; /** * AgentRunsList component - Displays a paginated list of agent execution runs - * + * * @example * = ({ }) => { const [currentPage, setCurrentPage] = useState(1); const { createAgentTab } = useTabState(); - + // Calculate pagination const totalPages = Math.ceil(runs.length / ITEMS_PER_PAGE); const startIndex = (currentPage - 1) * ITEMS_PER_PAGE; const endIndex = startIndex + ITEMS_PER_PAGE; const currentRuns = runs.slice(startIndex, endIndex); - + // Reset to page 1 if runs change React.useEffect(() => { setCurrentPage(1); }, [runs.length]); - + const renderIcon = (iconName: string) => { const Icon = AGENT_ICONS[iconName as keyof typeof AGENT_ICONS] || Bot; return ; }; - + const formatDuration = (ms?: number) => { if (!ms) return "N/A"; const seconds = Math.floor(ms / 1000); @@ -68,7 +68,7 @@ export const AgentRunsList: React.FC = ({ const remainingSeconds = seconds % 60; return `${minutes}m ${remainingSeconds}s`; }; - + const formatTokens = (tokens?: number) => { if (!tokens) return "0"; if (tokens >= 1000) { @@ -76,7 +76,7 @@ export const AgentRunsList: React.FC = ({ } return tokens.toString(); }; - + const handleRunClick = (run: AgentRunWithMetrics) => { // If there's a callback, use it (for full-page navigation) if (onRunClick) { @@ -86,7 +86,7 @@ export const AgentRunsList: React.FC = ({ createAgentTab(run.id.toString(), run.agent_name); } }; - + if (runs.length === 0) { return (
@@ -115,7 +115,7 @@ export const AgentRunsList: React.FC = ({ handleRunClick(run)} > @@ -124,7 +124,7 @@ export const AgentRunsList: React.FC = ({
{renderIcon(run.agent_icon)}
- +

@@ -133,48 +133,58 @@ export const AgentRunsList: React.FC = ({ {run.status === "running" && (
- Running + + Running +
)}

- +

{run.task}

- +
{formatISOTimestamp(run.created_at)}
- + {run.metrics?.duration_ms && ( {formatDuration(run.metrics.duration_ms)} )} - + {run.metrics?.total_tokens && (
- {formatTokens(run.metrics.total_tokens)} + + {formatTokens(run.metrics.total_tokens)} +
)}
- +
- - {run.status === "completed" ? "Completed" : - run.status === "running" ? "Running" : - run.status === "failed" ? "Failed" : - "Pending"} + {run.status === "completed" + ? "Completed" + : run.status === "running" + ? "Running" + : run.status === "failed" + ? "Failed" + : "Pending"}
@@ -183,7 +193,7 @@ export const AgentRunsList: React.FC = ({ ))} - + {/* Pagination */} {totalPages > 1 && (
@@ -195,7 +205,6 @@ export const AgentRunsList: React.FC = ({
)}
- ); -}; \ No newline at end of file +}; diff --git a/src/components/Agents.tsx b/src/components/Agents.tsx index 709afd2be..b2783edc1 100644 --- a/src/components/Agents.tsx +++ b/src/components/Agents.tsx @@ -1,33 +1,52 @@ -import React, { useState, useEffect } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { Bot, Loader2, Play, Clock, CheckCircle, XCircle, Trash2, Import, ChevronDown, ChevronRight, FileJson, Globe, Download, Plus, History } from 'lucide-react'; +import React, { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + Bot, + Loader2, + Play, + Clock, + CheckCircle, + XCircle, + Trash2, + Import, + ChevronDown, + ChevronRight, + FileJson, + Globe, + Download, + Plus, + History, +} from "lucide-react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; -import { Card } from '@/components/ui/card'; -import { Toast } from '@/components/ui/toast'; -import { api, type Agent, type AgentRunWithMetrics } from '@/lib/api'; -import { open as openDialog, save } from '@tauri-apps/plugin-dialog'; -import { invoke } from '@tauri-apps/api/core'; -import { GitHubAgentBrowser } from '@/components/GitHubAgentBrowser'; -import { CreateAgent } from '@/components/CreateAgent'; -import { useTabState } from '@/hooks/useTabState'; +} from "@/components/ui/dropdown-menu"; +import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { Card } from "@/components/ui/card"; +import { Toast } from "@/components/ui/toast"; +import { api, type Agent, type AgentRunWithMetrics } from "@/lib/api"; +import { open as openDialog, save } from "@tauri-apps/plugin-dialog"; +import { invoke } from "@tauri-apps/api/core"; +import { GitHubAgentBrowser } from "@/components/GitHubAgentBrowser"; +import { CreateAgent } from "@/components/CreateAgent"; +import { useTabState } from "@/hooks/useTabState"; export const Agents: React.FC = () => { - const [activeTab, setActiveTab] = useState('agents'); + const [activeTab, setActiveTab] = useState("agents"); const [showCreateAgent, setShowCreateAgent] = useState(false); const [agents, setAgents] = useState([]); const [runningAgents, setRunningAgents] = useState([]); const [loading, setLoading] = useState(true); const [agentToDelete, setAgentToDelete] = useState(null); const [showDeleteDialog, setShowDeleteDialog] = useState(false); - const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null); + const [toast, setToast] = useState<{ + message: string; + type: "success" | "error"; + } | null>(null); const [showGitHubBrowser, setShowGitHubBrowser] = useState(false); const { createAgentTab } = useTabState(); @@ -52,8 +71,8 @@ export const Agents: React.FC = () => { const agents = await api.listAgents(); setAgents(agents); } catch (error) { - console.error('Failed to load agents:', error); - setToast({ message: 'Failed to load agents', type: 'error' }); + console.error("Failed to load agents:", error); + setToast({ message: "Failed to load agents", type: "error" }); } finally { setLoading(false); } @@ -64,57 +83,68 @@ export const Agents: React.FC = () => { const runs = await api.listAgentRunsWithMetrics(); setRunningAgents(runs); } catch (error) { - console.error('Failed to load running agents:', error); + console.error("Failed to load running agents:", error); } }; const handleRunAgent = async (agent: Agent) => { if (!agent.id) { - setToast({ message: 'Agent ID is missing', type: 'error' }); + setToast({ message: "Agent ID is missing", type: "error" }); return; } - + // Import the dialog function - const { open } = await import('@tauri-apps/plugin-dialog'); - + const { open } = await import("@tauri-apps/plugin-dialog"); + try { // Prompt user to select a project directory const projectPath = await open({ directory: true, multiple: false, - title: `Select project directory for ${agent.name}` + title: `Select project directory for ${agent.name}`, }); - + if (!projectPath) { // User cancelled return; } - + // Dispatch event to open agent execution in a new tab const tabId = `agent-exec-${agent.id}-${Date.now()}`; - window.dispatchEvent(new CustomEvent('open-agent-execution', { - detail: { agent, tabId, projectPath } - })); - - setToast({ message: `Opening agent: ${agent.name}`, type: 'success' }); + window.dispatchEvent( + new CustomEvent("open-agent-execution", { + detail: { agent, tabId, projectPath }, + }), + ); + + setToast({ message: `Opening agent: ${agent.name}`, type: "success" }); } catch (error) { - console.error('Failed to open agent:', error); - setToast({ message: `Failed to open agent: ${agent.name}`, type: 'error' }); + console.error("Failed to open agent:", error); + setToast({ + message: `Failed to open agent: ${agent.name}`, + type: "error", + }); } }; const handleDeleteAgent = async () => { if (!agentToDelete || !agentToDelete.id) return; - + try { await api.deleteAgent(agentToDelete.id); - setToast({ message: `Deleted agent: ${agentToDelete.name}`, type: 'success' }); - setAgents(prev => prev.filter(a => a.id !== agentToDelete.id)); + setToast({ + message: `Deleted agent: ${agentToDelete.name}`, + type: "success", + }); + setAgents((prev) => prev.filter((a) => a.id !== agentToDelete.id)); setShowDeleteDialog(false); setAgentToDelete(null); } catch (error) { - console.error('Failed to delete agent:', error); - setToast({ message: `Failed to delete agent: ${agentToDelete.name}`, type: 'error' }); + console.error("Failed to delete agent:", error); + setToast({ + message: `Failed to delete agent: ${agentToDelete.name}`, + type: "error", + }); } }; @@ -122,23 +152,28 @@ export const Agents: React.FC = () => { try { const selected = await openDialog({ filters: [ - { name: 'JSON Files', extensions: ['json'] }, - { name: 'All Files', extensions: ['*'] } + { name: "JSON Files", extensions: ["json"] }, + { name: "All Files", extensions: ["*"] }, ], multiple: false, }); if (selected) { - const fileContent = await invoke('read_text_file', { path: selected }); + const fileContent = await invoke("read_text_file", { + path: selected, + }); const agentData = JSON.parse(fileContent); - + const importedAgent = await api.importAgent(JSON.stringify(agentData)); - setToast({ message: `Imported agent: ${importedAgent.name}`, type: 'success' }); + setToast({ + message: `Imported agent: ${importedAgent.name}`, + type: "success", + }); loadAgents(); } } catch (error) { - console.error('Failed to import agent:', error); - setToast({ message: 'Failed to import agent', type: 'error' }); + console.error("Failed to import agent:", error); + setToast({ message: "Failed to import agent", type: "error" }); } }; @@ -146,32 +181,30 @@ export const Agents: React.FC = () => { try { const path = await save({ defaultPath: `${agent.name}.json`, - filters: [ - { name: 'JSON Files', extensions: ['json'] } - ] + filters: [{ name: "JSON Files", extensions: ["json"] }], }); if (path && agent.id) { const agentData = await api.exportAgent(agent.id); - await invoke('write_text_file', { + await invoke("write_text_file", { path, - contents: agentData + contents: agentData, }); - setToast({ message: `Exported agent: ${agent.name}`, type: 'success' }); + setToast({ message: `Exported agent: ${agent.name}`, type: "success" }); } } catch (error) { - console.error('Failed to export agent:', error); - setToast({ message: 'Failed to export agent', type: 'error' }); + console.error("Failed to export agent:", error); + setToast({ message: "Failed to export agent", type: "error" }); } }; const getStatusIcon = (status: string) => { switch (status) { - case 'running': + case "running": return ; - case 'completed': + case "completed": return ; - case 'failed': + case "failed": return ; default: return ; @@ -181,7 +214,7 @@ export const Agents: React.FC = () => { // Show CreateAgent component if creating if (showCreateAgent) { return ( - setShowCreateAgent(false)} onAgentCreated={() => { setShowCreateAgent(false); @@ -241,8 +274,8 @@ export const Agents: React.FC = () => { exit={{ opacity: 0, y: -10 }} className="mx-6 mb-4" > - setToast(null)} /> @@ -250,60 +283,65 @@ export const Agents: React.FC = () => { )} - {showGitHubBrowser && ( - setShowGitHubBrowser(false)} - onImportSuccess={() => { - loadAgents(); - setShowGitHubBrowser(false); - setToast({ message: 'Agent imported successfully', type: 'success' }); - }} - /> - )} - - - {showDeleteDialog && agentToDelete && ( - setShowDeleteDialog(false)} - > + {showGitHubBrowser && ( + setShowGitHubBrowser(false)} + onImportSuccess={() => { + loadAgents(); + setShowGitHubBrowser(false); + setToast({ + message: "Agent imported successfully", + type: "success", + }); + }} + /> + )} + + + {showDeleteDialog && agentToDelete && ( e.stopPropagation()} + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + exit={{ opacity: 0 }} + className="fixed inset-0 bg-background/80 backdrop-blur-sm z-50 flex items-center justify-center" + onClick={() => setShowDeleteDialog(false)} > -

Delete Agent

-

- Are you sure you want to delete "{agentToDelete.name}"? This action cannot be undone. -

-
- - -
+ e.stopPropagation()} + > +

Delete Agent

+

+ Are you sure you want to delete "{agentToDelete.name}"? This + action cannot be undone. +

+
+ + +
+
-
- )} -
+ )} + {/* Content */}
- + @@ -315,7 +353,7 @@ export const Agents: React.FC = () => { - + {loading ? (
@@ -346,20 +384,28 @@ export const Agents: React.FC = () => {
- - handleRunAgent(agent)}> + handleRunAgent(agent)} + > Run - handleExportAgent(agent)}> + handleExportAgent(agent)} + > Export - { setAgentToDelete(agent); setShowDeleteDialog(true); @@ -381,10 +427,7 @@ export const Agents: React.FC = () => { v1.0.0 - @@ -400,7 +443,9 @@ export const Agents: React.FC = () => {
-

No Agent History

+

+ No Agent History +

Run an agent to see it here

@@ -409,10 +454,7 @@ export const Agents: React.FC = () => { ) : (
{runningAgents.map((run) => ( - +
{getStatusIcon(run.status)} @@ -424,7 +466,12 @@ export const Agents: React.FC = () => {
); -}; \ No newline at end of file +}; diff --git a/src/components/AgentsModal.tsx b/src/components/AgentsModal.tsx index f5eb4063c..096db1add 100644 --- a/src/components/AgentsModal.tsx +++ b/src/components/AgentsModal.tsx @@ -1,44 +1,64 @@ -import React, { useState, useEffect } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { Bot, Plus, Loader2, Play, Clock, CheckCircle, XCircle, Trash2, Import, ChevronDown, FileJson, Globe, Download } from 'lucide-react'; +import React, { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { + Bot, + Plus, + Loader2, + Play, + Clock, + CheckCircle, + XCircle, + Trash2, + Import, + ChevronDown, + FileJson, + Globe, + Download, +} from "lucide-react"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, -} from '@/components/ui/dialog'; +} from "@/components/ui/dialog"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, -} from '@/components/ui/dropdown-menu'; -import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'; -import { Button } from '@/components/ui/button'; -import { Badge } from '@/components/ui/badge'; -import { ScrollArea } from '@/components/ui/scroll-area'; -import { Toast } from '@/components/ui/toast'; -import { api, type Agent, type AgentRunWithMetrics } from '@/lib/api'; -import { useTabState } from '@/hooks/useTabState'; -import { formatISOTimestamp } from '@/lib/date-utils'; -import { open as openDialog, save } from '@tauri-apps/plugin-dialog'; -import { invoke } from '@tauri-apps/api/core'; -import { GitHubAgentBrowser } from '@/components/GitHubAgentBrowser'; +} from "@/components/ui/dropdown-menu"; +import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Toast } from "@/components/ui/toast"; +import { api, type Agent, type AgentRunWithMetrics } from "@/lib/api"; +import { useTabState } from "@/hooks/useTabState"; +import { formatISOTimestamp } from "@/lib/date-utils"; +import { open as openDialog, save } from "@tauri-apps/plugin-dialog"; +import { invoke } from "@tauri-apps/api/core"; +import { GitHubAgentBrowser } from "@/components/GitHubAgentBrowser"; interface AgentsModalProps { open: boolean; onOpenChange: (open: boolean) => void; } -export const AgentsModal: React.FC = ({ open, onOpenChange }) => { - const [activeTab, setActiveTab] = useState('agents'); +export const AgentsModal: React.FC = ({ + open, + onOpenChange, +}) => { + const [activeTab, setActiveTab] = useState("agents"); const [agents, setAgents] = useState([]); const [runningAgents, setRunningAgents] = useState([]); const [loading, setLoading] = useState(true); const [agentToDelete, setAgentToDelete] = useState(null); const [showDeleteDialog, setShowDeleteDialog] = useState(false); - const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null); + const [toast, setToast] = useState<{ + message: string; + type: "success" | "error"; + } | null>(null); const [showGitHubBrowser, setShowGitHubBrowser] = useState(false); const { createAgentTab, createCreateAgentTab } = useTabState(); @@ -53,7 +73,7 @@ export const AgentsModal: React.FC = ({ open, onOpenChange }) // Refresh running agents periodically useEffect(() => { if (!open) return; - + const interval = setInterval(() => { loadRunningAgents(); }, 3000); // Refresh every 3 seconds @@ -67,7 +87,7 @@ export const AgentsModal: React.FC = ({ open, onOpenChange }) const agentList = await api.listAgents(); setAgents(agentList); } catch (error) { - console.error('Failed to load agents:', error); + console.error("Failed to load agents:", error); } finally { setLoading(false); } @@ -76,52 +96,60 @@ export const AgentsModal: React.FC = ({ open, onOpenChange }) const loadRunningAgents = async () => { try { const runs = await api.listRunningAgentSessions(); - const agentRuns = runs.map(run => ({ - id: run.id, - agent_id: run.agent_id, - agent_name: run.agent_name, - task: run.task, - model: run.model, - status: 'running' as const, - created_at: run.created_at, - project_path: run.project_path, - } as AgentRunWithMetrics)); - + const agentRuns = runs.map( + (run) => + ({ + id: run.id, + agent_id: run.agent_id, + agent_name: run.agent_name, + task: run.task, + model: run.model, + status: "running" as const, + created_at: run.created_at, + project_path: run.project_path, + }) as AgentRunWithMetrics, + ); + setRunningAgents(agentRuns); } catch (error) { - console.error('Failed to load running agents:', error); + console.error("Failed to load running agents:", error); } }; const handleRunAgent = async (agent: Agent) => { // Open directory picker for project path - const { open } = await import('@tauri-apps/plugin-dialog'); - + const { open } = await import("@tauri-apps/plugin-dialog"); + try { const projectPath = await open({ directory: true, multiple: false, - title: `Select project directory for ${agent.name}` + title: `Select project directory for ${agent.name}`, }); - + if (!projectPath) { // User cancelled return; } - + // Create a new agent execution tab const tabId = `agent-exec-${agent.id}-${Date.now()}`; - + // Close modal onOpenChange(false); - + // Dispatch event to open agent execution in the new tab with project path - window.dispatchEvent(new CustomEvent('open-agent-execution', { - detail: { agent, tabId, projectPath } - })); + window.dispatchEvent( + new CustomEvent("open-agent-execution", { + detail: { agent, tabId, projectPath }, + }), + ); } catch (error) { - console.error('Failed to run agent:', error); - setToast({ message: `Failed to run agent: ${agent.name}`, type: 'error' }); + console.error("Failed to run agent:", error); + setToast({ + message: `Failed to run agent: ${agent.name}`, + type: "error", + }); } }; @@ -138,7 +166,7 @@ export const AgentsModal: React.FC = ({ open, onOpenChange }) setShowDeleteDialog(false); setAgentToDelete(null); } catch (error) { - console.error('Failed to delete agent:', error); + console.error("Failed to delete agent:", error); } }; @@ -158,19 +186,24 @@ export const AgentsModal: React.FC = ({ open, onOpenChange }) try { const filePath = await openDialog({ multiple: false, - filters: [{ - name: 'JSON', - extensions: ['json'] - }] + filters: [ + { + name: "JSON", + extensions: ["json"], + }, + ], }); - + if (filePath) { const agent = await api.importAgentFromFile(filePath as string); loadAgents(); // Refresh list - setToast({ message: `Agent "${agent.name}" imported successfully`, type: "success" }); + setToast({ + message: `Agent "${agent.name}" imported successfully`, + type: "success", + }); } } catch (error) { - console.error('Failed to import agent:', error); + console.error("Failed to import agent:", error); setToast({ message: "Failed to import agent", type: "error" }); } }; @@ -183,30 +216,35 @@ export const AgentsModal: React.FC = ({ open, onOpenChange }) try { const exportData = await api.exportAgent(agent.id!); const filePath = await save({ - defaultPath: `${agent.name.toLowerCase().replace(/\s+/g, '-')}.json`, - filters: [{ - name: 'JSON', - extensions: ['json'] - }] + defaultPath: `${agent.name.toLowerCase().replace(/\s+/g, "-")}.json`, + filters: [ + { + name: "JSON", + extensions: ["json"], + }, + ], }); - + if (filePath) { - await invoke('write_file', { path: filePath, content: JSON.stringify(exportData, null, 2) }); + await invoke("write_file", { + path: filePath, + content: JSON.stringify(exportData, null, 2), + }); setToast({ message: "Agent exported successfully", type: "success" }); } } catch (error) { - console.error('Failed to export agent:', error); + console.error("Failed to export agent:", error); setToast({ message: "Failed to export agent", type: "error" }); } }; const getStatusIcon = (status: string) => { switch (status) { - case 'running': + case "running": return ; - case 'completed': + case "completed": return ; - case 'failed': + case "failed": return ; default: return ; @@ -216,245 +254,260 @@ export const AgentsModal: React.FC = ({ open, onOpenChange }) return ( <> - - - - - Agent Management - - - Create new agents or manage running agent executions - - - - - - Available Agents - - Running Agents - {runningAgents.length > 0 && ( - - {runningAgents.length} - - )} - - - -
- - - {/* Action buttons at the top */} -
- - - - - - - - - From File - - - - From GitHub - - - -
- {loading ? ( -
- -
- ) : agents.length === 0 ? ( -
- -

No agents available

-

- Create your first agent to get started -

- + + + + + + + + From File + + + + From GitHub + + +
- ) : ( -
- {agents.map((agent) => ( - + +
+ ) : agents.length === 0 ? ( +
+ +

+ No agents available +

+

+ Create your first agent to get started +

+ - - -
-
- - ))} -
- )} - - - - - - {runningAgents.length === 0 ? ( -
- -

No running agents

-

- Agent executions will appear here when started -

-
- ) : ( -
- - {runningAgents.map((run) => ( + + Create Agent + +
+ ) : ( +
+ {agents.map((agent) => ( handleOpenAgentRun(run)} + key={agent.id} + initial={{ opacity: 0, y: 10 }} + animate={{ opacity: 1, y: 0 }} + className="p-4 border rounded-lg hover:bg-muted/50 transition-colors" >

- {getStatusIcon(run.status)} - {run.agent_name} + + {agent.name}

-

- {run.task} -

-
- Started: {formatISOTimestamp(run.created_at)} - - {run.model === 'opus' ? 'Claude 4 Opus' : 'Claude 4 Sonnet'} - -
+ {agent.default_task && ( +

+ {agent.default_task} +

+ )} +
+
+ + +
-
))} - -
- )} -
-
+
+ )} + +
+ + + + {runningAgents.length === 0 ? ( +
+ +

+ No running agents +

+

+ Agent executions will appear here when started +

+
+ ) : ( +
+ + {runningAgents.map((run) => ( + handleOpenAgentRun(run)} + > +
+
+

+ {getStatusIcon(run.status)} + {run.agent_name} +

+

+ {run.task} +

+
+ + Started:{" "} + {formatISOTimestamp(run.created_at)} + + + {run.model === "opus" + ? "Claude 4 Opus" + : "Claude 4 Sonnet"} + +
+
+ +
+
+ ))} +
+
+ )} +
+
+
+ + +
+ + {/* Delete Confirmation Dialog */} + + + + Delete Agent + + Are you sure you want to delete "{agentToDelete?.name}"? This + action cannot be undone. + + +
+ +
- -
-
- - {/* Delete Confirmation Dialog */} - - - - Delete Agent - - Are you sure you want to delete "{agentToDelete?.name}"? This action cannot be undone. - - -
- - -
-
-
- - {/* GitHub Agent Browser */} - setShowGitHubBrowser(false)} - onImportSuccess={() => { - setShowGitHubBrowser(false); - loadAgents(); // Refresh the agents list - setToast({ message: "Agent imported successfully", type: "success" }); - }} - /> - - {/* Toast notifications */} - {toast && ( - setToast(null)} + +
+ + {/* GitHub Agent Browser */} + setShowGitHubBrowser(false)} + onImportSuccess={() => { + setShowGitHubBrowser(false); + loadAgents(); // Refresh the agents list + setToast({ message: "Agent imported successfully", type: "success" }); + }} /> - )} + + {/* Toast notifications */} + {toast && ( + setToast(null)} + /> + )} ); }; -export default AgentsModal; \ No newline at end of file +export default AgentsModal; diff --git a/src/components/AnalyticsConsent.tsx b/src/components/AnalyticsConsent.tsx index dfd4c4cae..4f3683153 100644 --- a/src/components/AnalyticsConsent.tsx +++ b/src/components/AnalyticsConsent.tsx @@ -1,11 +1,17 @@ -import React, { useState, useEffect } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; -import { BarChart3, Shield, X, Check, Info } from 'lucide-react'; -import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from '@/components/ui/dialog'; -import { Button } from '@/components/ui/button'; -import { Card } from '@/components/ui/card'; -import { analytics } from '@/lib/analytics'; -import { cn } from '@/lib/utils'; +import React, { useState, useEffect } from "react"; +import { motion, AnimatePresence } from "framer-motion"; +import { BarChart3, Shield, X, Check, Info } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Card } from "@/components/ui/card"; +import { analytics } from "@/lib/analytics"; +import { cn } from "@/lib/utils"; interface AnalyticsConsentProps { open?: boolean; @@ -20,16 +26,16 @@ export const AnalyticsConsent: React.FC = ({ }) => { const [internalOpen, setInternalOpen] = useState(false); const [hasShownConsent, setHasShownConsent] = useState(false); - + const isControlled = controlledOpen !== undefined; const open = isControlled ? controlledOpen : internalOpen; - + useEffect(() => { // Check if we should show the consent dialog const checkConsent = async () => { await analytics.initialize(); const settings = analytics.getSettings(); - + if (!settings?.hasConsented && !hasShownConsent) { if (!isControlled) { setInternalOpen(true); @@ -37,10 +43,10 @@ export const AnalyticsConsent: React.FC = ({ setHasShownConsent(true); } }; - + checkConsent(); }, [isControlled, hasShownConsent]); - + const handleOpenChange = (newOpen: boolean) => { if (isControlled && onOpenChange) { onOpenChange(newOpen); @@ -48,19 +54,19 @@ export const AnalyticsConsent: React.FC = ({ setInternalOpen(newOpen); } }; - + const handleAccept = async () => { await analytics.enable(); handleOpenChange(false); onComplete?.(); }; - + const handleDecline = async () => { await analytics.disable(); handleOpenChange(false); onComplete?.(); }; - + return ( @@ -70,36 +76,45 @@ export const AnalyticsConsent: React.FC = ({
- Help Improve Claudia + + Help Improve Claudia +
- We'd like to collect anonymous usage data to improve your experience. + We'd like to collect anonymous usage data to improve your + experience.
- +
-

What we collect:

+

+ What we collect: +

  • • Feature usage (which tools and commands you use)
  • • Performance metrics (app speed and reliability)
  • • Error reports (to fix bugs and improve stability)
  • -
  • • General usage patterns (session frequency and duration)
  • +
  • + • General usage patterns (session frequency and duration) +
- +
-

Your privacy is protected:

+

+ Your privacy is protected: +

  • • No personal information is collected
  • • No file contents, paths, or project names
  • @@ -111,24 +126,21 @@ export const AnalyticsConsent: React.FC = ({
- +

- This data helps us understand which features are most valuable, identify performance - issues, and prioritize improvements. Your choice won't affect any functionality. + This data helps us understand which features are most valuable, + identify performance issues, and prioritize improvements. Your + choice won't affect any functionality.

- +
-
) : ( - + )}
)} @@ -530,7 +552,10 @@ export const CCAgents: React.FC = ({ onBack, className }) => { onImportSuccess={async () => { setShowGitHubBrowser(false); await loadAgents(); - setToast({ message: "Agent imported successfully from GitHub", type: "success" }); + setToast({ + message: "Agent imported successfully from GitHub", + type: "success", + }); }} /> @@ -543,8 +568,9 @@ export const CCAgents: React.FC = ({ onBack, className }) => { Delete Agent - Are you sure you want to delete the agent "{agentToDelete?.name}"? - This action cannot be undone and will permanently remove the agent and all its associated data. + Are you sure you want to delete the agent "{agentToDelete?.name}"? + This action cannot be undone and will permanently remove the agent + and all its associated data. diff --git a/src/components/CheckpointSettings.tsx b/src/components/CheckpointSettings.tsx index 4f2549836..3ddab0041 100644 --- a/src/components/CheckpointSettings.tsx +++ b/src/components/CheckpointSettings.tsx @@ -1,12 +1,12 @@ import React, { useState, useEffect } from "react"; import { motion } from "framer-motion"; -import { +import { Wrench, Save, Trash2, HardDrive, AlertCircle, - Loader2 + Loader2, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Label } from "@/components/ui/label"; @@ -27,9 +27,9 @@ interface CheckpointSettingsProps { /** * CheckpointSettings component for managing checkpoint configuration - * + * * @example - * = ({ className, }) => { const [autoCheckpointEnabled, setAutoCheckpointEnabled] = useState(true); - const [checkpointStrategy, setCheckpointStrategy] = useState("smart"); + const [checkpointStrategy, setCheckpointStrategy] = + useState("smart"); const [totalCheckpoints, setTotalCheckpoints] = useState(0); const [keepCount, setKeepCount] = useState(10); const [isLoading, setIsLoading] = useState(false); @@ -65,8 +66,12 @@ export const CheckpointSettings: React.FC = ({ try { setIsLoading(true); setError(null); - - const settings = await api.getCheckpointSettings(sessionId, projectId, projectPath); + + const settings = await api.getCheckpointSettings( + sessionId, + projectId, + projectPath, + ); setAutoCheckpointEnabled(settings.auto_checkpoint_enabled); setCheckpointStrategy(settings.checkpoint_strategy); setTotalCheckpoints(settings.total_checkpoints); @@ -83,15 +88,15 @@ export const CheckpointSettings: React.FC = ({ setIsSaving(true); setError(null); setSuccessMessage(null); - + await api.updateCheckpointSettings( sessionId, projectId, projectPath, autoCheckpointEnabled, - checkpointStrategy + checkpointStrategy, ); - + setSuccessMessage("Settings saved successfully"); setTimeout(() => setSuccessMessage(null), 3000); } catch (err) { @@ -107,17 +112,17 @@ export const CheckpointSettings: React.FC = ({ setIsLoading(true); setError(null); setSuccessMessage(null); - + const removed = await api.cleanupOldCheckpoints( sessionId, projectId, projectPath, - keepCount + keepCount, ); - + setSuccessMessage(`Removed ${removed} old checkpoints`); setTimeout(() => setSuccessMessage(null), 3000); - + // Reload settings to get updated count await loadSettings(); } catch (err) { @@ -143,8 +148,12 @@ export const CheckpointSettings: React.FC = ({
-

Checkpoint Settings

-

Manage session checkpoints and recovery

+

+ Checkpoint Settings +

+

+ Manage session checkpoints and recovery +

@@ -154,9 +163,12 @@ export const CheckpointSettings: React.FC = ({
-

Experimental Feature

+

+ Experimental Feature +

- Checkpointing may affect directory structure or cause data loss. Use with caution. + Checkpointing may affect directory structure or cause data loss. + Use with caution.

@@ -183,7 +195,9 @@ export const CheckpointSettings: React.FC = ({ transition={{ duration: 0.15 }} className="rounded-md border border-green-600/50 bg-green-50 dark:bg-green-950/20 p-3" > - {successMessage} + + {successMessage} + )} @@ -192,7 +206,9 @@ export const CheckpointSettings: React.FC = ({ {/* Auto-checkpoint toggle */}
- +

Automatically create checkpoints based on the selected strategy

@@ -207,26 +223,31 @@ export const CheckpointSettings: React.FC = ({ {/* Checkpoint strategy */}
- + setCheckpointStrategy(value as CheckpointStrategy)} + onValueChange={(value: string) => + setCheckpointStrategy(value as CheckpointStrategy) + } options={strategyOptions} disabled={isLoading || !autoCheckpointEnabled} />

- {checkpointStrategy === "manual" && "Checkpoints will only be created manually"} - {checkpointStrategy === "per_prompt" && "A checkpoint will be created after each user prompt"} - {checkpointStrategy === "per_tool_use" && "A checkpoint will be created after each tool use"} - {checkpointStrategy === "smart" && "Checkpoints will be created after destructive operations"} + {checkpointStrategy === "manual" && + "Checkpoints will only be created manually"} + {checkpointStrategy === "per_prompt" && + "A checkpoint will be created after each user prompt"} + {checkpointStrategy === "per_tool_use" && + "A checkpoint will be created after each tool use"} + {checkpointStrategy === "smart" && + "Checkpoints will be created after destructive operations"}

{/* Save button */} - +

- Total checkpoints: {totalCheckpoints} + Total checkpoints:{" "} + + {totalCheckpoints} +

{/* Cleanup settings */}
- +
= ({ ); -}; \ No newline at end of file +}; diff --git a/src/components/ClaudeBinaryDialog.tsx b/src/components/ClaudeBinaryDialog.tsx index eb72ccd62..ff424eea7 100644 --- a/src/components/ClaudeBinaryDialog.tsx +++ b/src/components/ClaudeBinaryDialog.tsx @@ -1,8 +1,21 @@ import { useState, useEffect } from "react"; import { api, type ClaudeInstallation } from "@/lib/api"; import { Button } from "@/components/ui/button"; -import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import { ExternalLink, FileQuestion, Terminal, AlertCircle, Loader2 } from "lucide-react"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { + ExternalLink, + FileQuestion, + Terminal, + AlertCircle, + Loader2, +} from "lucide-react"; import { ClaudeVersionSelector } from "./ClaudeVersionSelector"; interface ClaudeBinaryDialogProps { @@ -12,8 +25,14 @@ interface ClaudeBinaryDialogProps { onError: (message: string) => void; } -export function ClaudeBinaryDialog({ open, onOpenChange, onSuccess, onError }: ClaudeBinaryDialogProps) { - const [selectedInstallation, setSelectedInstallation] = useState(null); +export function ClaudeBinaryDialog({ + open, + onOpenChange, + onSuccess, + onError, +}: ClaudeBinaryDialogProps) { + const [selectedInstallation, setSelectedInstallation] = + useState(null); const [isValidating, setIsValidating] = useState(false); const [hasInstallations, setHasInstallations] = useState(true); const [checkingInstallations, setCheckingInstallations] = useState(true); @@ -50,7 +69,11 @@ export function ClaudeBinaryDialog({ open, onOpenChange, onSuccess, onError }: C onOpenChange(false); } catch (error) { console.error("Failed to save Claude binary path:", error); - onError(error instanceof Error ? error.message : "Failed to save Claude binary path"); + onError( + error instanceof Error + ? error.message + : "Failed to save Claude binary path", + ); } finally { setIsValidating(false); } @@ -68,24 +91,27 @@ export function ClaudeBinaryDialog({ open, onOpenChange, onSuccess, onError }: C {checkingInstallations ? (
- Searching for Claude installations... + + Searching for Claude installations... +
) : hasInstallations ? (

- Multiple Claude Code installations were found on your system. + Multiple Claude Code installations were found on your system. Please select which one you'd like to use.

) : ( <>

- Claude Code was not found in any of the common installation locations. - Please install Claude Code to continue. + Claude Code was not found in any of the common installation + locations. Please install Claude Code to continue.

- Searched locations: PATH, /usr/local/bin, - /opt/homebrew/bin, ~/.nvm/versions/node/*/bin, ~/.claude/local, ~/.local/bin + Searched locations:{" "} + PATH, /usr/local/bin, /opt/homebrew/bin, + ~/.nvm/versions/node/*/bin, ~/.claude/local, ~/.local/bin

@@ -94,8 +120,11 @@ export function ClaudeBinaryDialog({ open, onOpenChange, onSuccess, onError }: C

- Tip: You can install Claude Code using{" "} - npm install -g @claude + Tip: You can install + Claude Code using{" "} + + npm install -g @claude +

)} @@ -114,7 +143,12 @@ export function ClaudeBinaryDialog({ open, onOpenChange, onSuccess, onError }: C - ); -} \ No newline at end of file +} diff --git a/src/components/ClaudeCodeSession.refactored.tsx b/src/components/ClaudeCodeSession.refactored.tsx index ae70af687..d13c42131 100644 --- a/src/components/ClaudeCodeSession.refactored.tsx +++ b/src/components/ClaudeCodeSession.refactored.tsx @@ -6,12 +6,22 @@ import { Label } from "@/components/ui/label"; import { api, type Session } from "@/lib/api"; import { cn } from "@/lib/utils"; import { open } from "@tauri-apps/plugin-dialog"; -import { FloatingPromptInput, type FloatingPromptInputRef } from "./FloatingPromptInput"; +import { + FloatingPromptInput, + type FloatingPromptInputRef, +} from "./FloatingPromptInput"; import { ErrorBoundary } from "./ErrorBoundary"; import { TimelineNavigator } from "./TimelineNavigator"; import { CheckpointSettings } from "./CheckpointSettings"; import { SlashCommandsManager } from "./SlashCommandsManager"; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; import { SplitPane } from "@/components/ui/split-pane"; import { WebviewPreview } from "./WebviewPreview"; @@ -39,7 +49,9 @@ export const ClaudeCodeSession: React.FC = ({ className, onStreamingChange, }) => { - const [projectPath, setProjectPath] = useState(initialProjectPath || session?.project_path || ""); + const [projectPath, setProjectPath] = useState( + initialProjectPath || session?.project_path || "", + ); const [error, setError] = useState(null); const [copyPopoverOpen, setCopyPopoverOpen] = useState(false); const [isFirstPrompt, setIsFirstPrompt] = useState(!session); @@ -48,10 +60,13 @@ export const ClaudeCodeSession: React.FC = ({ const [showTimeline, setShowTimeline] = useState(false); const [showSettings, setShowSettings] = useState(false); const [showForkDialog, setShowForkDialog] = useState(false); - const [showSlashCommandsSettings, setShowSlashCommandsSettings] = useState(false); + const [showSlashCommandsSettings, setShowSlashCommandsSettings] = + useState(false); const [forkCheckpointId, setForkCheckpointId] = useState(null); const [forkSessionName, setForkSessionName] = useState(""); - const [queuedPrompts, setQueuedPrompts] = useState>([]); + const [queuedPrompts, setQueuedPrompts] = useState< + Array<{ id: string; prompt: string; model: "sonnet" | "opus" }> + >([]); const [showPreview, setShowPreview] = useState(false); const [previewUrl, setPreviewUrl] = useState(null); const [isPreviewMaximized, setIsPreviewMaximized] = useState(false); @@ -65,13 +80,13 @@ export const ClaudeCodeSession: React.FC = ({ isStreaming, currentSessionId: _currentSessionId, clearMessages, - loadMessages + loadMessages, } = useClaudeMessages({ onSessionInfo: (info) => { setClaudeSessionId(info.sessionId); }, onTokenUpdate: setTotalTokens, - onStreamingChange + onStreamingChange, }); const { @@ -80,14 +95,14 @@ export const ClaudeCodeSession: React.FC = ({ loadCheckpoints, createCheckpoint: _createCheckpoint, restoreCheckpoint, - forkCheckpoint + forkCheckpoint, } = useCheckpoints({ sessionId: claudeSessionId, - projectId: session?.project_id || '', + projectId: session?.project_id || "", projectPath: projectPath, - onToast: (message: string, type: 'success' | 'error') => { + onToast: (message: string, type: "success" | "error") => { console.log(`Toast: ${type} - ${message}`); - } + }, }); // Handle path selection @@ -95,10 +110,10 @@ export const ClaudeCodeSession: React.FC = ({ const selected = await open({ directory: true, multiple: false, - title: "Select Project Directory" + title: "Select Project Directory", }); - - if (selected && typeof selected === 'string') { + + if (selected && typeof selected === "string") { setProjectPath(selected); setError(null); setIsFirstPrompt(true); @@ -106,38 +121,43 @@ export const ClaudeCodeSession: React.FC = ({ }; // Handle sending prompts - const handleSendPrompt = useCallback(async (prompt: string, model: "sonnet" | "opus") => { - if (!projectPath || !prompt.trim()) return; - - // Add to queue if streaming - if (isStreaming) { - const id = Date.now().toString(); - setQueuedPrompts(prev => [...prev, { id, prompt, model }]); - return; - } + const handleSendPrompt = useCallback( + async (prompt: string, model: "sonnet" | "opus") => { + if (!projectPath || !prompt.trim()) return; - try { - setError(null); - - if (isFirstPrompt) { - await api.executeClaudeCode(projectPath, prompt, model); - setIsFirstPrompt(false); - } else if (claudeSessionId) { - await api.continueClaudeCode(projectPath, prompt, model); + // Add to queue if streaming + if (isStreaming) { + const id = Date.now().toString(); + setQueuedPrompts((prev) => [...prev, { id, prompt, model }]); + return; } - } catch (error) { - console.error("Failed to send prompt:", error); - setError(error instanceof Error ? error.message : "Failed to send prompt"); - } - }, [projectPath, isStreaming, isFirstPrompt, claudeSessionId]); + + try { + setError(null); + + if (isFirstPrompt) { + await api.executeClaudeCode(projectPath, prompt, model); + setIsFirstPrompt(false); + } else if (claudeSessionId) { + await api.continueClaudeCode(projectPath, prompt, model); + } + } catch (error) { + console.error("Failed to send prompt:", error); + setError( + error instanceof Error ? error.message : "Failed to send prompt", + ); + } + }, + [projectPath, isStreaming, isFirstPrompt, claudeSessionId], + ); // Process queued prompts const processQueuedPrompts = useCallback(async () => { if (queuedPrompts.length === 0 || isStreaming) return; const nextPrompt = queuedPrompts[0]; - setQueuedPrompts(prev => prev.slice(1)); - + setQueuedPrompts((prev) => prev.slice(1)); + await handleSendPrompt(nextPrompt.prompt, nextPrompt.model); }, [queuedPrompts, isStreaming, handleSendPrompt]); @@ -146,7 +166,7 @@ export const ClaudeCodeSession: React.FC = ({ if (!isStreaming && queuedPrompts.length > 0) { processQueueTimeoutRef.current = setTimeout(processQueuedPrompts, 500); } - + return () => { if (processQueueTimeoutRef.current) { clearTimeout(processQueueTimeoutRef.current); @@ -157,7 +177,7 @@ export const ClaudeCodeSession: React.FC = ({ // Copy handlers const handleCopyAsJsonl = async () => { try { - await navigator.clipboard.writeText(rawJsonlOutput.join('\n')); + await navigator.clipboard.writeText(rawJsonlOutput.join("\n")); setCopyPopoverOpen(false); console.log("Session output copied as JSONL"); } catch (error) { @@ -168,25 +188,28 @@ export const ClaudeCodeSession: React.FC = ({ const handleCopyAsMarkdown = async () => { try { const markdown = messages - .filter(msg => msg.type === 'user' || msg.type === 'assistant') - .map(msg => { - if (msg.type === 'user') { - return `## User\n\n${msg.message || ''}`; - } else if (msg.type === 'assistant' && msg.message?.content) { - const content = Array.isArray(msg.message.content) - ? msg.message.content.map((item: any) => { - if (typeof item === 'string') return item; - if (item.type === 'text') return item.text; - return ''; - }).filter(Boolean).join('') + .filter((msg) => msg.type === "user" || msg.type === "assistant") + .map((msg) => { + if (msg.type === "user") { + return `## User\n\n${msg.message || ""}`; + } else if (msg.type === "assistant" && msg.message?.content) { + const content = Array.isArray(msg.message.content) + ? msg.message.content + .map((item: any) => { + if (typeof item === "string") return item; + if (item.type === "text") return item.text; + return ""; + }) + .filter(Boolean) + .join("") : msg.message.content; return `## Assistant\n\n${content}`; } - return ''; + return ""; }) .filter(Boolean) - .join('\n\n---\n\n'); - + .join("\n\n---\n\n"); + await navigator.clipboard.writeText(markdown); setCopyPopoverOpen(false); console.log("Session output copied as Markdown"); @@ -205,7 +228,10 @@ export const ClaudeCodeSession: React.FC = ({ const handleConfirmFork = async () => { if (!forkCheckpointId || !forkSessionName.trim()) return; - const forkedSession = await forkCheckpoint(forkCheckpointId, forkSessionName); + const forkedSession = await forkCheckpoint( + forkCheckpointId, + forkSessionName, + ); if (forkedSession) { setShowForkDialog(false); // Navigate to forked session @@ -248,7 +274,9 @@ export const ClaudeCodeSession: React.FC = ({ onCopyAsJsonl={handleCopyAsJsonl} onCopyAsMarkdown={handleCopyAsMarkdown} onToggleTimeline={() => setShowTimeline(!showTimeline)} - onProjectSettings={onProjectSettings ? () => onProjectSettings(projectPath) : undefined} + onProjectSettings={ + onProjectSettings ? () => onProjectSettings(projectPath) : undefined + } onSlashCommandsSettings={() => setShowSlashCommandsSettings(true)} setCopyPopoverOpen={setCopyPopoverOpen} /> @@ -268,7 +296,11 @@ export const ClaudeCodeSession: React.FC = ({ /> setQueuedPrompts(prev => prev.filter(p => p.id !== id))} + onRemove={(id) => + setQueuedPrompts((prev) => + prev.filter((p) => p.id !== id), + ) + } />
} @@ -278,7 +310,9 @@ export const ClaudeCodeSession: React.FC = ({ isMaximized={isPreviewMaximized} onClose={() => setShowPreview(false)} onUrlChange={setPreviewUrl} - onToggleMaximize={() => setIsPreviewMaximized(!isPreviewMaximized)} + onToggleMaximize={() => + setIsPreviewMaximized(!isPreviewMaximized) + } /> } initialSplit={60} @@ -294,7 +328,9 @@ export const ClaudeCodeSession: React.FC = ({ /> setQueuedPrompts(prev => prev.filter(p => p.id !== id))} + onRemove={(id) => + setQueuedPrompts((prev) => prev.filter((p) => p.id !== id)) + } />
)} @@ -356,9 +392,7 @@ export const ClaudeCodeSession: React.FC = ({ )} {showSlashCommandsSettings && projectPath && ( - + )} {/* Fork dialog */} @@ -367,7 +401,8 @@ export const ClaudeCodeSession: React.FC = ({ Fork Session from Checkpoint - Create a new session branching from this checkpoint. The original session will remain unchanged. + Create a new session branching from this checkpoint. The + original session will remain unchanged.
@@ -383,10 +418,13 @@ export const ClaudeCodeSession: React.FC = ({
- -
); -}; \ No newline at end of file +}; diff --git a/src/components/ClaudeCodeSession.tsx b/src/components/ClaudeCodeSession.tsx index d4563e242..384444283 100644 --- a/src/components/ClaudeCodeSession.tsx +++ b/src/components/ClaudeCodeSession.tsx @@ -1,13 +1,13 @@ import React, { useState, useEffect, useRef, useMemo } from "react"; import { motion, AnimatePresence } from "framer-motion"; -import { +import { Copy, ChevronDown, GitBranch, ChevronUp, X, Hash, - Wrench + Wrench, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; @@ -17,18 +17,32 @@ import { api, type Session } from "@/lib/api"; import { cn } from "@/lib/utils"; import { listen, type UnlistenFn } from "@tauri-apps/api/event"; import { StreamMessage } from "./StreamMessage"; -import { FloatingPromptInput, type FloatingPromptInputRef } from "./FloatingPromptInput"; +import { + FloatingPromptInput, + type FloatingPromptInputRef, +} from "./FloatingPromptInput"; import { ErrorBoundary } from "./ErrorBoundary"; import { TimelineNavigator } from "./TimelineNavigator"; import { CheckpointSettings } from "./CheckpointSettings"; import { SlashCommandsManager } from "./SlashCommandsManager"; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogFooter, +} from "@/components/ui/dialog"; import { TooltipProvider, TooltipSimple } from "@/components/ui/tooltip-modern"; import { SplitPane } from "@/components/ui/split-pane"; import { WebviewPreview } from "./WebviewPreview"; import type { ClaudeStreamMessage } from "./AgentExecution"; import { useVirtualizer } from "@tanstack/react-virtual"; -import { useTrackEvent, useComponentMetrics, useWorkflowTracking } from "@/hooks"; +import { + useTrackEvent, + useComponentMetrics, + useWorkflowTracking, +} from "@/hooks"; import { SessionPersistenceService } from "@/services/sessionPersistence"; interface ClaudeCodeSessionProps { @@ -64,7 +78,7 @@ interface ClaudeCodeSessionProps { /** * ClaudeCodeSession component for interactive Claude Code sessions - * + * * @example * setView('projects')} /> */ @@ -75,7 +89,9 @@ export const ClaudeCodeSession: React.FC = ({ onStreamingChange, onProjectPathChange, }) => { - const [projectPath] = useState(initialProjectPath || session?.project_path || ""); + const [projectPath] = useState( + initialProjectPath || session?.project_path || "", + ); const [messages, setMessages] = useState([]); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); @@ -83,38 +99,46 @@ export const ClaudeCodeSession: React.FC = ({ const [copyPopoverOpen, setCopyPopoverOpen] = useState(false); const [isFirstPrompt, setIsFirstPrompt] = useState(!session); const [totalTokens, setTotalTokens] = useState(0); - const [extractedSessionInfo, setExtractedSessionInfo] = useState<{ sessionId: string; projectId: string } | null>(null); + const [extractedSessionInfo, setExtractedSessionInfo] = useState<{ + sessionId: string; + projectId: string; + } | null>(null); const [claudeSessionId, setClaudeSessionId] = useState(null); const [showTimeline, setShowTimeline] = useState(false); const [timelineVersion, setTimelineVersion] = useState(0); const [showSettings, setShowSettings] = useState(false); const [showForkDialog, setShowForkDialog] = useState(false); - const [showSlashCommandsSettings, setShowSlashCommandsSettings] = useState(false); + const [showSlashCommandsSettings, setShowSlashCommandsSettings] = + useState(false); const [forkCheckpointId, setForkCheckpointId] = useState(null); const [forkSessionName, setForkSessionName] = useState(""); - + // Queued prompts state - const [queuedPrompts, setQueuedPrompts] = useState>([]); - + const [queuedPrompts, setQueuedPrompts] = useState< + Array<{ id: string; prompt: string; model: "sonnet" | "opus" }> + >([]); + // New state for preview feature const [showPreview, setShowPreview] = useState(false); const [previewUrl, setPreviewUrl] = useState(""); const [showPreviewPrompt, setShowPreviewPrompt] = useState(false); const [splitPosition, setSplitPosition] = useState(50); const [isPreviewMaximized, setIsPreviewMaximized] = useState(false); - + // Add collapsed state for queued prompts const [queuedPromptsCollapsed, setQueuedPromptsCollapsed] = useState(false); - + const parentRef = useRef(null); const unlistenRefs = useRef([]); const hasActiveSessionRef = useRef(false); const floatingPromptRef = useRef(null); - const queuedPromptsRef = useRef>([]); + const queuedPromptsRef = useRef< + Array<{ id: string; prompt: string; model: "sonnet" | "opus" }> + >([]); const isMountedRef = useRef(true); const isListeningRef = useRef(false); const sessionStartTime = useRef(Date.now()); - + // Session metrics state for enhanced analytics const sessionMetrics = useRef({ firstMessageTime: null as number | null, @@ -135,17 +159,17 @@ export const ClaudeCodeSession: React.FC = ({ // Analytics tracking const trackEvent = useTrackEvent(); - useComponentMetrics('ClaudeCodeSession'); + useComponentMetrics("ClaudeCodeSession"); // const aiTracking = useAIInteractionTracking('sonnet'); // Default model - const workflowTracking = useWorkflowTracking('claude_session'); - + const workflowTracking = useWorkflowTracking("claude_session"); + // Call onProjectPathChange when component mounts with initial path useEffect(() => { if (onProjectPathChange && projectPath) { onProjectPathChange(projectPath); } }, []); // Only run on mount - + // Keep ref in sync with state useEffect(() => { queuedPromptsRef.current = queuedPrompts; @@ -178,7 +202,10 @@ export const ClaudeCodeSession: React.FC = ({ if (message.isMeta) return false; const msg = message.message; - if (!msg.content || (Array.isArray(msg.content) && msg.content.length === 0)) { + if ( + !msg.content || + (Array.isArray(msg.content) && msg.content.length === 0) + ) { return false; } @@ -195,17 +222,33 @@ export const ClaudeCodeSession: React.FC = ({ // Look for the matching tool_use in previous assistant messages for (let i = index - 1; i >= 0; i--) { const prevMsg = messages[i]; - if (prevMsg.type === 'assistant' && prevMsg.message?.content && Array.isArray(prevMsg.message.content)) { - const toolUse = prevMsg.message.content.find((c: any) => - c.type === 'tool_use' && c.id === content.tool_use_id + if ( + prevMsg.type === "assistant" && + prevMsg.message?.content && + Array.isArray(prevMsg.message.content) + ) { + const toolUse = prevMsg.message.content.find( + (c: any) => + c.type === "tool_use" && c.id === content.tool_use_id, ); if (toolUse) { const toolName = toolUse.name?.toLowerCase(); const toolsWithWidgets = [ - 'task', 'edit', 'multiedit', 'todowrite', 'ls', 'read', - 'glob', 'bash', 'write', 'grep' + "task", + "edit", + "multiedit", + "todowrite", + "ls", + "read", + "glob", + "bash", + "write", + "grep", ]; - if (toolsWithWidgets.includes(toolName) || toolUse.name?.startsWith('mcp__')) { + if ( + toolsWithWidgets.includes(toolName) || + toolUse.name?.startsWith("mcp__") + ) { willBeSkipped = true; } break; @@ -237,22 +280,29 @@ export const ClaudeCodeSession: React.FC = ({ // Debug logging useEffect(() => { - console.log('[ClaudeCodeSession] State update:', { + console.log("[ClaudeCodeSession] State update:", { projectPath, session, extractedSessionInfo, effectiveSession, messagesCount: messages.length, - isLoading + isLoading, }); - }, [projectPath, session, extractedSessionInfo, effectiveSession, messages.length, isLoading]); + }, [ + projectPath, + session, + extractedSessionInfo, + effectiveSession, + messages.length, + isLoading, + ]); // Load session history if resuming useEffect(() => { if (session) { // Set the claudeSessionId immediately when we have a session setClaudeSessionId(session.id); - + // Load session history first, then check for active session const initializeSession = async () => { await loadSessionHistory(); @@ -261,7 +311,7 @@ export const ClaudeCodeSession: React.FC = ({ await checkForActiveSession(); } }; - + initializeSession(); } }, [session]); // Remove hasLoadedSession dependency to ensure it runs on mount @@ -274,7 +324,10 @@ export const ClaudeCodeSession: React.FC = ({ // Auto-scroll to bottom when new messages arrive useEffect(() => { if (displayableMessages.length > 0) { - rowVirtualizer.scrollToIndex(displayableMessages.length - 1, { align: 'end', behavior: 'smooth' }); + rowVirtualizer.scrollToIndex(displayableMessages.length - 1, { + align: "end", + behavior: "smooth", + }); } }, [displayableMessages.length, rowVirtualizer]); @@ -282,7 +335,11 @@ export const ClaudeCodeSession: React.FC = ({ useEffect(() => { const tokens = messages.reduce((total, msg) => { if (msg.message?.usage) { - return total + msg.message.usage.input_tokens + msg.message.usage.output_tokens; + return ( + total + + msg.message.usage.input_tokens + + msg.message.usage.output_tokens + ); } if (msg.usage) { return total + msg.usage.input_tokens + msg.usage.output_tokens; @@ -294,39 +351,45 @@ export const ClaudeCodeSession: React.FC = ({ const loadSessionHistory = async () => { if (!session) return; - + try { setIsLoading(true); setError(null); - - const history = await api.loadSessionHistory(session.id, session.project_id); - + + const history = await api.loadSessionHistory( + session.id, + session.project_id, + ); + // Save session data for restoration if (history && history.length > 0) { SessionPersistenceService.saveSession( session.id, session.project_id, session.project_path, - history.length + history.length, ); } - + // Convert history to messages format - const loadedMessages: ClaudeStreamMessage[] = history.map(entry => ({ + const loadedMessages: ClaudeStreamMessage[] = history.map((entry) => ({ ...entry, - type: entry.type || "assistant" + type: entry.type || "assistant", })); - + setMessages(loadedMessages); - setRawJsonlOutput(history.map(h => JSON.stringify(h))); - + setRawJsonlOutput(history.map((h) => JSON.stringify(h))); + // After loading history, we're continuing a conversation setIsFirstPrompt(false); - + // Scroll to bottom after loading history setTimeout(() => { if (loadedMessages.length > 0) { - rowVirtualizer.scrollToIndex(loadedMessages.length - 1, { align: 'end', behavior: 'auto' }); + rowVirtualizer.scrollToIndex(loadedMessages.length - 1, { + align: "end", + behavior: "auto", + }); } }, 100); } catch (err) { @@ -343,84 +406,110 @@ export const ClaudeCodeSession: React.FC = ({ try { const activeSessions = await api.listRunningClaudeSessions(); const activeSession = activeSessions.find((s: any) => { - if ('process_type' in s && s.process_type && 'ClaudeSession' in s.process_type) { - return (s.process_type as any).ClaudeSession.session_id === session.id; + if ( + "process_type" in s && + s.process_type && + "ClaudeSession" in s.process_type + ) { + return ( + (s.process_type as any).ClaudeSession.session_id === session.id + ); } return false; }); - + if (activeSession) { // Session is still active, reconnect to its stream - console.log('[ClaudeCodeSession] Found active session, reconnecting:', session.id); + console.log( + "[ClaudeCodeSession] Found active session, reconnecting:", + session.id, + ); // IMPORTANT: Set claudeSessionId before reconnecting setClaudeSessionId(session.id); - + // Don't add buffered messages here - they've already been loaded by loadSessionHistory // Just set up listeners for new messages - + // Set up listeners for the active session reconnectToSession(session.id); } } catch (err) { - console.error('Failed to check for active sessions:', err); + console.error("Failed to check for active sessions:", err); } } }; const reconnectToSession = async (sessionId: string) => { - console.log('[ClaudeCodeSession] Reconnecting to session:', sessionId); - + console.log("[ClaudeCodeSession] Reconnecting to session:", sessionId); + // Prevent duplicate listeners if (isListeningRef.current) { - console.log('[ClaudeCodeSession] Already listening to session, skipping reconnect'); + console.log( + "[ClaudeCodeSession] Already listening to session, skipping reconnect", + ); return; } - + // Clean up previous listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // IMPORTANT: Set the session ID before setting up listeners setClaudeSessionId(sessionId); - + // Mark as listening isListeningRef.current = true; - + // Set up session-specific listeners - const outputUnlisten = await listen(`claude-output:${sessionId}`, async (event) => { - try { - console.log('[ClaudeCodeSession] Received claude-output on reconnect:', event.payload); - - if (!isMountedRef.current) return; - - // Store raw JSONL - setRawJsonlOutput(prev => [...prev, event.payload]); - - // Parse and display - const message = JSON.parse(event.payload) as ClaudeStreamMessage; - setMessages(prev => [...prev, message]); - } catch (err) { - console.error("Failed to parse message:", err, event.payload); - } - }); + const outputUnlisten = await listen( + `claude-output:${sessionId}`, + async (event) => { + try { + console.log( + "[ClaudeCodeSession] Received claude-output on reconnect:", + event.payload, + ); + + if (!isMountedRef.current) return; + + // Store raw JSONL + setRawJsonlOutput((prev) => [...prev, event.payload]); + + // Parse and display + const message = JSON.parse(event.payload) as ClaudeStreamMessage; + setMessages((prev) => [...prev, message]); + } catch (err) { + console.error("Failed to parse message:", err, event.payload); + } + }, + ); - const errorUnlisten = await listen(`claude-error:${sessionId}`, (event) => { - console.error("Claude error:", event.payload); - if (isMountedRef.current) { - setError(event.payload); - } - }); + const errorUnlisten = await listen( + `claude-error:${sessionId}`, + (event) => { + console.error("Claude error:", event.payload); + if (isMountedRef.current) { + setError(event.payload); + } + }, + ); - const completeUnlisten = await listen(`claude-complete:${sessionId}`, async (event) => { - console.log('[ClaudeCodeSession] Received claude-complete on reconnect:', event.payload); - if (isMountedRef.current) { - setIsLoading(false); - hasActiveSessionRef.current = false; - } - }); + const completeUnlisten = await listen( + `claude-complete:${sessionId}`, + async (event) => { + console.log( + "[ClaudeCodeSession] Received claude-complete on reconnect:", + event.payload, + ); + if (isMountedRef.current) { + setIsLoading(false); + hasActiveSessionRef.current = false; + } + }, + ); unlistenRefs.current = [outputUnlisten, errorUnlisten, completeUnlisten]; - + // Mark as loading to show the session is active if (isMountedRef.current) { setIsLoading(true); @@ -431,8 +520,14 @@ export const ClaudeCodeSession: React.FC = ({ // Project path selection handled by parent tab controls const handleSendPrompt = async (prompt: string, model: "sonnet" | "opus") => { - console.log('[ClaudeCodeSession] handleSendPrompt called with:', { prompt, model, projectPath, claudeSessionId, effectiveSession }); - + console.log("[ClaudeCodeSession] handleSendPrompt called with:", { + prompt, + model, + projectPath, + claudeSessionId, + effectiveSession, + }); + if (!projectPath) { setError("Please select a project directory first"); return; @@ -443,9 +538,9 @@ export const ClaudeCodeSession: React.FC = ({ const newPrompt = { id: `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, prompt, - model + model, }; - setQueuedPrompts(prev => [...prev, newPrompt]); + setQueuedPrompts((prev) => [...prev, newPrompt]); return; } @@ -453,21 +548,21 @@ export const ClaudeCodeSession: React.FC = ({ setIsLoading(true); setError(null); hasActiveSessionRef.current = true; - + // For resuming sessions, ensure we have the session ID if (effectiveSession && !claudeSessionId) { setClaudeSessionId(effectiveSession.id); } - + // Only clean up and set up new listeners if not already listening if (!isListeningRef.current) { // Clean up previous listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // Mark as setting up listeners isListeningRef.current = true; - + // -------------------------------------------------------------------- // 1ļøāƒ£ Event Listener Setup Strategy // -------------------------------------------------------------------- @@ -481,150 +576,198 @@ export const ClaudeCodeSession: React.FC = ({ // generic ones to prevent duplicate handling. // -------------------------------------------------------------------- - console.log('[ClaudeCodeSession] Setting up generic event listeners first'); + console.log( + "[ClaudeCodeSession] Setting up generic event listeners first", + ); - let currentSessionId: string | null = claudeSessionId || effectiveSession?.id || null; + let currentSessionId: string | null = + claudeSessionId || effectiveSession?.id || null; // Helper to attach session-specific listeners **once we are sure** const attachSessionSpecificListeners = async (sid: string) => { - console.log('[ClaudeCodeSession] Attaching session-specific listeners for', sid); - - const specificOutputUnlisten = await listen(`claude-output:${sid}`, (evt) => { - handleStreamMessage(evt.payload); - }); - - const specificErrorUnlisten = await listen(`claude-error:${sid}`, (evt) => { - console.error('Claude error (scoped):', evt.payload); - setError(evt.payload); - }); - - const specificCompleteUnlisten = await listen(`claude-complete:${sid}`, (evt) => { - console.log('[ClaudeCodeSession] Received claude-complete (scoped):', evt.payload); - processComplete(evt.payload); - }); + console.log( + "[ClaudeCodeSession] Attaching session-specific listeners for", + sid, + ); + + const specificOutputUnlisten = await listen( + `claude-output:${sid}`, + (evt) => { + handleStreamMessage(evt.payload); + }, + ); + + const specificErrorUnlisten = await listen( + `claude-error:${sid}`, + (evt) => { + console.error("Claude error (scoped):", evt.payload); + setError(evt.payload); + }, + ); + + const specificCompleteUnlisten = await listen( + `claude-complete:${sid}`, + (evt) => { + console.log( + "[ClaudeCodeSession] Received claude-complete (scoped):", + evt.payload, + ); + processComplete(evt.payload); + }, + ); // Replace existing unlisten refs with these new ones (after cleaning up) unlistenRefs.current.forEach((u) => u()); - unlistenRefs.current = [specificOutputUnlisten, specificErrorUnlisten, specificCompleteUnlisten]; + unlistenRefs.current = [ + specificOutputUnlisten, + specificErrorUnlisten, + specificCompleteUnlisten, + ]; }; // Generic listeners (catch-all) - const genericOutputUnlisten = await listen('claude-output', async (event) => { - handleStreamMessage(event.payload); + const genericOutputUnlisten = await listen( + "claude-output", + async (event) => { + handleStreamMessage(event.payload); - // Attempt to extract session_id on the fly (for the very first init) - try { - const msg = JSON.parse(event.payload) as ClaudeStreamMessage; - if (msg.type === 'system' && msg.subtype === 'init' && msg.session_id) { - if (!currentSessionId || currentSessionId !== msg.session_id) { - console.log('[ClaudeCodeSession] Detected new session_id from generic listener:', msg.session_id); - currentSessionId = msg.session_id; - setClaudeSessionId(msg.session_id); - - // If we haven't extracted session info before, do it now - if (!extractedSessionInfo) { - const projectId = projectPath.replace(/[^a-zA-Z0-9]/g, '-'); - setExtractedSessionInfo({ sessionId: msg.session_id, projectId }); - - // Save session data for restoration - SessionPersistenceService.saveSession( + // Attempt to extract session_id on the fly (for the very first init) + try { + const msg = JSON.parse(event.payload) as ClaudeStreamMessage; + if ( + msg.type === "system" && + msg.subtype === "init" && + msg.session_id + ) { + if (!currentSessionId || currentSessionId !== msg.session_id) { + console.log( + "[ClaudeCodeSession] Detected new session_id from generic listener:", msg.session_id, - projectId, - projectPath, - messages.length ); - } + currentSessionId = msg.session_id; + setClaudeSessionId(msg.session_id); + + // If we haven't extracted session info before, do it now + if (!extractedSessionInfo) { + const projectId = projectPath.replace(/[^a-zA-Z0-9]/g, "-"); + setExtractedSessionInfo({ + sessionId: msg.session_id, + projectId, + }); + + // Save session data for restoration + SessionPersistenceService.saveSession( + msg.session_id, + projectId, + projectPath, + messages.length, + ); + } - // Switch to session-specific listeners - await attachSessionSpecificListeners(msg.session_id); + // Switch to session-specific listeners + await attachSessionSpecificListeners(msg.session_id); + } } + } catch { + /* ignore parse errors */ } - } catch { - /* ignore parse errors */ - } - }); + }, + ); // Helper to process any JSONL stream message string function handleStreamMessage(payload: string) { try { // Don't process if component unmounted if (!isMountedRef.current) return; - + // Store raw JSONL setRawJsonlOutput((prev) => [...prev, payload]); const message = JSON.parse(payload) as ClaudeStreamMessage; - + // Track enhanced tool execution - if (message.type === 'assistant' && message.message?.content) { - const toolUses = message.message.content.filter((c: any) => c.type === 'tool_use'); + if (message.type === "assistant" && message.message?.content) { + const toolUses = message.message.content.filter( + (c: any) => c.type === "tool_use", + ); toolUses.forEach((toolUse: any) => { // Increment tools executed counter sessionMetrics.current.toolsExecuted += 1; sessionMetrics.current.lastActivityTime = Date.now(); - + // Track file operations - const toolName = toolUse.name?.toLowerCase() || ''; - if (toolName.includes('create') || toolName.includes('write')) { + const toolName = toolUse.name?.toLowerCase() || ""; + if (toolName.includes("create") || toolName.includes("write")) { sessionMetrics.current.filesCreated += 1; - } else if (toolName.includes('edit') || toolName.includes('multiedit') || toolName.includes('search_replace')) { + } else if ( + toolName.includes("edit") || + toolName.includes("multiedit") || + toolName.includes("search_replace") + ) { sessionMetrics.current.filesModified += 1; - } else if (toolName.includes('delete')) { + } else if (toolName.includes("delete")) { sessionMetrics.current.filesDeleted += 1; } - + // Track tool start - we'll track completion when we get the result workflowTracking.trackStep(toolUse.name); }); } - + // Track tool results - if (message.type === 'user' && message.message?.content) { - const toolResults = message.message.content.filter((c: any) => c.type === 'tool_result'); + if (message.type === "user" && message.message?.content) { + const toolResults = message.message.content.filter( + (c: any) => c.type === "tool_result", + ); toolResults.forEach((result: any) => { const isError = result.is_error || false; // Note: We don't have execution time here, but we can track success/failure if (isError) { sessionMetrics.current.toolsFailed += 1; sessionMetrics.current.errorsEncountered += 1; - + trackEvent.enhancedError({ - error_type: 'tool_execution', - error_code: 'tool_failed', + error_type: "tool_execution", + error_code: "tool_failed", error_message: result.content, context: `Tool execution failed`, - user_action_before_error: 'executing_tool', + user_action_before_error: "executing_tool", recovery_attempted: false, recovery_successful: false, error_frequency: 1, - stack_trace_hash: undefined + stack_trace_hash: undefined, }); } }); } - + // Track code blocks generated - if (message.type === 'assistant' && message.message?.content) { - const codeBlocks = message.message.content.filter((c: any) => - c.type === 'text' && c.text?.includes('```') + if (message.type === "assistant" && message.message?.content) { + const codeBlocks = message.message.content.filter( + (c: any) => c.type === "text" && c.text?.includes("```"), ); if (codeBlocks.length > 0) { // Count code blocks in text content codeBlocks.forEach((block: any) => { const matches = (block.text.match(/```/g) || []).length; - sessionMetrics.current.codeBlocksGenerated += Math.floor(matches / 2); + sessionMetrics.current.codeBlocksGenerated += Math.floor( + matches / 2, + ); }); } } - + // Track errors in system messages - if (message.type === 'system' && (message.subtype === 'error' || message.error)) { + if ( + message.type === "system" && + (message.subtype === "error" || message.error) + ) { sessionMetrics.current.errorsEncountered += 1; } - + setMessages((prev) => [...prev, message]); } catch (err) { - console.error('Failed to parse message:', err, payload); + console.error("Failed to parse message:", err, payload); } } @@ -633,31 +776,36 @@ export const ClaudeCodeSession: React.FC = ({ setIsLoading(false); hasActiveSessionRef.current = false; isListeningRef.current = false; // Reset listening state - + // Track enhanced session stopped metrics when session completes if (effectiveSession && claudeSessionId) { - const sessionStartTimeValue = messages.length > 0 ? messages[0].timestamp || Date.now() : Date.now(); + const sessionStartTimeValue = + messages.length > 0 + ? messages[0].timestamp || Date.now() + : Date.now(); const duration = Date.now() - sessionStartTimeValue; const metrics = sessionMetrics.current; - const timeToFirstMessage = metrics.firstMessageTime - ? metrics.firstMessageTime - sessionStartTime.current + const timeToFirstMessage = metrics.firstMessageTime + ? metrics.firstMessageTime - sessionStartTime.current : undefined; const idleTime = Date.now() - metrics.lastActivityTime; - const avgResponseTime = metrics.toolExecutionTimes.length > 0 - ? metrics.toolExecutionTimes.reduce((a, b) => a + b, 0) / metrics.toolExecutionTimes.length - : undefined; - + const avgResponseTime = + metrics.toolExecutionTimes.length > 0 + ? metrics.toolExecutionTimes.reduce((a, b) => a + b, 0) / + metrics.toolExecutionTimes.length + : undefined; + trackEvent.enhancedSessionStopped({ // Basic metrics duration_ms: duration, messages_count: messages.length, - reason: success ? 'completed' : 'error', - + reason: success ? "completed" : "error", + // Timing metrics time_to_first_message_ms: timeToFirstMessage, average_response_time_ms: avgResponseTime, idle_time_ms: idleTime, - + // Interaction metrics prompts_sent: metrics.promptsSent, tools_executed: metrics.toolsExecuted, @@ -665,28 +813,29 @@ export const ClaudeCodeSession: React.FC = ({ files_created: metrics.filesCreated, files_modified: metrics.filesModified, files_deleted: metrics.filesDeleted, - + // Content metrics total_tokens_used: totalTokens, code_blocks_generated: metrics.codeBlocksGenerated, errors_encountered: metrics.errorsEncountered, - + // Session context - model: metrics.modelChanges.length > 0 - ? metrics.modelChanges[metrics.modelChanges.length - 1].to - : 'sonnet', + model: + metrics.modelChanges.length > 0 + ? metrics.modelChanges[metrics.modelChanges.length - 1].to + : "sonnet", has_checkpoints: metrics.checkpointCount > 0, checkpoint_count: metrics.checkpointCount, was_resumed: metrics.wasResumed, - + // Agent context (if applicable) agent_type: undefined, // TODO: Pass from agent execution agent_name: undefined, // TODO: Pass from agent execution agent_success: success, - + // Stop context - stop_source: 'completed', - final_state: success ? 'success' : 'failed', + stop_source: "completed", + final_state: success ? "success" : "failed", has_pending_prompts: queuedPrompts.length > 0, pending_prompts_count: queuedPrompts.length, }); @@ -697,7 +846,7 @@ export const ClaudeCodeSession: React.FC = ({ const settings = await api.getCheckpointSettings( effectiveSession.id, effectiveSession.project_id, - projectPath + projectPath, ); if (settings.auto_checkpoint_enabled) { @@ -705,13 +854,13 @@ export const ClaudeCodeSession: React.FC = ({ effectiveSession.id, effectiveSession.project_id, projectPath, - prompt + prompt, ); // Reload timeline to show new checkpoint setTimelineVersion((v) => v + 1); } } catch (err) { - console.error('Failed to check auto checkpoint:', err); + console.error("Failed to check auto checkpoint:", err); } } @@ -719,7 +868,7 @@ export const ClaudeCodeSession: React.FC = ({ if (queuedPromptsRef.current.length > 0) { const [nextPrompt, ...remainingPrompts] = queuedPromptsRef.current; setQueuedPrompts(remainingPrompts); - + // Small delay to ensure UI updates setTimeout(() => { handleSendPrompt(nextPrompt.prompt, nextPrompt.model); @@ -727,18 +876,31 @@ export const ClaudeCodeSession: React.FC = ({ } }; - const genericErrorUnlisten = await listen('claude-error', (evt) => { - console.error('Claude error:', evt.payload); - setError(evt.payload); - }); + const genericErrorUnlisten = await listen( + "claude-error", + (evt) => { + console.error("Claude error:", evt.payload); + setError(evt.payload); + }, + ); - const genericCompleteUnlisten = await listen('claude-complete', (evt) => { - console.log('[ClaudeCodeSession] Received claude-complete (generic):', evt.payload); - processComplete(evt.payload); - }); + const genericCompleteUnlisten = await listen( + "claude-complete", + (evt) => { + console.log( + "[ClaudeCodeSession] Received claude-complete (generic):", + evt.payload, + ); + processComplete(evt.payload); + }, + ); // Store the generic unlisteners for now; they may be replaced later. - unlistenRefs.current = [genericOutputUnlisten, genericErrorUnlisten, genericCompleteUnlisten]; + unlistenRefs.current = [ + genericOutputUnlisten, + genericErrorUnlisten, + genericCompleteUnlisten, + ]; // -------------------------------------------------------------------- // 2ļøāƒ£ Auto-checkpoint logic moved after listener setup (unchanged) @@ -751,63 +913,87 @@ export const ClaudeCodeSession: React.FC = ({ content: [ { type: "text", - text: prompt - } - ] - } + text: prompt, + }, + ], + }, }; - setMessages(prev => [...prev, userMessage]); - + setMessages((prev) => [...prev, userMessage]); + // Update session metrics sessionMetrics.current.promptsSent += 1; sessionMetrics.current.lastActivityTime = Date.now(); if (!sessionMetrics.current.firstMessageTime) { sessionMetrics.current.firstMessageTime = Date.now(); } - + // Track model changes - const lastModel = sessionMetrics.current.modelChanges.length > 0 - ? sessionMetrics.current.modelChanges[sessionMetrics.current.modelChanges.length - 1].to - : (sessionMetrics.current.wasResumed ? 'sonnet' : model); // Default to sonnet if resumed - + const lastModel = + sessionMetrics.current.modelChanges.length > 0 + ? sessionMetrics.current.modelChanges[ + sessionMetrics.current.modelChanges.length - 1 + ].to + : sessionMetrics.current.wasResumed + ? "sonnet" + : model; // Default to sonnet if resumed + if (lastModel !== model) { sessionMetrics.current.modelChanges.push({ from: lastModel, to: model, - timestamp: Date.now() + timestamp: Date.now(), }); } - + // Track enhanced prompt submission const codeBlockMatches = prompt.match(/```[\s\S]*?```/g) || []; const hasCode = codeBlockMatches.length > 0; - const conversationDepth = messages.filter(m => m.user_message).length; - const sessionAge = sessionStartTime.current ? Date.now() - sessionStartTime.current : 0; - const wordCount = prompt.split(/\s+/).filter(word => word.length > 0).length; - + const conversationDepth = messages.filter((m) => m.user_message).length; + const sessionAge = sessionStartTime.current + ? Date.now() - sessionStartTime.current + : 0; + const wordCount = prompt + .split(/\s+/) + .filter((word) => word.length > 0).length; + trackEvent.enhancedPromptSubmitted({ prompt_length: prompt.length, model: model, has_attachments: false, // TODO: Add attachment support when implemented - source: 'keyboard', // TODO: Track actual source (keyboard vs button) + source: "keyboard", // TODO: Track actual source (keyboard vs button) word_count: wordCount, conversation_depth: conversationDepth, - prompt_complexity: wordCount < 20 ? 'simple' : wordCount < 100 ? 'moderate' : 'complex', + prompt_complexity: + wordCount < 20 + ? "simple" + : wordCount < 100 + ? "moderate" + : "complex", contains_code: hasCode, - language_detected: hasCode ? codeBlockMatches?.[0]?.match(/```(\w+)/)?.[1] : undefined, - session_age_ms: sessionAge + language_detected: hasCode + ? codeBlockMatches?.[0]?.match(/```(\w+)/)?.[1] + : undefined, + session_age_ms: sessionAge, }); // Execute the appropriate command if (effectiveSession && !isFirstPrompt) { - console.log('[ClaudeCodeSession] Resuming session:', effectiveSession.id); + console.log( + "[ClaudeCodeSession] Resuming session:", + effectiveSession.id, + ); trackEvent.sessionResumed(effectiveSession.id); trackEvent.modelSelected(model); - await api.resumeClaudeCode(projectPath, effectiveSession.id, prompt, model); + await api.resumeClaudeCode( + projectPath, + effectiveSession.id, + prompt, + model, + ); } else { - console.log('[ClaudeCodeSession] Starting new session'); + console.log("[ClaudeCodeSession] Starting new session"); setIsFirstPrompt(false); - trackEvent.sessionCreated(model, 'prompt_input'); + trackEvent.sessionCreated(model, "prompt_input"); trackEvent.modelSelected(model); await api.executeClaudeCode(projectPath, prompt, model); } @@ -821,7 +1007,7 @@ export const ClaudeCodeSession: React.FC = ({ }; const handleCopyAsJsonl = async () => { - const jsonl = rawJsonlOutput.join('\n'); + const jsonl = rawJsonlOutput.join("\n"); await navigator.clipboard.writeText(jsonl); setCopyPopoverOpen(false); }; @@ -835,18 +1021,19 @@ export const ClaudeCodeSession: React.FC = ({ for (const msg of messages) { if (msg.type === "system" && msg.subtype === "init") { markdown += `## System Initialization\n\n`; - markdown += `- Session ID: \`${msg.session_id || 'N/A'}\`\n`; - markdown += `- Model: \`${msg.model || 'default'}\`\n`; + markdown += `- Session ID: \`${msg.session_id || "N/A"}\`\n`; + markdown += `- Model: \`${msg.model || "default"}\`\n`; if (msg.cwd) markdown += `- Working Directory: \`${msg.cwd}\`\n`; - if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(', ')}\n`; + if (msg.tools?.length) markdown += `- Tools: ${msg.tools.join(", ")}\n`; markdown += `\n`; } else if (msg.type === "assistant" && msg.message) { markdown += `## Assistant\n\n`; for (const content of msg.message.content || []) { if (content.type === "text") { - const textContent = typeof content.text === 'string' - ? content.text - : (content.text?.text || JSON.stringify(content.text || content)); + const textContent = + typeof content.text === "string" + ? content.text + : content.text?.text || JSON.stringify(content.text || content); markdown += `${textContent}\n\n`; } else if (content.type === "tool_use") { markdown += `### Tool: ${content.name}\n\n`; @@ -860,22 +1047,25 @@ export const ClaudeCodeSession: React.FC = ({ markdown += `## User\n\n`; for (const content of msg.message.content || []) { if (content.type === "text") { - const textContent = typeof content.text === 'string' - ? content.text - : (content.text?.text || JSON.stringify(content.text)); + const textContent = + typeof content.text === "string" + ? content.text + : content.text?.text || JSON.stringify(content.text); markdown += `${textContent}\n\n`; } else if (content.type === "tool_result") { markdown += `### Tool Result\n\n`; - let contentText = ''; - if (typeof content.content === 'string') { + let contentText = ""; + if (typeof content.content === "string") { contentText = content.content; - } else if (content.content && typeof content.content === 'object') { + } else if (content.content && typeof content.content === "object") { if (content.content.text) { contentText = content.content.text; } else if (Array.isArray(content.content)) { contentText = content.content - .map((c: any) => (typeof c === 'string' ? c : c.text || JSON.stringify(c))) - .join('\n'); + .map((c: any) => + typeof c === "string" ? c : c.text || JSON.stringify(c), + ) + .join("\n"); } else { contentText = JSON.stringify(content.content, null, 2); } @@ -904,7 +1094,7 @@ export const ClaudeCodeSession: React.FC = ({ // Ensure timeline reloads to highlight current checkpoint setTimelineVersion((v) => v + 1); }; - + const handleCheckpointCreated = () => { // Update checkpoint count in session metrics sessionMetrics.current.checkpointCount += 1; @@ -912,35 +1102,38 @@ export const ClaudeCodeSession: React.FC = ({ const handleCancelExecution = async () => { if (!claudeSessionId || !isLoading) return; - + try { - const sessionStartTime = messages.length > 0 ? messages[0].timestamp || Date.now() : Date.now(); + const sessionStartTime = + messages.length > 0 ? messages[0].timestamp || Date.now() : Date.now(); const duration = Date.now() - sessionStartTime; - + await api.cancelClaudeExecution(claudeSessionId); - + // Calculate metrics for enhanced analytics const metrics = sessionMetrics.current; - const timeToFirstMessage = metrics.firstMessageTime - ? metrics.firstMessageTime - sessionStartTime.current + const timeToFirstMessage = metrics.firstMessageTime + ? metrics.firstMessageTime - sessionStartTime.current : undefined; const idleTime = Date.now() - metrics.lastActivityTime; - const avgResponseTime = metrics.toolExecutionTimes.length > 0 - ? metrics.toolExecutionTimes.reduce((a, b) => a + b, 0) / metrics.toolExecutionTimes.length - : undefined; - + const avgResponseTime = + metrics.toolExecutionTimes.length > 0 + ? metrics.toolExecutionTimes.reduce((a, b) => a + b, 0) / + metrics.toolExecutionTimes.length + : undefined; + // Track enhanced session stopped trackEvent.enhancedSessionStopped({ // Basic metrics duration_ms: duration, messages_count: messages.length, - reason: 'user_stopped', - + reason: "user_stopped", + // Timing metrics time_to_first_message_ms: timeToFirstMessage, average_response_time_ms: avgResponseTime, idle_time_ms: idleTime, - + // Interaction metrics prompts_sent: metrics.promptsSent, tools_executed: metrics.toolsExecuted, @@ -948,70 +1141,71 @@ export const ClaudeCodeSession: React.FC = ({ files_created: metrics.filesCreated, files_modified: metrics.filesModified, files_deleted: metrics.filesDeleted, - + // Content metrics total_tokens_used: totalTokens, code_blocks_generated: metrics.codeBlocksGenerated, errors_encountered: metrics.errorsEncountered, - + // Session context - model: metrics.modelChanges.length > 0 - ? metrics.modelChanges[metrics.modelChanges.length - 1].to - : 'sonnet', // Default to sonnet + model: + metrics.modelChanges.length > 0 + ? metrics.modelChanges[metrics.modelChanges.length - 1].to + : "sonnet", // Default to sonnet has_checkpoints: metrics.checkpointCount > 0, checkpoint_count: metrics.checkpointCount, was_resumed: metrics.wasResumed, - + // Agent context (if applicable) agent_type: undefined, // TODO: Pass from agent execution agent_name: undefined, // TODO: Pass from agent execution agent_success: undefined, // TODO: Pass from agent execution - + // Stop context - stop_source: 'user_button', - final_state: 'cancelled', + stop_source: "user_button", + final_state: "cancelled", has_pending_prompts: queuedPrompts.length > 0, pending_prompts_count: queuedPrompts.length, }); - + // Clean up listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // Reset states setIsLoading(false); hasActiveSessionRef.current = false; isListeningRef.current = false; setError(null); - + // Clear queued prompts setQueuedPrompts([]); - + // Add a message indicating the session was cancelled const cancelMessage: ClaudeStreamMessage = { type: "system", subtype: "info", result: "Session cancelled by user", - timestamp: new Date().toISOString() + timestamp: new Date().toISOString(), }; - setMessages(prev => [...prev, cancelMessage]); + setMessages((prev) => [...prev, cancelMessage]); } catch (err) { console.error("Failed to cancel execution:", err); - + // Even if backend fails, we should update UI to reflect stopped state // Add error message but still stop the UI loading state const errorMessage: ClaudeStreamMessage = { type: "system", subtype: "error", - result: `Failed to cancel execution: ${err instanceof Error ? err.message : 'Unknown error'}. The process may still be running in the background.`, - timestamp: new Date().toISOString() + result: `Failed to cancel execution: ${err instanceof Error ? err.message : "Unknown error"}. The process may still be running in the background.`, + timestamp: new Date().toISOString(), }; - setMessages(prev => [...prev, errorMessage]); - + setMessages((prev) => [...prev, errorMessage]); + // Clean up listeners anyway - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // Reset states to allow user to continue setIsLoading(false); hasActiveSessionRef.current = false; @@ -1027,12 +1221,13 @@ export const ClaudeCodeSession: React.FC = ({ }; const handleConfirmFork = async () => { - if (!forkCheckpointId || !forkSessionName.trim() || !effectiveSession) return; - + if (!forkCheckpointId || !forkSessionName.trim() || !effectiveSession) + return; + try { setIsLoading(true); setError(null); - + const newSessionId = `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; await api.forkFromCheckpoint( forkCheckpointId, @@ -1040,13 +1235,13 @@ export const ClaudeCodeSession: React.FC = ({ effectiveSession.project_id, projectPath, newSessionId, - forkSessionName + forkSessionName, ); - + // Open the new forked session // You would need to implement navigation to the new session console.log("Forked to new session:", newSessionId); - + setShowForkDialog(false); setForkCheckpointId(null); setForkSessionName(""); @@ -1073,7 +1268,7 @@ export const ClaudeCodeSession: React.FC = ({ }; const handlePreviewUrlChange = (url: string) => { - console.log('[ClaudeCodeSession] Preview URL changed to:', url); + console.log("[ClaudeCodeSession] Preview URL changed to:", url); setPreviewUrl(url); }; @@ -1088,50 +1283,57 @@ export const ClaudeCodeSession: React.FC = ({ // Cleanup event listeners and track mount state useEffect(() => { isMountedRef.current = true; - + return () => { - console.log('[ClaudeCodeSession] Component unmounting, cleaning up listeners'); + console.log( + "[ClaudeCodeSession] Component unmounting, cleaning up listeners", + ); isMountedRef.current = false; isListeningRef.current = false; - + // Track session completion with engagement metrics if (effectiveSession) { trackEvent.sessionCompleted(); - + // Track session engagement - const sessionDuration = sessionStartTime.current ? Date.now() - sessionStartTime.current : 0; - const messageCount = messages.filter(m => m.user_message).length; + const sessionDuration = sessionStartTime.current + ? Date.now() - sessionStartTime.current + : 0; + const messageCount = messages.filter((m) => m.user_message).length; const toolsUsed = new Set(); - messages.forEach(msg => { - if (msg.type === 'assistant' && msg.message?.content) { - const tools = msg.message.content.filter((c: any) => c.type === 'tool_use'); + messages.forEach((msg) => { + if (msg.type === "assistant" && msg.message?.content) { + const tools = msg.message.content.filter( + (c: any) => c.type === "tool_use", + ); tools.forEach((tool: any) => toolsUsed.add(tool.name)); } }); - + // Calculate engagement score (0-100) - const engagementScore = Math.min(100, - (messageCount * 10) + - (toolsUsed.size * 5) + - (sessionDuration > 300000 ? 20 : sessionDuration / 15000) // 5+ min session gets 20 points + const engagementScore = Math.min( + 100, + messageCount * 10 + + toolsUsed.size * 5 + + (sessionDuration > 300000 ? 20 : sessionDuration / 15000), // 5+ min session gets 20 points ); - + trackEvent.sessionEngagement({ session_duration_ms: sessionDuration, messages_sent: messageCount, tools_used: Array.from(toolsUsed), files_modified: 0, // TODO: Track file modifications - engagement_score: Math.round(engagementScore) + engagement_score: Math.round(engagementScore), }); } - + // Clean up listeners - unlistenRefs.current.forEach(unlisten => unlisten()); + unlistenRefs.current.forEach((unlisten) => unlisten()); unlistenRefs.current = []; - + // Clear checkpoint manager when session ends if (effectiveSession) { - api.clearCheckpointManager(effectiveSession.id).catch(err => { + api.clearCheckpointManager(effectiveSession.id).catch((err) => { console.error("Failed to clear checkpoint manager:", err); }); } @@ -1143,14 +1345,14 @@ export const ClaudeCodeSession: React.FC = ({ ref={parentRef} className="flex-1 overflow-y-auto relative pb-40" style={{ - contain: 'strict', + contain: "strict", }} >
@@ -1170,8 +1372,8 @@ export const ClaudeCodeSession: React.FC = ({ top: virtualItem.start, }} > - @@ -1213,7 +1415,7 @@ export const ClaudeCodeSession: React.FC = ({ if (showPreview && isPreviewMaximized) { return ( - = ({
+ {/* Main Content Area */} +
+ {showPreview ? ( + // Split pane layout when preview is active + + {projectPathInput} + {messagesList} +
+ } + right={ + + } + initialSplit={splitPosition} + onSplitChange={setSplitPosition} + minLeftWidth={400} + minRightWidth={400} + className="h-full" + /> + ) : ( + // Original layout when no preview +
+ {projectPathInput} + {messagesList} + + {isLoading && messages.length === 0 && ( +
+
+
+ + {session + ? "Loading session history..." + : "Initializing Claude Code..."} + +
+
+ )} +
+ )} +
- {/* Main Content Area */} -
- {showPreview ? ( - // Split pane layout when preview is active - - {projectPathInput} - {messagesList} -
- } - right={ - - } - initialSplit={splitPosition} - onSplitChange={setSplitPosition} - minLeftWidth={400} - minRightWidth={400} - className="h-full" - /> - ) : ( - // Original layout when no preview -
- {projectPathInput} - {messagesList} - - {isLoading && messages.length === 0 && ( -
-
-
- - {session ? "Loading session history..." : "Initializing Claude Code..."} - + {/* Floating Prompt Input - Always visible */} + + {/* Queued Prompts Display */} + + {queuedPrompts.length > 0 && ( + +
+
+
+ Queued Prompts ({queuedPrompts.length}) +
+ + + + + +
+ {!queuedPromptsCollapsed && + queuedPrompts.map((queuedPrompt, index) => ( + +
+
+ + #{index + 1} + + + {queuedPrompt.model === "opus" + ? "Opus" + : "Sonnet"} + +
+

+ {queuedPrompt.prompt} +

+
+ + + +
+ ))}
-
+ )} -
- )} -
+ - {/* Floating Prompt Input - Always visible */} - - {/* Queued Prompts Display */} - - {queuedPrompts.length > 0 && ( + {/* Navigation Arrows - positioned above prompt bar with spacing */} + {displayableMessages.length > 5 && ( -
-
-
- Queued Prompts ({queuedPrompts.length}) -
- - + + + - - -
- {!queuedPromptsCollapsed && queuedPrompts.map((queuedPrompt, index) => ( + + + + +
+ -
-
- #{index + 1} - - {queuedPrompt.model === "opus" ? "Opus" : "Sonnet"} - -
-

{queuedPrompt.prompt}

-
- { + // Use virtualizer to scroll to the last item + if (displayableMessages.length > 0) { + // Scroll to bottom of the container + const scrollElement = parentRef.current; + if (scrollElement) { + scrollElement.scrollTo({ + top: scrollElement.scrollHeight, + behavior: "smooth", + }); + } + } + }} + className="px-3 py-2 hover:bg-accent rounded-none" > - - + +
- ))} +
)} - - {/* Navigation Arrows - positioned above prompt bar with spacing */} - {displayableMessages.length > 5 && ( - -
- - - - - -
- - - + + + )} + {messages.length > 0 && ( + + + + + } - } - }} - className="px-3 py-2 hover:bg-accent rounded-none" - > - - - - -
- - )} - -
- - {effectiveSession && ( - + content={ +
+ + +
+ } + open={copyPopoverOpen} + onOpenChange={setCopyPopoverOpen} + side="top" + align="end" + /> + )} + = ({ - )} - {messages.length > 0 && ( - - - - -
- } - content={ -
- - -
- } - open={copyPopoverOpen} - onOpenChange={setCopyPopoverOpen} - side="top" - align="end" - /> - )} - + + } + /> +
+ + {/* Token Counter - positioned under the Send button */} + {totalTokens > 0 && ( +
+
+
- +
+ + + {totalTokens.toLocaleString()} + + tokens +
- - - } - /> -
- - {/* Token Counter - positioned under the Send button */} - {totalTokens > 0 && ( -
-
-
- -
- - {totalTokens.toLocaleString()} - tokens -
-
+
-
- )} - + )} + - {/* Timeline */} - - {showTimeline && effectiveSession && ( - -
- {/* Timeline Header */} -
-

Session Timeline

- -
- - {/* Timeline Content */} -
- -
-
-
- )} -
-
+ {/* Timeline */} + + {showTimeline && effectiveSession && ( + +
+ {/* Timeline Header */} +
+

Session Timeline

+ +
- {/* Fork Dialog */} - - - - Fork Session - - Create a new session branch from the selected checkpoint. - - - -
-
- - setForkSessionName(e.target.value)} - onKeyPress={(e) => { - if (e.key === "Enter" && !isLoading) { - handleConfirmFork(); - } - }} - /> -
-
- - - - - -
-
- - {/* Settings Dialog */} - {showSettings && effectiveSession && ( - - - setShowSettings(false)} - /> - - - )} + {/* Timeline Content */} +
+ +
+
+
+ )} +
+
- {/* Slash Commands Settings Dialog */} - {showSlashCommandsSettings && ( - - + {/* Fork Dialog */} + + - Slash Commands + Fork Session - Manage project-specific slash commands for {projectPath} + Create a new session branch from the selected checkpoint. -
- + +
+
+ + setForkSessionName(e.target.value)} + onKeyPress={(e) => { + if (e.key === "Enter" && !isLoading) { + handleConfirmFork(); + } + }} + /> +
+ + + + +
- )} + + {/* Settings Dialog */} + {showSettings && effectiveSession && ( + + + setShowSettings(false)} + /> + + + )} + + {/* Slash Commands Settings Dialog */} + {showSlashCommandsSettings && ( + + + + Slash Commands + + Manage project-specific slash commands for {projectPath} + + +
+ +
+
+
+ )}
); diff --git a/src/components/ClaudeFileEditor.tsx b/src/components/ClaudeFileEditor.tsx index 252e3e7bc..9d455de28 100644 --- a/src/components/ClaudeFileEditor.tsx +++ b/src/components/ClaudeFileEditor.tsx @@ -24,11 +24,11 @@ interface ClaudeFileEditorProps { /** * ClaudeFileEditor component for editing project-specific CLAUDE.md files - * + * * @example - * setEditingFile(null)} + * setEditingFile(null)} * /> */ export const ClaudeFileEditor: React.FC = ({ @@ -41,15 +41,18 @@ export const ClaudeFileEditor: React.FC = ({ const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); - const [toast, setToast] = useState<{ message: string; type: "success" | "error" } | null>(null); - + const [toast, setToast] = useState<{ + message: string; + type: "success" | "error"; + } | null>(null); + const hasChanges = content !== originalContent; - + // Load the file content on mount useEffect(() => { loadFileContent(); }, [file.absolute_path]); - + const loadFileContent = async () => { try { setLoading(true); @@ -64,7 +67,7 @@ export const ClaudeFileEditor: React.FC = ({ setLoading(false); } }; - + const handleSave = async () => { try { setSaving(true); @@ -81,17 +84,17 @@ export const ClaudeFileEditor: React.FC = ({ setSaving(false); } }; - + const handleBack = () => { if (hasChanges) { const confirmLeave = window.confirm( - "You have unsaved changes. Are you sure you want to leave?" + "You have unsaved changes. Are you sure you want to leave?", ); if (!confirmLeave) return; } onBack(); }; - + return (
@@ -112,13 +115,15 @@ export const ClaudeFileEditor: React.FC = ({
-

{file.relative_path}

+

+ {file.relative_path} +

Edit project-specific Claude Code system prompt

- + - + {/* Error display */} {error && ( = ({ {error} )} - + {/* Editor */}
{loading ? ( @@ -151,7 +156,10 @@ export const ClaudeFileEditor: React.FC = ({
) : ( -
+
setContent(val || "")} @@ -163,7 +171,7 @@ export const ClaudeFileEditor: React.FC = ({ )}
- + {/* Toast Notification */} {toast && ( @@ -176,4 +184,4 @@ export const ClaudeFileEditor: React.FC = ({
); -}; \ No newline at end of file +}; diff --git a/src/components/ClaudeMemoriesDropdown.tsx b/src/components/ClaudeMemoriesDropdown.tsx index da4c8037e..c2c9cbb6a 100644 --- a/src/components/ClaudeMemoriesDropdown.tsx +++ b/src/components/ClaudeMemoriesDropdown.tsx @@ -24,7 +24,7 @@ interface ClaudeMemoriesDropdownProps { /** * ClaudeMemoriesDropdown component - Shows all CLAUDE.md files in a project - * + * * @example * = ({ const [files, setFiles] = useState([]); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); - + // Load CLAUDE.md files when dropdown opens useEffect(() => { if (isOpen && files.length === 0) { loadClaudeMdFiles(); } }, [isOpen]); - + const loadClaudeMdFiles = async () => { try { setLoading(true); @@ -61,13 +61,13 @@ export const ClaudeMemoriesDropdown: React.FC = ({ setLoading(false); } }; - + const formatFileSize = (bytes: number): string => { if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; }; - + return (
@@ -80,7 +80,9 @@ export const ClaudeMemoriesDropdown: React.FC = ({ CLAUDE.md Memories {files.length > 0 && !loading && ( - ({files.length}) + + ({files.length}) + )}
= ({ - + {/* Dropdown Content */} {isOpen && ( @@ -123,7 +125,9 @@ export const ClaudeMemoriesDropdown: React.FC = ({ className="flex items-center justify-between p-3 hover:bg-accent/50 transition-colors border-b border-border last:border-b-0" >
-

{file.relative_path}

+

+ {file.relative_path} +

{formatFileSize(file.size)} @@ -155,4 +159,4 @@ export const ClaudeMemoriesDropdown: React.FC = ({
); -}; \ No newline at end of file +}; diff --git a/src/components/ClaudeVersionSelector.tsx b/src/components/ClaudeVersionSelector.tsx index d78ac370c..129351aa4 100644 --- a/src/components/ClaudeVersionSelector.tsx +++ b/src/components/ClaudeVersionSelector.tsx @@ -1,8 +1,20 @@ import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; import { Badge } from "@/components/ui/badge"; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; import { Label } from "@/components/ui/label"; import { api, type ClaudeInstallation } from "@/lib/api"; import { cn } from "@/lib/utils"; @@ -42,7 +54,7 @@ interface ClaudeVersionSelectorProps { /** * ClaudeVersionSelector component for selecting Claude Code installations * Supports system installations and user preferences - * + * * @example * = ({ const [installations, setInstallations] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [selectedInstallation, setSelectedInstallation] = useState(null); + const [selectedInstallation, setSelectedInstallation] = + useState(null); useEffect(() => { loadInstallations(); @@ -70,7 +83,7 @@ export const ClaudeVersionSelector: React.FC = ({ useEffect(() => { // Update selected installation when selectedPath changes if (selectedPath && installations.length > 0) { - const found = installations.find(i => i.path === selectedPath); + const found = installations.find((i) => i.path === selectedPath); if (found) { setSelectedInstallation(found); } @@ -83,10 +96,10 @@ export const ClaudeVersionSelector: React.FC = ({ setError(null); const foundInstallations = await api.listClaudeInstallations(); setInstallations(foundInstallations); - + // If we have a selected path, find and select it if (selectedPath) { - const found = foundInstallations.find(i => i.path === selectedPath); + const found = foundInstallations.find((i) => i.path === selectedPath); if (found) { setSelectedInstallation(found); } @@ -97,14 +110,18 @@ export const ClaudeVersionSelector: React.FC = ({ } } catch (err) { console.error("Failed to load Claude installations:", err); - setError(err instanceof Error ? err.message : "Failed to load Claude installations"); + setError( + err instanceof Error + ? err.message + : "Failed to load Claude installations", + ); } finally { setLoading(false); } }; const handleInstallationChange = (installationPath: string) => { - const installation = installations.find(i => i.path === installationPath); + const installation = installations.find((i) => i.path === installationPath); if (installation) { setSelectedInstallation(installation); onSelect(installation); @@ -189,8 +206,12 @@ export const ClaudeVersionSelector: React.FC = ({ ); } - const systemInstallations = installations.filter(i => i.installation_type === "System"); - const customInstallations = installations.filter(i => i.installation_type === "Custom"); + const systemInstallations = installations.filter( + (i) => i.installation_type === "System", + ); + const customInstallations = installations.filter( + (i) => i.installation_type === "Custom", + ); // Simplified mode - more streamlined UI if (simplified) { @@ -198,27 +219,43 @@ export const ClaudeVersionSelector: React.FC = ({
- +

Select which version of Claude to use

{selectedInstallation && ( - + {selectedInstallation.installation_type} )}
- - {selectedInstallation && (
- {selectedInstallation.path.split('/').pop() || selectedInstallation.path} + + {selectedInstallation.path.split("/").pop() || + selectedInstallation.path} + {selectedInstallation.version && ( - ({selectedInstallation.version}) + + ({selectedInstallation.version}) + )}
)} @@ -232,16 +269,27 @@ export const ClaudeVersionSelector: React.FC = ({ ) : ( <> {installations.map((installation) => ( - +
-
{installation.path}
+
+ {installation.path} +
- {installation.version || "Unknown version"} + + {installation.version || "Unknown version"} + • {installation.source} - + {installation.installation_type}
@@ -253,12 +301,13 @@ export const ClaudeVersionSelector: React.FC = ({ )} - + {selectedInstallation && (
- Path: {selectedInstallation.path} + Path:{" "} + {selectedInstallation.path}
)} @@ -282,14 +331,22 @@ export const ClaudeVersionSelector: React.FC = ({ {/* Available Installations */}
- {selectedInstallation && (
{getInstallationIcon(selectedInstallation)} - {selectedInstallation.path} - + + {selectedInstallation.path} + + {selectedInstallation.installation_type}
@@ -299,15 +356,24 @@ export const ClaudeVersionSelector: React.FC = ({ {systemInstallations.length > 0 && ( <> -
System Installations
+
+ System Installations +
{systemInstallations.map((installation) => ( - +
{getInstallationIcon(installation)}
-
{installation.path}
+
+ {installation.path} +
- {installation.version || "Version unknown"} • {installation.source} + {installation.version || "Version unknown"} •{" "} + {installation.source}
@@ -321,15 +387,24 @@ export const ClaudeVersionSelector: React.FC = ({ {customInstallations.length > 0 && ( <> -
Custom Installations
+
+ Custom Installations +
{customInstallations.map((installation) => ( - +
{getInstallationIcon(installation)}
-
{installation.path}
+
+ {installation.path} +
- {installation.version || "Version unknown"} • {installation.source} + {installation.version || "Version unknown"} •{" "} + {installation.source}
@@ -349,15 +424,24 @@ export const ClaudeVersionSelector: React.FC = ({
Selected Installation - + {selectedInstallation.installation_type}
-
Path: {selectedInstallation.path}
-
Source: {selectedInstallation.source}
+
+ Path: {selectedInstallation.path} +
+
+ Source: {selectedInstallation.source} +
{selectedInstallation.version && ( -
Version: {selectedInstallation.version}
+
+ Version: {selectedInstallation.version} +
)}
@@ -365,8 +449,8 @@ export const ClaudeVersionSelector: React.FC = ({ {/* Save Button */} {showSaveButton && ( -
- + = ({
- + {/* Error display */} {error && ( = ({ {error} )} - + {/* Content */}
@@ -200,7 +219,12 @@ export const CreateAgent: React.FC = ({
- + = ({ className="h-9" />
- +
- + = ({ {/* Model Selection */}
- +
= ({ transition={{ duration: 0.15 }} className={cn( "flex-1 px-4 py-3 rounded-md border transition-all", - model === "sonnet" - ? "border-primary bg-primary/10 text-primary" - : "border-border hover:border-primary/50 hover:bg-accent" + model === "sonnet" + ? "border-primary bg-primary/10 text-primary" + : "border-border hover:border-primary/50 hover:bg-accent", )} >
- +
-
Claude 4 Sonnet
-
Faster, efficient for most tasks
+
+ Claude 4 Sonnet +
+
+ Faster, efficient for most tasks +
- + setModel("opus")} @@ -270,19 +306,27 @@ export const CreateAgent: React.FC = ({ transition={{ duration: 0.15 }} className={cn( "flex-1 px-4 py-3 rounded-md border transition-all", - model === "opus" - ? "border-primary bg-primary/10 text-primary" - : "border-border hover:border-primary/50 hover:bg-accent" + model === "opus" + ? "border-primary bg-primary/10 text-primary" + : "border-border hover:border-primary/50 hover:bg-accent", )} >
- +
-
Claude 4 Opus
-
More capable, better for complex tasks
+
+ Claude 4 Opus +
+
+ More capable, better for complex tasks +
@@ -294,7 +338,12 @@ export const CreateAgent: React.FC = ({

Configuration

- + = ({ className="h-9" />

- This will be used as the default task placeholder when executing the agent + This will be used as the default task placeholder when + executing the agent

@@ -317,7 +367,10 @@ export const CreateAgent: React.FC = ({ Define the behavior and capabilities of your Claude Code agent

-
+
setSystemPrompt(val || "")} @@ -330,7 +383,7 @@ export const CreateAgent: React.FC = ({
- + {/* Toast Notification */} {toast && ( @@ -354,4 +407,4 @@ export const CreateAgent: React.FC = ({ />
); -}; +}; diff --git a/src/components/CustomTitlebar.tsx b/src/components/CustomTitlebar.tsx index 3342959b0..03a7d2513 100644 --- a/src/components/CustomTitlebar.tsx +++ b/src/components/CustomTitlebar.tsx @@ -1,8 +1,19 @@ -import React, { useState, useRef, useEffect } from 'react'; -import { motion } from 'framer-motion'; -import { Settings, Minus, Square, X, Bot, BarChart3, FileText, Network, Info, MoreVertical } from 'lucide-react'; -import { getCurrentWindow } from '@tauri-apps/api/window'; -import { TooltipProvider, TooltipSimple } from '@/components/ui/tooltip-modern'; +import React, { useState, useRef, useEffect } from "react"; +import { motion } from "framer-motion"; +import { + Settings, + Minus, + Square, + X, + Bot, + BarChart3, + FileText, + Network, + Info, + MoreVertical, +} from "lucide-react"; +import { getCurrentWindow } from "@tauri-apps/api/window"; +import { TooltipProvider, TooltipSimple } from "@/components/ui/tooltip-modern"; interface CustomTitlebarProps { onSettingsClick?: () => void; @@ -19,7 +30,7 @@ export const CustomTitlebar: React.FC = ({ onUsageClick, onClaudeClick, onMCPClick, - onInfoClick + onInfoClick, }) => { const [isHovered, setIsHovered] = useState(false); const [isDropdownOpen, setIsDropdownOpen] = useState(false); @@ -27,22 +38,25 @@ export const CustomTitlebar: React.FC = ({ useEffect(() => { const handleClickOutside = (event: MouseEvent) => { - if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { setIsDropdownOpen(false); } }; - document.addEventListener('mousedown', handleClickOutside); - return () => document.removeEventListener('mousedown', handleClickOutside); + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); }, []); const handleMinimize = async () => { try { const window = getCurrentWindow(); await window.minimize(); - console.log('Window minimized successfully'); + console.log("Window minimized successfully"); } catch (error) { - console.error('Failed to minimize window:', error); + console.error("Failed to minimize window:", error); } }; @@ -52,13 +66,13 @@ export const CustomTitlebar: React.FC = ({ const isMaximized = await window.isMaximized(); if (isMaximized) { await window.unmaximize(); - console.log('Window unmaximized successfully'); + console.log("Window unmaximized successfully"); } else { await window.maximize(); - console.log('Window maximized successfully'); + console.log("Window maximized successfully"); } } catch (error) { - console.error('Failed to maximize/unmaximize window:', error); + console.error("Failed to maximize/unmaximize window:", error); } }; @@ -66,185 +80,194 @@ export const CustomTitlebar: React.FC = ({ try { const window = getCurrentWindow(); await window.close(); - console.log('Window closed successfully'); + console.log("Window closed successfully"); } catch (error) { - console.error('Failed to close window:', error); + console.error("Failed to close window:", error); } }; return ( -
setIsHovered(true)} - onMouseLeave={() => setIsHovered(false)} - > - {/* Left side - macOS Traffic Light buttons */} -
-
- {/* Close button */} - - - {/* Minimize button */} - - - {/* Maximize button */} - +
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + > + {/* Left side - macOS Traffic Light buttons */} +
+
+ {/* Close button */} + + + {/* Minimize button */} + + + {/* Maximize button */} + +
-
- {/* Center - Title (hidden) */} - {/*
{title}
*/} - {/* Right side - Navigation icons with improved spacing */} -
- {/* Primary actions group */} -
- {onAgentsClick && ( - - - - - - )} - - {onUsageClick && ( - - - - - - )} -
+ {/* Right side - Navigation icons with improved spacing */} +
+ {/* Primary actions group */} +
+ {onAgentsClick && ( + + + + + + )} - {/* Visual separator */} -
- - {/* Secondary actions group */} -
- {onSettingsClick && ( - - - - - - )} - - {/* Dropdown menu for additional options */} -
- - setIsDropdownOpen(!isDropdownOpen)} - whileTap={{ scale: 0.97 }} - transition={{ duration: 0.15 }} - className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors flex items-center gap-1" - > - - - - - {isDropdownOpen && ( -
-
- {onClaudeClick && ( - - )} - - {onMCPClick && ( - - )} - - {onInfoClick && ( - - )} -
-
+ {onUsageClick && ( + + + + + + )} +
+ + {/* Visual separator */} +
+ + {/* Secondary actions group */} +
+ {onSettingsClick && ( + + + + + )} + + {/* Dropdown menu for additional options */} +
+ + setIsDropdownOpen(!isDropdownOpen)} + whileTap={{ scale: 0.97 }} + transition={{ duration: 0.15 }} + className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors flex items-center gap-1" + > + + + + + {isDropdownOpen && ( +
+
+ {onClaudeClick && ( + + )} + + {onMCPClick && ( + + )} + + {onInfoClick && ( + + )} +
+
+ )} +
-
); }; diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx index 591c99e37..cf5136a9c 100644 --- a/src/components/ErrorBoundary.tsx +++ b/src/components/ErrorBoundary.tsx @@ -16,7 +16,10 @@ interface ErrorBoundaryState { /** * Error Boundary component to catch and display React rendering errors */ -export class ErrorBoundary extends Component { +export class ErrorBoundary extends Component< + ErrorBoundaryProps, + ErrorBoundaryState +> { constructor(props: ErrorBoundaryProps) { super(props); this.state = { hasError: false, error: null }; @@ -51,7 +54,9 @@ export class ErrorBoundary extends Component
-

Something went wrong

+

+ Something went wrong +

An error occurred while rendering this component.

@@ -65,11 +70,7 @@ export class ErrorBoundary extends Component )} -
@@ -82,4 +83,4 @@ export class ErrorBoundary extends Component = ({ - isExecuting, - onStop, +export const ExecutionControlBar: React.FC = ({ + isExecuting, + onStop, totalTokens = 0, elapsedTime = 0, - className + className, }) => { // Format elapsed time const formatTime = (seconds: number) => { @@ -53,7 +53,7 @@ export const ExecutionControlBar: React.FC = ({ "fixed bottom-6 left-1/2 -translate-x-1/2 z-50", "bg-background/95 backdrop-blur-md border rounded-full shadow-lg", "px-6 py-3 flex items-center gap-4", - className + className, )} > {/* Rotating symbol indicator */} @@ -99,4 +99,4 @@ export const ExecutionControlBar: React.FC = ({ )} ); -}; \ No newline at end of file +}; diff --git a/src/components/FilePicker.optimized.tsx b/src/components/FilePicker.optimized.tsx index 4169e79b9..a6490565a 100644 --- a/src/components/FilePicker.optimized.tsx +++ b/src/components/FilePicker.optimized.tsx @@ -1,18 +1,24 @@ -import React, { useState, useEffect, useRef, useCallback, useMemo } from "react"; +import React, { + useState, + useEffect, + useRef, + useCallback, + useMemo, +} from "react"; import { motion } from "framer-motion"; import { useVirtualizer } from "@tanstack/react-virtual"; import { Button } from "@/components/ui/button"; import { api } from "@/lib/api"; -import { - X, - Folder, - File, +import { + X, + Folder, + File, ArrowLeft, FileCode, FileText, FileImage, Search, - ChevronRight + ChevronRight, } from "lucide-react"; import type { FileEntry } from "@/lib/api"; import { cn } from "@/lib/utils"; @@ -33,33 +39,33 @@ interface FilePickerProps { // Memoized file icon selector const getFileIcon = (entry: FileEntry) => { if (entry.is_directory) return Folder; - - const ext = entry.name.split('.').pop()?.toLowerCase(); + + const ext = entry.name.split(".").pop()?.toLowerCase(); switch (ext) { - case 'js': - case 'jsx': - case 'ts': - case 'tsx': - case 'py': - case 'java': - case 'cpp': - case 'c': - case 'go': - case 'rs': + case "js": + case "jsx": + case "ts": + case "tsx": + case "py": + case "java": + case "cpp": + case "c": + case "go": + case "rs": return FileCode; - case 'md': - case 'txt': - case 'json': - case 'xml': - case 'yaml': - case 'yml': + case "md": + case "txt": + case "json": + case "xml": + case "yaml": + case "yml": return FileText; - case 'png': - case 'jpg': - case 'jpeg': - case 'gif': - case 'svg': - case 'webp': + case "png": + case "jpg": + case "jpeg": + case "gif": + case "svg": + case "webp": return FileImage; default: return File; @@ -67,350 +73,385 @@ const getFileIcon = (entry: FileEntry) => { }; const formatFileSize = (bytes: number): string => { - if (bytes === 0) return '0 B'; + if (bytes === 0) return "0 B"; const k = 1024; - const sizes = ['B', 'KB', 'MB', 'GB']; + const sizes = ["B", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${(bytes / Math.pow(k, i)).toFixed(1)} ${sizes[i]}`; }; -export const FilePicker: React.FC = React.memo(({ - basePath, - onSelect, - onClose, - initialQuery = "", - className, - allowDirectorySelection = false -}) => { - const [currentPath, setCurrentPath] = useState(basePath); - const [entries, setEntries] = useState([]); - const [searchQuery, setSearchQuery] = useState(initialQuery); - const [selectedIndex, setSelectedIndex] = useState(0); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - const searchInputRef = useRef(null); - const scrollContainerRef = useRef(null); - const searchDebounceRef = useRef(); - - // Filter and sort entries - const displayEntries = useMemo(() => { - const filtered = searchQuery.trim() - ? entries.filter(entry => - entry.name.toLowerCase().includes(searchQuery.toLowerCase()) - ) - : entries; - - return filtered.sort((a, b) => { - if (a.is_directory !== b.is_directory) { - return a.is_directory ? -1 : 1; - } - return a.name.localeCompare(b.name); +export const FilePicker: React.FC = React.memo( + ({ + basePath, + onSelect, + onClose, + initialQuery = "", + className, + allowDirectorySelection = false, + }) => { + const [currentPath, setCurrentPath] = useState(basePath); + const [entries, setEntries] = useState([]); + const [searchQuery, setSearchQuery] = useState(initialQuery); + const [selectedIndex, setSelectedIndex] = useState(0); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + + const searchInputRef = useRef(null); + const scrollContainerRef = useRef(null); + const searchDebounceRef = useRef(); + + // Filter and sort entries + const displayEntries = useMemo(() => { + const filtered = searchQuery.trim() + ? entries.filter((entry) => + entry.name.toLowerCase().includes(searchQuery.toLowerCase()), + ) + : entries; + + return filtered.sort((a, b) => { + if (a.is_directory !== b.is_directory) { + return a.is_directory ? -1 : 1; + } + return a.name.localeCompare(b.name); + }); + }, [entries, searchQuery]); + + // Virtual scrolling setup + const virtualizer = useVirtualizer({ + count: displayEntries.length, + getScrollElement: () => scrollContainerRef.current, + estimateSize: () => 32, // Height of each item + overscan: 10, // Number of items to render outside viewport }); - }, [entries, searchQuery]); - - // Virtual scrolling setup - const virtualizer = useVirtualizer({ - count: displayEntries.length, - getScrollElement: () => scrollContainerRef.current, - estimateSize: () => 32, // Height of each item - overscan: 10, // Number of items to render outside viewport - }); - - const virtualItems = virtualizer.getVirtualItems(); - - // Load directory contents - const loadDirectory = useCallback(async (path: string) => { - const cacheKey = path; - - // Check cache first - if (globalDirectoryCache.has(cacheKey)) { - setEntries(globalDirectoryCache.get(cacheKey)!); - return; - } - - setIsLoading(true); - setError(null); - - try { - const result = await api.listDirectoryContents(path); - globalDirectoryCache.set(cacheKey, result); - setEntries(result); - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to load directory'); - } finally { - setIsLoading(false); - } - }, []); - - // Search functionality - const performSearch = useCallback(async (query: string) => { - if (!query.trim()) { - loadDirectory(currentPath); - return; - } - - const cacheKey = `${currentPath}:${query}`; - - if (globalSearchCache.has(cacheKey)) { - setEntries(globalSearchCache.get(cacheKey)!); - return; - } - - setIsLoading(true); - setError(null); - - try { - const result = await api.searchFiles(currentPath, query); - globalSearchCache.set(cacheKey, result); - setEntries(result); - } catch (err) { - setError(err instanceof Error ? err.message : 'Search failed'); - } finally { - setIsLoading(false); - } - }, [currentPath, loadDirectory]); - - // Handle entry click - const handleEntryClick = useCallback((entry: FileEntry) => { - if (!entry.is_directory || allowDirectorySelection) { - onSelect(entry); - } - }, [onSelect, allowDirectorySelection]); - - // Handle entry double click - const handleEntryDoubleClick = useCallback((entry: FileEntry) => { - if (entry.is_directory) { - setCurrentPath(entry.path); - setSearchQuery(""); - setSelectedIndex(0); - } else { - onSelect(entry); - } - }, [onSelect]); - - // Keyboard navigation - const handleKeyDown = useCallback((e: React.KeyboardEvent) => { - if (displayEntries.length === 0) return; - - switch (e.key) { - case 'ArrowUp': - e.preventDefault(); - setSelectedIndex(prev => Math.max(0, prev - 1)); - break; - case 'ArrowDown': - e.preventDefault(); - setSelectedIndex(prev => Math.min(displayEntries.length - 1, prev + 1)); - break; - case 'Enter': - e.preventDefault(); - const selectedEntry = displayEntries[selectedIndex]; - if (selectedEntry) { - if (e.shiftKey || !selectedEntry.is_directory) { - handleEntryClick(selectedEntry); - } else { - handleEntryDoubleClick(selectedEntry); - } + + const virtualItems = virtualizer.getVirtualItems(); + + // Load directory contents + const loadDirectory = useCallback(async (path: string) => { + const cacheKey = path; + + // Check cache first + if (globalDirectoryCache.has(cacheKey)) { + setEntries(globalDirectoryCache.get(cacheKey)!); + return; + } + + setIsLoading(true); + setError(null); + + try { + const result = await api.listDirectoryContents(path); + globalDirectoryCache.set(cacheKey, result); + setEntries(result); + } catch (err) { + setError( + err instanceof Error ? err.message : "Failed to load directory", + ); + } finally { + setIsLoading(false); + } + }, []); + + // Search functionality + const performSearch = useCallback( + async (query: string) => { + if (!query.trim()) { + loadDirectory(currentPath); + return; + } + + const cacheKey = `${currentPath}:${query}`; + + if (globalSearchCache.has(cacheKey)) { + setEntries(globalSearchCache.get(cacheKey)!); + return; + } + + setIsLoading(true); + setError(null); + + try { + const result = await api.searchFiles(currentPath, query); + globalSearchCache.set(cacheKey, result); + setEntries(result); + } catch (err) { + setError(err instanceof Error ? err.message : "Search failed"); + } finally { + setIsLoading(false); + } + }, + [currentPath, loadDirectory], + ); + + // Handle entry click + const handleEntryClick = useCallback( + (entry: FileEntry) => { + if (!entry.is_directory || allowDirectorySelection) { + onSelect(entry); + } + }, + [onSelect, allowDirectorySelection], + ); + + // Handle entry double click + const handleEntryDoubleClick = useCallback( + (entry: FileEntry) => { + if (entry.is_directory) { + setCurrentPath(entry.path); + setSearchQuery(""); + setSelectedIndex(0); + } else { + onSelect(entry); } - break; - case 'Escape': - e.preventDefault(); - onClose(); - break; - } - }, [displayEntries, selectedIndex, handleEntryClick, handleEntryDoubleClick, onClose]); - - // Debounced search - useEffect(() => { - if (searchDebounceRef.current) { - clearTimeout(searchDebounceRef.current); - } - - searchDebounceRef.current = setTimeout(() => { - performSearch(searchQuery); - }, 300); - - return () => { + }, + [onSelect], + ); + + // Keyboard navigation + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (displayEntries.length === 0) return; + + switch (e.key) { + case "ArrowUp": + e.preventDefault(); + setSelectedIndex((prev) => Math.max(0, prev - 1)); + break; + case "ArrowDown": + e.preventDefault(); + setSelectedIndex((prev) => + Math.min(displayEntries.length - 1, prev + 1), + ); + break; + case "Enter": + e.preventDefault(); + const selectedEntry = displayEntries[selectedIndex]; + if (selectedEntry) { + if (e.shiftKey || !selectedEntry.is_directory) { + handleEntryClick(selectedEntry); + } else { + handleEntryDoubleClick(selectedEntry); + } + } + break; + case "Escape": + e.preventDefault(); + onClose(); + break; + } + }, + [ + displayEntries, + selectedIndex, + handleEntryClick, + handleEntryDoubleClick, + onClose, + ], + ); + + // Debounced search + useEffect(() => { if (searchDebounceRef.current) { clearTimeout(searchDebounceRef.current); } - }; - }, [searchQuery, performSearch]); - - // Load initial directory - useEffect(() => { - loadDirectory(currentPath); - }, [currentPath, loadDirectory]); - - // Focus search input on mount - useEffect(() => { - searchInputRef.current?.focus(); - }, []); - - // Scroll selected item into view - useEffect(() => { - const item = virtualizer.getVirtualItems().find( - vItem => vItem.index === selectedIndex - ); - if (item) { - virtualizer.scrollToIndex(selectedIndex, { align: 'center' }); - } - }, [selectedIndex, virtualizer]); - - return ( - - {/* Header */} -
- - -
- - setSearchQuery(e.target.value)} - placeholder="Search files..." - className="flex-1 bg-transparent outline-none text-sm" - /> -
- -
- - {/* Current path */} -
-
- {currentPath} -
-
+ searchDebounceRef.current = setTimeout(() => { + performSearch(searchQuery); + }, 300); - {/* File list with virtual scrolling */} -
- {isLoading && ( -
-
Loading...
-
- )} + return () => { + if (searchDebounceRef.current) { + clearTimeout(searchDebounceRef.current); + } + }; + }, [searchQuery, performSearch]); - {error && ( -
-
{error}
-
+ // Load initial directory + useEffect(() => { + loadDirectory(currentPath); + }, [currentPath, loadDirectory]); + + // Focus search input on mount + useEffect(() => { + searchInputRef.current?.focus(); + }, []); + + // Scroll selected item into view + useEffect(() => { + const item = virtualizer + .getVirtualItems() + .find((vItem) => vItem.index === selectedIndex); + if (item) { + virtualizer.scrollToIndex(selectedIndex, { align: "center" }); + } + }, [selectedIndex, virtualizer]); + + return ( + - - - {searchQuery.trim() ? 'No files found' : 'Empty directory'} - + onKeyDown={handleKeyDown} + > + {/* Header */} +
+ + +
+ + setSearchQuery(e.target.value)} + placeholder="Search files..." + className="flex-1 bg-transparent outline-none text-sm" + />
- )} - {displayEntries.length > 0 && ( -
- {virtualItems.map((virtualRow) => { - const entry = displayEntries[virtualRow.index]; - const Icon = getFileIcon(entry); - const isSelected = virtualRow.index === selectedIndex; - - return ( -
- -
- ); - })} + + +
+ + {/* Current path */} +
+
+ {currentPath}
- )} -
+
- {/* Footer */} -
-
- {displayEntries.length} {displayEntries.length === 1 ? 'item' : 'items'} + {/* File list with virtual scrolling */} +
+ {isLoading && ( +
+
Loading...
+
+ )} + + {error && ( +
+
{error}
+
+ )} + + {!isLoading && !error && displayEntries.length === 0 && ( +
+ + + {searchQuery.trim() ? "No files found" : "Empty directory"} + +
+ )} + + {displayEntries.length > 0 && ( +
+ {virtualItems.map((virtualRow) => { + const entry = displayEntries[virtualRow.index]; + const Icon = getFileIcon(entry); + const isSelected = virtualRow.index === selectedIndex; + + return ( +
+ +
+ ); + })} +
+ )}
- {allowDirectorySelection && ( + + {/* Footer */} +
- Shift+Enter to select directory + {displayEntries.length}{" "} + {displayEntries.length === 1 ? "item" : "items"}
- )} -
- - ); -}); \ No newline at end of file + {allowDirectorySelection && ( +
+ Shift+Enter to select directory +
+ )} +
+ + ); + }, +); diff --git a/src/components/FilePicker.tsx b/src/components/FilePicker.tsx index 3038df4e1..0ec093cc6 100644 --- a/src/components/FilePicker.tsx +++ b/src/components/FilePicker.tsx @@ -2,16 +2,16 @@ import React, { useState, useEffect, useRef } from "react"; import { motion } from "framer-motion"; import { Button } from "@/components/ui/button"; import { api } from "@/lib/api"; -import { - X, - Folder, - File, +import { + X, + Folder, + File, ArrowLeft, FileCode, FileText, FileImage, Search, - ChevronRight + ChevronRight, } from "lucide-react"; import type { FileEntry } from "@/lib/api"; import { cn } from "@/lib/utils"; @@ -53,40 +53,58 @@ interface FilePickerProps { // File icon mapping based on extension const getFileIcon = (entry: FileEntry) => { if (entry.is_directory) return Folder; - + const ext = entry.extension?.toLowerCase(); if (!ext) return File; - + // Code files - if (['ts', 'tsx', 'js', 'jsx', 'py', 'rs', 'go', 'java', 'cpp', 'c', 'h'].includes(ext)) { + if ( + [ + "ts", + "tsx", + "js", + "jsx", + "py", + "rs", + "go", + "java", + "cpp", + "c", + "h", + ].includes(ext) + ) { return FileCode; } - + // Text/Markdown files - if (['md', 'txt', 'json', 'yaml', 'yml', 'toml', 'xml', 'html', 'css'].includes(ext)) { + if ( + ["md", "txt", "json", "yaml", "yml", "toml", "xml", "html", "css"].includes( + ext, + ) + ) { return FileText; } - + // Image files - if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'ico'].includes(ext)) { + if (["png", "jpg", "jpeg", "gif", "svg", "webp", "ico"].includes(ext)) { return FileImage; } - + return File; }; // Format file size to human readable const formatFileSize = (bytes: number): string => { - if (bytes === 0) return ''; + if (bytes === 0) return ""; const k = 1024; - const sizes = ['B', 'KB', 'MB', 'GB']; + const sizes = ["B", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`; }; /** * FilePicker component - File browser with fuzzy search - * + * * @example * = ({ className, }) => { const searchQuery = initialQuery; - + const [currentPath, setCurrentPath] = useState(basePath); - const [entries, setEntries] = useState(() => - searchQuery.trim() ? [] : globalDirectoryCache.get(basePath) || [] + const [entries, setEntries] = useState(() => + searchQuery.trim() ? [] : globalDirectoryCache.get(basePath) || [], ); const [searchResults, setSearchResults] = useState(() => { if (searchQuery.trim()) { @@ -126,17 +144,17 @@ export const FilePicker: React.FC = ({ } return globalDirectoryCache.has(basePath); }); - + const searchDebounceRef = useRef(null); const fileListRef = useRef(null); - + // Computed values const displayEntries = searchQuery.trim() ? searchResults : entries; const canGoBack = pathHistory.length > 1; - + // Get relative path for display - const relativePath = currentPath.startsWith(basePath) - ? currentPath.slice(basePath.length) || '/' + const relativePath = currentPath.startsWith(basePath) + ? currentPath.slice(basePath.length) || "/" : currentPath; // Load directory contents @@ -152,15 +170,18 @@ export const FilePicker: React.FC = ({ if (searchQuery.trim()) { const cacheKey = `${basePath}:${searchQuery}`; - + // Immediately show cached results if available if (globalSearchCache.has(cacheKey)) { - console.log('[FilePicker] Immediately showing cached search results for:', searchQuery); + console.log( + "[FilePicker] Immediately showing cached search results for:", + searchQuery, + ); setSearchResults(globalSearchCache.get(cacheKey) || []); setIsShowingCached(true); setError(null); } - + // Schedule fresh search after debounce searchDebounceRef.current = setTimeout(() => { performSearch(searchQuery); @@ -186,43 +207,51 @@ export const FilePicker: React.FC = ({ useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { const displayEntries = searchQuery.trim() ? searchResults : entries; - + switch (e.key) { - case 'Escape': + case "Escape": e.preventDefault(); onClose(); break; - - case 'Enter': + + case "Enter": e.preventDefault(); // Enter always selects the current item (file or directory) - if (displayEntries.length > 0 && selectedIndex < displayEntries.length) { + if ( + displayEntries.length > 0 && + selectedIndex < displayEntries.length + ) { onSelect(displayEntries[selectedIndex]); } break; - - case 'ArrowUp': + + case "ArrowUp": e.preventDefault(); - setSelectedIndex(prev => Math.max(0, prev - 1)); + setSelectedIndex((prev) => Math.max(0, prev - 1)); break; - - case 'ArrowDown': + + case "ArrowDown": e.preventDefault(); - setSelectedIndex(prev => Math.min(displayEntries.length - 1, prev + 1)); + setSelectedIndex((prev) => + Math.min(displayEntries.length - 1, prev + 1), + ); break; - - case 'ArrowRight': + + case "ArrowRight": e.preventDefault(); // Right arrow enters directories - if (displayEntries.length > 0 && selectedIndex < displayEntries.length) { + if ( + displayEntries.length > 0 && + selectedIndex < displayEntries.length + ) { const entry = displayEntries[selectedIndex]; if (entry.is_directory) { navigateToDirectory(entry.path); } } break; - - case 'ArrowLeft': + + case "ArrowLeft": e.preventDefault(); // Left arrow goes back to parent directory if (canGoBack) { @@ -232,27 +261,32 @@ export const FilePicker: React.FC = ({ } }; - window.addEventListener('keydown', handleKeyDown); - return () => window.removeEventListener('keydown', handleKeyDown); + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); }, [entries, searchResults, selectedIndex, searchQuery, canGoBack]); // Scroll selected item into view useEffect(() => { if (fileListRef.current) { - const selectedElement = fileListRef.current.querySelector(`[data-index="${selectedIndex}"]`); + const selectedElement = fileListRef.current.querySelector( + `[data-index="${selectedIndex}"]`, + ); if (selectedElement) { - selectedElement.scrollIntoView({ block: 'nearest', behavior: 'smooth' }); + selectedElement.scrollIntoView({ + block: "nearest", + behavior: "smooth", + }); } } }, [selectedIndex]); const loadDirectory = async (path: string) => { try { - console.log('[FilePicker] Loading directory:', path); - + console.log("[FilePicker] Loading directory:", path); + // Check cache first and show immediately if (globalDirectoryCache.has(path)) { - console.log('[FilePicker] Showing cached contents for:', path); + console.log("[FilePicker] Showing cached contents for:", path); setEntries(globalDirectoryCache.get(path) || []); setIsShowingCached(true); setError(null); @@ -260,24 +294,30 @@ export const FilePicker: React.FC = ({ // Only show loading if we don't have cached data setIsLoading(true); } - + // Always fetch fresh data in background const contents = await api.listDirectoryContents(path); - console.log('[FilePicker] Loaded fresh contents:', contents.length, 'items'); - + console.log( + "[FilePicker] Loaded fresh contents:", + contents.length, + "items", + ); + // Cache the results globalDirectoryCache.set(path, contents); - + // Update with fresh data setEntries(contents); setIsShowingCached(false); setError(null); } catch (err) { - console.error('[FilePicker] Failed to load directory:', path, err); - console.error('[FilePicker] Error details:', err); + console.error("[FilePicker] Failed to load directory:", path, err); + console.error("[FilePicker] Error details:", err); // Only set error if we don't have cached data to show if (!globalDirectoryCache.has(path)) { - setError(err instanceof Error ? err.message : 'Failed to load directory'); + setError( + err instanceof Error ? err.message : "Failed to load directory", + ); } } finally { setIsLoading(false); @@ -286,14 +326,14 @@ export const FilePicker: React.FC = ({ const performSearch = async (query: string) => { try { - console.log('[FilePicker] Searching for:', query, 'in:', basePath); - + console.log("[FilePicker] Searching for:", query, "in:", basePath); + // Create cache key that includes both query and basePath const cacheKey = `${basePath}:${query}`; - + // Check cache first and show immediately if (globalSearchCache.has(cacheKey)) { - console.log('[FilePicker] Showing cached search results for:', query); + console.log("[FilePicker] Showing cached search results for:", query); setSearchResults(globalSearchCache.get(cacheKey) || []); setIsShowingCached(true); setError(null); @@ -301,24 +341,28 @@ export const FilePicker: React.FC = ({ // Only show loading if we don't have cached data setIsLoading(true); } - + // Always fetch fresh results in background const results = await api.searchFiles(basePath, query); - console.log('[FilePicker] Fresh search results:', results.length, 'items'); - + console.log( + "[FilePicker] Fresh search results:", + results.length, + "items", + ); + // Cache the results globalSearchCache.set(cacheKey, results); - + // Update with fresh results setSearchResults(results); setIsShowingCached(false); setError(null); } catch (err) { - console.error('[FilePicker] Search failed:', query, err); + console.error("[FilePicker] Search failed:", query, err); // Only set error if we don't have cached data to show const cacheKey = `${basePath}:${query}`; if (!globalSearchCache.has(cacheKey)) { - setError(err instanceof Error ? err.message : 'Search failed'); + setError(err instanceof Error ? err.message : "Search failed"); } } finally { setIsLoading(false); @@ -327,7 +371,7 @@ export const FilePicker: React.FC = ({ const navigateToDirectory = (path: string) => { setCurrentPath(path); - setPathHistory(prev => [...prev, path]); + setPathHistory((prev) => [...prev, path]); }; const navigateBack = () => { @@ -335,7 +379,7 @@ export const FilePicker: React.FC = ({ const newHistory = [...pathHistory]; newHistory.pop(); // Remove current const previousPath = newHistory[newHistory.length - 1]; - + // Don't go beyond the base path if (previousPath.startsWith(basePath) || previousPath === basePath) { setCurrentPath(previousPath); @@ -348,7 +392,7 @@ export const FilePicker: React.FC = ({ // Single click always selects (file or directory) onSelect(entry); }; - + const handleEntryDoubleClick = (entry: FileEntry) => { // Double click navigates into directories if (entry.is_directory) { @@ -366,7 +410,7 @@ export const FilePicker: React.FC = ({ "w-[500px] h-[400px]", "bg-background border border-border rounded-lg shadow-lg", "flex flex-col overflow-hidden", - className + className, )} > {/* Header */} @@ -423,7 +467,7 @@ export const FilePicker: React.FC = ({
- {searchQuery.trim() ? 'No files found' : 'Empty directory'} + {searchQuery.trim() ? "No files found" : "Empty directory"}
)} @@ -432,9 +476,9 @@ export const FilePicker: React.FC = ({
{displayEntries.map((entry, index) => { const Icon = getFileIcon(entry); - const isSearching = searchQuery.trim() !== ''; + const isSearching = searchQuery.trim() !== ""; const isSelected = index === selectedIndex; - + return ( @@ -489,4 +539,4 @@ export const FilePicker: React.FC = ({
); -}; \ No newline at end of file +}; diff --git a/src/components/FloatingPromptInput.tsx b/src/components/FloatingPromptInput.tsx index c3f5ea28c..ec3ca7dc0 100644 --- a/src/components/FloatingPromptInput.tsx +++ b/src/components/FloatingPromptInput.tsx @@ -12,13 +12,18 @@ import { Lightbulb, Cpu, Rocket, - } from "lucide-react"; import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; import { Popover } from "@/components/ui/popover"; import { Textarea } from "@/components/ui/textarea"; -import { TooltipProvider, TooltipSimple, Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip-modern"; +import { + TooltipProvider, + TooltipSimple, + Tooltip, + TooltipTrigger, + TooltipContent, +} from "@/components/ui/tooltip-modern"; import { FilePicker } from "./FilePicker"; import { SlashCommandPicker } from "./SlashCommandPicker"; import { ImagePreview } from "./ImagePreview"; @@ -67,7 +72,12 @@ export interface FloatingPromptInputRef { /** * Thinking mode type definition */ -type ThinkingMode = "auto" | "think" | "think_hard" | "think_harder" | "ultrathink"; +type ThinkingMode = + | "auto" + | "think" + | "think_hard" + | "think_harder" + | "ultrathink"; /** * Thinking mode configuration @@ -91,7 +101,7 @@ const THINKING_MODES: ThinkingModeConfig[] = [ level: 0, icon: , color: "text-muted-foreground", - shortName: "A" + shortName: "A", }, { id: "think", @@ -101,7 +111,7 @@ const THINKING_MODES: ThinkingModeConfig[] = [ phrase: "think", icon: , color: "text-primary", - shortName: "T" + shortName: "T", }, { id: "think_hard", @@ -111,7 +121,7 @@ const THINKING_MODES: ThinkingModeConfig[] = [ phrase: "think hard", icon: , color: "text-primary", - shortName: "T+" + shortName: "T+", }, { id: "think_harder", @@ -121,7 +131,7 @@ const THINKING_MODES: ThinkingModeConfig[] = [ phrase: "think harder", icon: , color: "text-primary", - shortName: "T++" + shortName: "T++", }, { id: "ultrathink", @@ -131,19 +141,22 @@ const THINKING_MODES: ThinkingModeConfig[] = [ phrase: "ultrathink", icon: , color: "text-primary", - shortName: "Ultra" - } + shortName: "Ultra", + }, ]; /** * ThinkingModeIndicator component - Shows visual indicator bars for thinking level */ -const ThinkingModeIndicator: React.FC<{ level: number; color?: string }> = ({ level, color: _color }) => { +const ThinkingModeIndicator: React.FC<{ level: number; color?: string }> = ({ + level, + color: _color, +}) => { const getBarColor = (barIndex: number) => { if (barIndex > level) return "bg-muted"; return "bg-primary"; }; - + return (
{[1, 2, 3, 4].map((i) => ( @@ -152,7 +165,7 @@ const ThinkingModeIndicator: React.FC<{ level: number; color?: string }> = ({ le className={cn( "w-1 h-3 rounded-full transition-all duration-200", getBarColor(i), - i <= level && "shadow-sm" + i <= level && "shadow-sm", )} /> ))} @@ -176,7 +189,7 @@ const MODELS: Model[] = [ description: "Faster, efficient for most tasks", icon: , shortName: "S", - color: "text-primary" + color: "text-primary", }, { id: "opus", @@ -184,13 +197,13 @@ const MODELS: Model[] = [ description: "More capable, better for complex tasks", icon: , shortName: "O", - color: "text-primary" - } + color: "text-primary", + }, ]; /** * FloatingPromptInput component - Fixed position prompt input with model picker - * + * * @example * const promptRef = useRef(null); * , ) => { const [prompt, setPrompt] = useState(""); - const [selectedModel, setSelectedModel] = useState<"sonnet" | "opus">(defaultModel); - const [selectedThinkingMode, setSelectedThinkingMode] = useState("auto"); + const [selectedModel, setSelectedModel] = useState<"sonnet" | "opus">( + defaultModel, + ); + const [selectedThinkingMode, setSelectedThinkingMode] = + useState("auto"); const [isExpanded, setIsExpanded] = useState(false); const [modelPickerOpen, setModelPickerOpen] = useState(false); const [thinkingModePickerOpen, setThinkingModePickerOpen] = useState(false); @@ -236,108 +252,132 @@ const FloatingPromptInputInner = ( ref, () => ({ addImage: (imagePath: string) => { - setPrompt(currentPrompt => { + setPrompt((currentPrompt) => { const existingPaths = extractImagePaths(currentPrompt); if (existingPaths.includes(imagePath)) { return currentPrompt; // Image already added } // Wrap path in quotes if it contains spaces - const mention = imagePath.includes(' ') ? `@"${imagePath}"` : `@${imagePath}`; - const newPrompt = currentPrompt + (currentPrompt.endsWith(' ') || currentPrompt === '' ? '' : ' ') + mention + ' '; + const mention = imagePath.includes(" ") + ? `@"${imagePath}"` + : `@${imagePath}`; + const newPrompt = + currentPrompt + + (currentPrompt.endsWith(" ") || currentPrompt === "" ? "" : " ") + + mention + + " "; // Focus the textarea setTimeout(() => { - const target = isExpanded ? expandedTextareaRef.current : textareaRef.current; + const target = isExpanded + ? expandedTextareaRef.current + : textareaRef.current; target?.focus(); target?.setSelectionRange(newPrompt.length, newPrompt.length); }, 0); return newPrompt; }); - } + }, }), - [isExpanded] + [isExpanded], ); // Helper function to check if a file is an image const isImageFile = (path: string): boolean => { // Check if it's a data URL - if (path.startsWith('data:image/')) { + if (path.startsWith("data:image/")) { return true; } // Otherwise check file extension - const ext = path.split('.').pop()?.toLowerCase(); - return ['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'ico', 'bmp'].includes(ext || ''); + const ext = path.split(".").pop()?.toLowerCase(); + return ["png", "jpg", "jpeg", "gif", "svg", "webp", "ico", "bmp"].includes( + ext || "", + ); }; // Extract image paths from prompt text const extractImagePaths = (text: string): string[] => { - console.log('[extractImagePaths] Input text length:', text.length); - + console.log("[extractImagePaths] Input text length:", text.length); + // Updated regex to handle both quoted and unquoted paths // Pattern 1: @"path with spaces or data URLs" - quoted paths // Pattern 2: @path - unquoted paths (continues until @ or end) const quotedRegex = /@"([^"]+)"/g; const unquotedRegex = /@([^@\n\s]+)/g; - + const pathsSet = new Set(); // Use Set to ensure uniqueness - + // First, extract quoted paths (including data URLs) let matches = Array.from(text.matchAll(quotedRegex)); - console.log('[extractImagePaths] Quoted matches:', matches.length); - + console.log("[extractImagePaths] Quoted matches:", matches.length); + for (const match of matches) { const path = match[1]; // No need to trim, quotes preserve exact path - console.log('[extractImagePaths] Processing quoted path:', path.startsWith('data:') ? 'data URL' : path); - + console.log( + "[extractImagePaths] Processing quoted path:", + path.startsWith("data:") ? "data URL" : path, + ); + // For data URLs, use as-is; for file paths, convert to absolute - const fullPath = path.startsWith('data:') - ? path - : (path.startsWith('/') ? path : (projectPath ? `${projectPath}/${path}` : path)); - + const fullPath = path.startsWith("data:") + ? path + : path.startsWith("/") + ? path + : projectPath + ? `${projectPath}/${path}` + : path; + if (isImageFile(fullPath)) { pathsSet.add(fullPath); } } - + // Remove quoted mentions from text to avoid double-matching - let textWithoutQuoted = text.replace(quotedRegex, ''); - + let textWithoutQuoted = text.replace(quotedRegex, ""); + // Then extract unquoted paths (typically file paths) matches = Array.from(textWithoutQuoted.matchAll(unquotedRegex)); - console.log('[extractImagePaths] Unquoted matches:', matches.length); - + console.log("[extractImagePaths] Unquoted matches:", matches.length); + for (const match of matches) { const path = match[1].trim(); // Skip if it looks like a data URL fragment (shouldn't happen with proper quoting) - if (path.includes('data:')) continue; - - console.log('[extractImagePaths] Processing unquoted path:', path); - + if (path.includes("data:")) continue; + + console.log("[extractImagePaths] Processing unquoted path:", path); + // Convert relative path to absolute if needed - const fullPath = path.startsWith('/') ? path : (projectPath ? `${projectPath}/${path}` : path); - + const fullPath = path.startsWith("/") + ? path + : projectPath + ? `${projectPath}/${path}` + : path; + if (isImageFile(fullPath)) { pathsSet.add(fullPath); } } const uniquePaths = Array.from(pathsSet); - console.log('[extractImagePaths] Final extracted paths (unique):', uniquePaths.length); + console.log( + "[extractImagePaths] Final extracted paths (unique):", + uniquePaths.length, + ); return uniquePaths; }; // Update embedded images when prompt changes useEffect(() => { - console.log('[useEffect] Prompt changed:', prompt); + console.log("[useEffect] Prompt changed:", prompt); const imagePaths = extractImagePaths(prompt); - console.log('[useEffect] Setting embeddedImages to:', imagePaths); + console.log("[useEffect] Setting embeddedImages to:", imagePaths); setEmbeddedImages(imagePaths); - + // Auto-resize on prompt change (handles paste, programmatic changes, etc.) if (textareaRef.current && !isExpanded) { - textareaRef.current.style.height = 'auto'; + textareaRef.current.style.height = "auto"; const scrollHeight = textareaRef.current.scrollHeight; const newHeight = Math.min(Math.max(scrollHeight, 48), 240); setTextareaHeight(newHeight); @@ -359,11 +399,11 @@ const FloatingPromptInputInner = ( const webview = getCurrentWebviewWindow(); unlistenDragDropRef.current = await webview.onDragDropEvent((event) => { - if (event.payload.type === 'enter' || event.payload.type === 'over') { + if (event.payload.type === "enter" || event.payload.type === "over") { setDragActive(true); - } else if (event.payload.type === 'leave') { + } else if (event.payload.type === "leave") { setDragActive(false); - } else if (event.payload.type === 'drop' && event.payload.paths) { + } else if (event.payload.type === "drop" && event.payload.paths) { setDragActive(false); const currentTime = Date.now(); @@ -378,26 +418,38 @@ const FloatingPromptInputInner = ( const imagePaths = droppedPaths.filter(isImageFile); if (imagePaths.length > 0) { - setPrompt(currentPrompt => { + setPrompt((currentPrompt) => { const existingPaths = extractImagePaths(currentPrompt); - const newPaths = imagePaths.filter(p => !existingPaths.includes(p)); + const newPaths = imagePaths.filter( + (p) => !existingPaths.includes(p), + ); if (newPaths.length === 0) { return currentPrompt; // All dropped images are already in the prompt } // Wrap paths with spaces in quotes for clarity - const mentionsToAdd = newPaths.map(p => { - // If path contains spaces, wrap in quotes - if (p.includes(' ')) { - return `@"${p}"`; - } - return `@${p}`; - }).join(' '); - const newPrompt = currentPrompt + (currentPrompt.endsWith(' ') || currentPrompt === '' ? '' : ' ') + mentionsToAdd + ' '; + const mentionsToAdd = newPaths + .map((p) => { + // If path contains spaces, wrap in quotes + if (p.includes(" ")) { + return `@"${p}"`; + } + return `@${p}`; + }) + .join(" "); + const newPrompt = + currentPrompt + + (currentPrompt.endsWith(" ") || currentPrompt === "" + ? "" + : " ") + + mentionsToAdd + + " "; setTimeout(() => { - const target = isExpanded ? expandedTextareaRef.current : textareaRef.current; + const target = isExpanded + ? expandedTextareaRef.current + : textareaRef.current; target?.focus(); target?.setSelectionRange(newPrompt.length, newPrompt.length); }, 0); @@ -408,7 +460,7 @@ const FloatingPromptInputInner = ( } }); } catch (error) { - console.error('Failed to set up Tauri drag-drop listener:', error); + console.error("Failed to set up Tauri drag-drop listener:", error); } }; @@ -435,13 +487,15 @@ const FloatingPromptInputInner = ( const handleSend = () => { if (prompt.trim() && !disabled) { let finalPrompt = prompt.trim(); - + // Append thinking phrase if not auto mode - const thinkingMode = THINKING_MODES.find(m => m.id === selectedThinkingMode); + const thinkingMode = THINKING_MODES.find( + (m) => m.id === selectedThinkingMode, + ); if (thinkingMode && thinkingMode.phrase) { finalPrompt = `${finalPrompt}.\n\n${thinkingMode.phrase}.`; } - + onSend(finalPrompt, selectedModel); setPrompt(""); setEmbeddedImages([]); @@ -452,11 +506,11 @@ const FloatingPromptInputInner = ( const handleTextChange = (e: React.ChangeEvent) => { const newValue = e.target.value; const newCursorPosition = e.target.selectionStart || 0; - + // Auto-resize textarea based on content if (textareaRef.current && !isExpanded) { // Reset height to auto to get the actual scrollHeight - textareaRef.current.style.height = 'auto'; + textareaRef.current.style.height = "auto"; const scrollHeight = textareaRef.current.scrollHeight; // Set min height to 48px and max to 240px (about 10 lines) const newHeight = Math.min(Math.max(scrollHeight, 48), 240); @@ -465,13 +519,17 @@ const FloatingPromptInputInner = ( } // Check if / was just typed at the beginning of input or after whitespace - if (newValue.length > prompt.length && newValue[newCursorPosition - 1] === '/') { + if ( + newValue.length > prompt.length && + newValue[newCursorPosition - 1] === "/" + ) { // Check if it's at the start or after whitespace - const isStartOfCommand = newCursorPosition === 1 || + const isStartOfCommand = + newCursorPosition === 1 || (newCursorPosition > 1 && /\s/.test(newValue[newCursorPosition - 2])); - + if (isStartOfCommand) { - console.log('[FloatingPromptInput] / detected for slash command'); + console.log("[FloatingPromptInput] / detected for slash command"); setShowSlashCommandPicker(true); setSlashCommandQuery(""); setCursorPosition(newCursorPosition); @@ -479,8 +537,15 @@ const FloatingPromptInputInner = ( } // Check if @ was just typed - if (projectPath?.trim() && newValue.length > prompt.length && newValue[newCursorPosition - 1] === '@') { - console.log('[FloatingPromptInput] @ detected, projectPath:', projectPath); + if ( + projectPath?.trim() && + newValue.length > prompt.length && + newValue[newCursorPosition - 1] === "@" + ) { + console.log( + "[FloatingPromptInput] @ detected, projectPath:", + projectPath, + ); setShowFilePicker(true); setFilePickerQuery(""); setCursorPosition(newCursorPosition); @@ -491,12 +556,12 @@ const FloatingPromptInputInner = ( // Find the / position before cursor let slashPosition = -1; for (let i = newCursorPosition - 1; i >= 0; i--) { - if (newValue[i] === '/') { + if (newValue[i] === "/") { slashPosition = i; break; } // Stop if we hit whitespace (new word) - if (newValue[i] === ' ' || newValue[i] === '\n') { + if (newValue[i] === " " || newValue[i] === "\n") { break; } } @@ -516,12 +581,12 @@ const FloatingPromptInputInner = ( // Find the @ position before cursor let atPosition = -1; for (let i = newCursorPosition - 1; i >= 0; i--) { - if (newValue[i] === '@') { + if (newValue[i] === "@") { atPosition = i; break; } // Stop if we hit whitespace (new word) - if (newValue[i] === ' ' || newValue[i] === '\n') { + if (newValue[i] === " " || newValue[i] === "\n") { break; } } @@ -545,19 +610,19 @@ const FloatingPromptInputInner = ( // Find the @ position before cursor let atPosition = -1; for (let i = cursorPosition - 1; i >= 0; i--) { - if (prompt[i] === '@') { + if (prompt[i] === "@") { atPosition = i; break; } // Stop if we hit whitespace (new word) - if (prompt[i] === ' ' || prompt[i] === '\n') { + if (prompt[i] === " " || prompt[i] === "\n") { break; } } if (atPosition === -1) { // @ not found, this shouldn't happen but handle gracefully - console.error('[FloatingPromptInput] @ position not found'); + console.error("[FloatingPromptInput] @ position not found"); return; } @@ -565,8 +630,8 @@ const FloatingPromptInputInner = ( const textarea = textareaRef.current; const beforeAt = prompt.substring(0, atPosition); const afterCursor = prompt.substring(cursorPosition); - const relativePath = entry.path.startsWith(projectPath || '') - ? entry.path.slice((projectPath || '').length + 1) + const relativePath = entry.path.startsWith(projectPath || "") + ? entry.path.slice((projectPath || "").length + 1) : entry.path; const newPrompt = `${beforeAt}@${relativePath} ${afterCursor}`; @@ -593,31 +658,33 @@ const FloatingPromptInputInner = ( }; const handleSlashCommandSelect = (command: SlashCommand) => { - const textarea = isExpanded ? expandedTextareaRef.current : textareaRef.current; + const textarea = isExpanded + ? expandedTextareaRef.current + : textareaRef.current; if (!textarea) return; // Find the / position before cursor let slashPosition = -1; for (let i = cursorPosition - 1; i >= 0; i--) { - if (prompt[i] === '/') { + if (prompt[i] === "/") { slashPosition = i; break; } // Stop if we hit whitespace (new word) - if (prompt[i] === ' ' || prompt[i] === '\n') { + if (prompt[i] === " " || prompt[i] === "\n") { break; } } if (slashPosition === -1) { - console.error('[FloatingPromptInput] / position not found'); + console.error("[FloatingPromptInput] / position not found"); return; } // Simply insert the command syntax const beforeSlash = prompt.substring(0, slashPosition); const afterCursor = prompt.substring(cursorPosition); - + if (command.accepts_arguments) { // Insert command with placeholder for arguments const newPrompt = `${beforeSlash}${command.full_command} `; @@ -628,7 +695,8 @@ const FloatingPromptInputInner = ( // Focus and position cursor after the command setTimeout(() => { textarea.focus(); - const newCursorPos = beforeSlash.length + command.full_command.length + 1; + const newCursorPos = + beforeSlash.length + command.full_command.length + 1; textarea.setSelectionRange(newCursorPos, newCursorPos); }, 0); } else { @@ -641,7 +709,8 @@ const FloatingPromptInputInner = ( // Focus and position cursor after the command setTimeout(() => { textarea.focus(); - const newCursorPos = beforeSlash.length + command.full_command.length + 1; + const newCursorPos = + beforeSlash.length + command.full_command.length + 1; textarea.setSelectionRange(newCursorPos, newCursorPos); }, 0); } @@ -652,20 +721,22 @@ const FloatingPromptInputInner = ( setSlashCommandQuery(""); // Return focus to textarea setTimeout(() => { - const textarea = isExpanded ? expandedTextareaRef.current : textareaRef.current; + const textarea = isExpanded + ? expandedTextareaRef.current + : textareaRef.current; textarea?.focus(); }, 0); }; const handleKeyDown = (e: React.KeyboardEvent) => { - if (showFilePicker && e.key === 'Escape') { + if (showFilePicker && e.key === "Escape") { e.preventDefault(); setShowFilePicker(false); setFilePickerQuery(""); return; } - if (showSlashCommandPicker && e.key === 'Escape') { + if (showSlashCommandPicker && e.key === "Escape") { e.preventDefault(); setShowSlashCommandPicker(false); setSlashCommandQuery(""); @@ -673,13 +744,19 @@ const FloatingPromptInputInner = ( } // Add keyboard shortcut for expanding - if (e.key === 'e' && (e.ctrlKey || e.metaKey) && e.shiftKey) { + if (e.key === "e" && (e.ctrlKey || e.metaKey) && e.shiftKey) { e.preventDefault(); setIsExpanded(true); return; } - if (e.key === "Enter" && !e.shiftKey && !isExpanded && !showFilePicker && !showSlashCommandPicker) { + if ( + e.key === "Enter" && + !e.shiftKey && + !isExpanded && + !showFilePicker && + !showSlashCommandPicker + ) { e.preventDefault(); handleSend(); } @@ -690,9 +767,9 @@ const FloatingPromptInputInner = ( if (!items) return; for (const item of items) { - if (item.type.startsWith('image/')) { + if (item.type.startsWith("image/")) { e.preventDefault(); - + // Get the image blob const blob = item.getAsFile(); if (!blob) continue; @@ -702,16 +779,24 @@ const FloatingPromptInputInner = ( const reader = new FileReader(); reader.onload = () => { const base64Data = reader.result as string; - + // Add the base64 data URL directly to the prompt - setPrompt(currentPrompt => { + setPrompt((currentPrompt) => { // Use the data URL directly as the image reference const mention = `@"${base64Data}"`; - const newPrompt = currentPrompt + (currentPrompt.endsWith(' ') || currentPrompt === '' ? '' : ' ') + mention + ' '; - + const newPrompt = + currentPrompt + + (currentPrompt.endsWith(" ") || currentPrompt === "" + ? "" + : " ") + + mention + + " "; + // Focus the textarea and move cursor to end setTimeout(() => { - const target = isExpanded ? expandedTextareaRef.current : textareaRef.current; + const target = isExpanded + ? expandedTextareaRef.current + : textareaRef.current; target?.focus(); target?.setSelectionRange(newPrompt.length, newPrompt.length); }, 0); @@ -719,10 +804,10 @@ const FloatingPromptInputInner = ( return newPrompt; }); }; - + reader.readAsDataURL(blob); } catch (error) { - console.error('Failed to paste image:', error); + console.error("Failed to paste image:", error); } } } @@ -745,282 +830,320 @@ const FloatingPromptInputInner = ( const handleRemoveImage = (index: number) => { // Remove the corresponding @mention from the prompt const imagePath = embeddedImages[index]; - + // For data URLs, we need to handle them specially since they're always quoted - if (imagePath.startsWith('data:')) { + if (imagePath.startsWith("data:")) { // Simply remove the exact quoted data URL const quotedPath = `@"${imagePath}"`; - const newPrompt = prompt.replace(quotedPath, '').trim(); + const newPrompt = prompt.replace(quotedPath, "").trim(); setPrompt(newPrompt); return; } - + // For file paths, use the original logic - const escapedPath = imagePath.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - const escapedRelativePath = imagePath.replace(projectPath + '/', '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - + const escapedPath = imagePath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + const escapedRelativePath = imagePath + .replace(projectPath + "/", "") + .replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + // Create patterns for both quoted and unquoted mentions const patterns = [ // Quoted full path - new RegExp(`@"${escapedPath}"\\s?`, 'g'), + new RegExp(`@"${escapedPath}"\\s?`, "g"), // Unquoted full path - new RegExp(`@${escapedPath}\\s?`, 'g'), + new RegExp(`@${escapedPath}\\s?`, "g"), // Quoted relative path - new RegExp(`@"${escapedRelativePath}"\\s?`, 'g'), + new RegExp(`@"${escapedRelativePath}"\\s?`, "g"), // Unquoted relative path - new RegExp(`@${escapedRelativePath}\\s?`, 'g') + new RegExp(`@${escapedRelativePath}\\s?`, "g"), ]; let newPrompt = prompt; for (const pattern of patterns) { - newPrompt = newPrompt.replace(pattern, ''); + newPrompt = newPrompt.replace(pattern, ""); } setPrompt(newPrompt.trim()); }; - const selectedModelData = MODELS.find(m => m.id === selectedModel) || MODELS[0]; + const selectedModelData = + MODELS.find((m) => m.id === selectedModel) || MODELS[0]; return ( - <> - {/* Expanded Modal */} - - {isExpanded && ( - setIsExpanded(false)} - > + <> + {/* Expanded Modal */} + + {isExpanded && ( e.stopPropagation()} + initial={{ opacity: 0 }} + animate={{ opacity: 1 }} + exit={{ opacity: 0 }} + className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-background/80 backdrop-blur-sm" + onClick={() => setIsExpanded(false)} > -
-

Compose your prompt

- - - - - -
+ +
+ +
- {/* Image previews in expanded mode */} - {embeddedImages.length > 0 && ( - 0 && ( + + )} + +