diff --git a/package-lock.json b/package-lock.json index 6b0efd9f23a..716510f87a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "pretty-bytes": "^6.1.1", "puppeteer-chromium-resolver": "^23.0.0", "puppeteer-core": "^23.4.0", + "react-dev-inspector": "^2.0.1", "react-tooltip": "^5.28.0", "reconnecting-eventsource": "^1.6.4", "say": "^0.16.0", @@ -102,7 +103,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -2266,7 +2266,6 @@ "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", "js-tokens": "^4.0.0", @@ -2280,7 +2279,6 @@ "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz", "integrity": "sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -2289,7 +2287,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.26.0", @@ -2319,7 +2316,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -2328,7 +2324,6 @@ "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", - "dev": true, "dependencies": { "@babel/parser": "^7.26.3", "@babel/types": "^7.26.3", @@ -2344,7 +2339,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.25.9", "@babel/helper-validator-option": "^7.25.9", @@ -2360,7 +2354,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -2369,7 +2362,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" @@ -2382,7 +2374,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", @@ -2408,7 +2399,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -2417,7 +2407,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -2426,7 +2415,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -2435,7 +2423,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", - "dev": true, "dependencies": { "@babel/template": "^7.25.9", "@babel/types": "^7.26.0" @@ -2448,7 +2435,6 @@ "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", - "dev": true, "dependencies": { "@babel/types": "^7.26.3" }, @@ -2696,7 +2682,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.25.9", "@babel/parser": "^7.25.9", @@ -2710,7 +2695,6 @@ "version": "7.26.4", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.26.3", @@ -2728,7 +2712,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -2737,7 +2720,6 @@ "version": "7.26.3", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", - "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" @@ -3193,7 +3175,7 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", - "dev": true, + "devOptional": true, "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -3211,7 +3193,7 @@ "version": "4.12.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, + "devOptional": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -3220,7 +3202,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, + "devOptional": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -3243,7 +3225,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3253,7 +3235,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3265,7 +3247,7 @@ "version": "8.57.1", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, + "devOptional": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -3320,7 +3302,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "deprecated": "Use @eslint/config-array instead", - "dev": true, + "devOptional": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.3", "debug": "^4.3.1", @@ -3334,7 +3316,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3344,7 +3326,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3356,7 +3338,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=12.22" }, @@ -3370,7 +3352,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "deprecated": "Use @eslint/object-schema instead", - "dev": true + "devOptional": true }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -3916,7 +3898,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -3930,7 +3911,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -3939,22 +3919,30 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -4268,6 +4256,86 @@ "node": ">=18" } }, + "node_modules/@react-dev-inspector/babel-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@react-dev-inspector/babel-plugin/-/babel-plugin-2.0.1.tgz", + "integrity": "sha512-V2MzN9dj3uZu6NvAjSxXwa3+FOciVIuwAUwPLpO6ji5xpUyx8E6UiEng1QqzttdpacKHFKtkNYjtQAE+Lsqa5A==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.20.5", + "@babel/generator": "^7.20.5", + "@babel/parser": "^7.20.5", + "@babel/traverse": "^7.20.5", + "@babel/types": "7.20.5" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@react-dev-inspector/babel-plugin/node_modules/@babel/types": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", + "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@react-dev-inspector/middleware": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@react-dev-inspector/middleware/-/middleware-2.0.1.tgz", + "integrity": "sha512-qDMtBzAxNNAX01jjU1THZVuNiVB7J1Hjk42k8iLSSwfinc3hk667iqgdzeq1Za1a0V2bF5Ev6D4+nkZ+E1YUrQ==", + "license": "MIT", + "dependencies": { + "react-dev-utils": "12.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@react-dev-inspector/umi3-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@react-dev-inspector/umi3-plugin/-/umi3-plugin-2.0.1.tgz", + "integrity": "sha512-lRw65yKQdI/1BwrRXWJEHDJel4DWboOartGmR3S5xiTF+EiOLjmndxdA5LoVSdqbcggdtq5SWcsoZqI0TkhH7Q==", + "license": "MIT", + "dependencies": { + "@react-dev-inspector/babel-plugin": "2.0.1", + "@react-dev-inspector/middleware": "2.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@react-dev-inspector/umi4-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@react-dev-inspector/umi4-plugin/-/umi4-plugin-2.0.1.tgz", + "integrity": "sha512-vTefsJVAZsgpuO9IZ1ZFIoyryVUU+hjV8OPD8DfDU+po5LjVXc5Uncn+MkFOsT24AMpNdDvCnTRYiuSkFn8EsA==", + "license": "MIT", + "dependencies": { + "@react-dev-inspector/babel-plugin": "2.0.1", + "@react-dev-inspector/middleware": "2.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@react-dev-inspector/vite-plugin": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@react-dev-inspector/vite-plugin/-/vite-plugin-2.0.1.tgz", + "integrity": "sha512-J1eI7cIm2IXE6EwhHR1OyoefvobUJEn/vJWEBwOM5uW4JkkLwuVoV9vk++XJyAmKUNQ87gdWZvSWrI2LjfrSug==", + "license": "MIT", + "dependencies": { + "@react-dev-inspector/middleware": "2.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", @@ -6054,6 +6122,35 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "license": "MIT", + "peer": true + }, "node_modules/@types/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", @@ -6108,6 +6205,12 @@ "pretty-format": "^29.0.0" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "license": "MIT" + }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -6139,11 +6242,36 @@ "form-data": "^4.0.0" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, "node_modules/@types/pdf-parse": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/pdf-parse/-/pdf-parse-1.1.4.tgz", "integrity": "sha512-+gbBHbNCVGGYw1S9lAIIvrHW47UYOhMIFUsJcMkMrzy1Jf0vulBN3XQIjPgnoOXveMuHnF3b57fXROnY/Or7eg==" }, + "node_modules/@types/react": { + "version": "19.0.12", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz", + "integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-reconciler": { + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.31.0.tgz", + "integrity": "sha512-wa1KtV3SHKnWeLHfZFg/7nrPSe/Ejdn+qbanNX4V6i9I7C3ECKPfBnC1KM3ef58KFWEohLmTvoTH5XuEIKGX2g==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*" + } + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -6420,13 +6548,174 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "devOptional": true }, "node_modules/@vscode/codicons": { "version": "0.0.36", "resolved": "https://registry.npmjs.org/@vscode/codicons/-/codicons-0.0.36.tgz", "integrity": "sha512-wsNOvNMMJ2BY8rC2N2MNBG7yOowV3ov8KlvUE/AiVUlHKTfWsw3OgAOQduX7h0Un6GssKD3aoTVH+TF3DSQwKQ==" }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.8.10", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz", @@ -6435,6 +6724,20 @@ "node": ">=10.0.0" } }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -6484,7 +6787,6 @@ "version": "8.14.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -6496,11 +6798,20 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, + "devOptional": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/address": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz", + "integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/agent-base": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", @@ -6540,7 +6851,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -6552,6 +6862,57 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT", + "peer": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -6617,7 +6978,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6635,7 +6995,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "devOptional": true }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", @@ -6657,7 +7017,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, "engines": { "node": ">=8" } @@ -6711,10 +7070,19 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", "dev": true, "dependencies": { "possible-typed-array-names": "^1.0.0" @@ -6872,8 +7240,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/bare-events": { "version": "2.5.0", @@ -6963,6 +7330,18 @@ "node": "*" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bluebird": { "version": "3.4.7", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", @@ -7049,7 +7428,6 @@ "version": "4.24.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7114,8 +7492,7 @@ "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/bytes": { "version": "3.1.2", @@ -7177,7 +7554,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -7195,7 +7571,6 @@ "version": "1.0.30001687", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001687.tgz", "integrity": "sha512-0S/FDhf4ZiqrTUiQ39dKeUjYRjkv7lOZU1Dgif2rIqrTzX/1wV2hfKu9TOm1IHkdSijfLswxTFzl/cvir+SLSQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -7215,7 +7590,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7231,7 +7605,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -7308,6 +7681,16 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/chromium-bidi": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.8.0.tgz", @@ -7553,8 +7936,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/console-control-strings": { "version": "1.1.0", @@ -7585,8 +7967,7 @@ "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 + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" }, "node_modules/cookie": { "version": "0.7.1", @@ -7624,6 +8005,40 @@ "node": ">= 0.10" } }, + "node_modules/cosmiconfig": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", + "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.7.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cosmiconfig/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -7684,6 +8099,13 @@ "url": "https://github.com/sponsors/fb55" } }, + "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", + "peer": true + }, "node_modules/data-uri-to-buffer": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", @@ -7777,13 +8199,12 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "devOptional": true }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7829,6 +8250,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/define-properties": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", @@ -7915,6 +8345,38 @@ "node": ">=8" } }, + "node_modules/detect-port-alt": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/detect-port-alt/-/detect-port-alt-1.1.6.tgz", + "integrity": "sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==", + "license": "MIT", + "dependencies": { + "address": "^1.0.1", + "debug": "^2.6.0" + }, + "bin": { + "detect": "bin/detect-port", + "detect-port": "bin/detect-port" + }, + "engines": { + "node": ">= 4.2.1" + } + }, + "node_modules/detect-port-alt/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/detect-port-alt/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/devtools-protocol": { "version": "0.0.1367902", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", @@ -7952,7 +8414,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, "dependencies": { "path-type": "^4.0.0" }, @@ -7964,7 +8425,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -7973,7 +8433,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, + "devOptional": true, "dependencies": { "esutils": "^2.0.2" }, @@ -8067,6 +8527,12 @@ "node": ">= 0.4" } }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "license": "MIT" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -8149,8 +8615,7 @@ "node_modules/electron-to-chromium": { "version": "1.5.71", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.71.tgz", - "integrity": "sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==", - "dev": true + "integrity": "sha512-dB68l59BI75W1BUGVTAEJy45CEVuEGy9qPVVQ8pnHyHMn36PLPPoE1mjLH+lo9rKulO3HC2OhbACI/8tCqJBcA==" }, "node_modules/emittery": { "version": "0.13.1", @@ -8204,7 +8669,6 @@ "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -8274,7 +8738,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -8355,6 +8818,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "license": "MIT", + "peer": true + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -8455,7 +8925,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -8488,7 +8957,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, + "devOptional": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -8543,7 +9012,7 @@ "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, + "devOptional": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -8559,7 +9028,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, + "devOptional": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -8571,7 +9040,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -8580,7 +9049,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -8590,7 +9059,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, + "devOptional": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -8602,7 +9071,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -8614,7 +9083,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "devOptional": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -8626,7 +9095,7 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, + "devOptional": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -8655,7 +9124,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, + "devOptional": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -8667,7 +9136,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -8714,6 +9182,16 @@ "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", "dev": true }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/eventsource": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.5.tgz", @@ -9002,14 +9480,30 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "devOptional": true + }, + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "peer": true }, "node_modules/fast-xml-parser": { "version": "4.5.1", @@ -9071,7 +9565,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, + "devOptional": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -9100,6 +9594,15 @@ "node": ">=10" } }, + "node_modules/filesize": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-8.0.7.tgz", + "integrity": "sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -9132,7 +9635,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -9148,7 +9650,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, + "devOptional": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -9162,7 +9664,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -9173,7 +9675,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, + "devOptional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -9193,7 +9695,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -9206,7 +9708,7 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, + "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -9221,7 +9723,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", - "dev": true + "devOptional": true }, "node_modules/follow-redirects": { "version": "1.15.9", @@ -9267,78 +9769,245 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz", + "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==", + "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "chokidar": "^3.4.2", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "glob": "^7.1.6", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "eslint": ">= 6", + "typescript": ">= 2.7", + "vue-template-compiler": "*", + "webpack": ">= 4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + }, + "vue-template-compiler": { + "optional": true + } } }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, "engines": { - "node": ">= 0.6" + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" } }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">= 0.8" + "node": ">=10" } }, - "node_modules/fs-extra": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", - "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=6 <7 || >=8" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "node_modules/fork-ts-checker-webpack-plugin/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } }, - "node_modules/fsevents": { - "version": "2.3.3", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "license": "Unlicense" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -9475,7 +10144,6 @@ "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, "engines": { "node": ">=6.9.0" } @@ -9635,6 +10303,13 @@ "node": ">= 6" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause", + "peer": true + }, "node_modules/glob/node_modules/minimatch": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", @@ -9651,11 +10326,49 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "license": "MIT", + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "license": "MIT", + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, + "devOptional": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -9737,7 +10450,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "devOptional": true }, "node_modules/gtoken": { "version": "7.1.0", @@ -9751,6 +10464,21 @@ "node": ">=14.0.0" } }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "license": "MIT", + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -9764,7 +10492,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -9844,6 +10571,15 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, + "node_modules/hotkeys-js": { + "version": "3.13.9", + "resolved": "https://registry.npmjs.org/hotkeys-js/-/hotkeys-js-3.13.9.tgz", + "integrity": "sha512-3TRCj9u9KUH6cKo25w4KIdBfdBfNRjfUwrljCLDC2XhmPDG0SjAZFcFZekpUZFmXzfYoGhFDcdx2gX/vUVtztQ==", + "license": "MIT", + "funding": { + "url": "https://jaywcjlove.github.io/#/sponsor" + } + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -10019,11 +10755,20 @@ "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, + "node_modules/immer": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", + "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -10058,7 +10803,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.8.19" } @@ -10077,7 +10822,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -10088,6 +10832,12 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -10142,8 +10892,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-async-function": { "version": "2.0.0", @@ -10175,6 +10924,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.0.tgz", @@ -10248,6 +11009,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -10366,7 +11142,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" } @@ -10406,6 +11182,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-root": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-root/-/is-root-2.1.0.tgz", + "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/is-set": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", @@ -10553,6 +11338,18 @@ "node": ">=0.10.0" } }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -11403,21 +12200,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", @@ -11438,14 +12220,13 @@ "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==", - "dev": true + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "devOptional": true, "dependencies": { "argparse": "^2.0.1" }, @@ -11462,7 +12243,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -11482,7 +12262,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "devOptional": true }, "node_modules/json-parse-better-errors": { "version": "1.0.2", @@ -11493,26 +12273,23 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "devOptional": true }, "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, "bin": { "json5": "lib/cli.js" }, @@ -11562,7 +12339,7 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, + "devOptional": true, "dependencies": { "json-buffer": "3.0.1" } @@ -11579,7 +12356,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, "engines": { "node": ">=6" } @@ -11705,7 +12481,7 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, + "devOptional": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -11737,8 +12513,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lint-staged": { "version": "15.2.11", @@ -12028,11 +12803,29 @@ "node": ">=4" } }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -12053,7 +12846,7 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "devOptional": true }, "node_modules/lodash.startcase": { "version": "4.4.0", @@ -12238,7 +13031,6 @@ "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, "dependencies": { "yallist": "^3.0.2" } @@ -12338,6 +13130,18 @@ "node": ">= 0.8" } }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/memorystream": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", @@ -12526,7 +13330,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "devOptional": true }, "node_modules/negotiator": { "version": "1.0.0", @@ -12537,6 +13341,13 @@ "node": ">= 0.6" } }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT", + "peer": true + }, "node_modules/netmask": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", @@ -12602,8 +13413,7 @@ "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/normalize-package-data": { "version": "2.5.0", @@ -12630,7 +13440,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -12941,9 +13750,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/openai": { - "version": "4.78.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.78.1.tgz", + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.78.1", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.78.1.tgz", "integrity": "sha512-drt0lHZBd2lMyORckOXFPQTmnGLWSLt8VK0W9BhOKWpMFBEoHMoz5gxMPmVq5icp+sOrsbMnsmZTVHUlKvD1Ow==", "dependencies": { "@types/node": "^18.11.18", @@ -12988,7 +13814,7 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, + "devOptional": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -13048,7 +13874,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -13063,7 +13888,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -13098,7 +13922,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "engines": { "node": ">=6" } @@ -13168,7 +13991,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -13180,7 +14002,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -13253,7 +14074,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "engines": { "node": ">=8" } @@ -13355,8 +14175,7 @@ "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -13472,6 +14291,79 @@ "node": ">=8" } }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -13496,7 +14388,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 0.8.0" } @@ -13586,7 +14478,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -13652,7 +14543,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -13740,6 +14630,16 @@ "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -13774,6 +14674,120 @@ "node": ">=0.10.0" } }, + "node_modules/react-dev-inspector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/react-dev-inspector/-/react-dev-inspector-2.0.1.tgz", + "integrity": "sha512-b8PAmbwGFrWcxeaX8wYveqO+VTwTXGJaz/yl9RO31LK1zeLKJVlkkbeLExLnJ6IvhXY1TwL8Q4+gR2GKJ8BI6Q==", + "license": "MIT", + "dependencies": { + "@react-dev-inspector/babel-plugin": "2.0.1", + "@react-dev-inspector/middleware": "2.0.1", + "@react-dev-inspector/umi3-plugin": "2.0.1", + "@react-dev-inspector/umi4-plugin": "2.0.1", + "@react-dev-inspector/vite-plugin": "2.0.1", + "@types/react-reconciler": ">=0.26.6", + "hotkeys-js": "^3.8.1", + "picocolors": "1.0.0", + "react-dev-utils": "12.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-dev-inspector/node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "license": "ISC" + }, + "node_modules/react-dev-utils": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", + "integrity": "sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.16.0", + "address": "^1.1.2", + "browserslist": "^4.18.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "detect-port-alt": "^1.1.6", + "escape-string-regexp": "^4.0.0", + "filesize": "^8.0.6", + "find-up": "^5.0.0", + "fork-ts-checker-webpack-plugin": "^6.5.0", + "global-modules": "^2.0.0", + "globby": "^11.0.4", + "gzip-size": "^6.0.0", + "immer": "^9.0.7", + "is-root": "^2.1.0", + "loader-utils": "^3.2.0", + "open": "^8.4.0", + "pkg-up": "^3.1.0", + "prompts": "^2.4.2", + "react-error-overlay": "^6.0.11", + "recursive-readdir": "^2.2.2", + "shell-quote": "^1.7.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-dev-utils/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-dev-utils/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-dev-utils/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/react-dom": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", @@ -13787,6 +14801,12 @@ "react": "^19.0.0" } }, + "node_modules/react-error-overlay": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.1.0.tgz", + "integrity": "sha512-SN/U6Ytxf1QGkw/9ve5Y+NxBbZM6Ht95tuXNMKs8EJyFa/Vy/+Co3stop3KBHARfn/giv+Lj1uUnTfOJ3moFEQ==", + "license": "MIT" + }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -13934,6 +14954,40 @@ "node": ">=12.0.0" } }, + "node_modules/recursive-readdir": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.3.tgz", + "integrity": "sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==", + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/recursive-readdir/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/recursive-readdir/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.8.tgz", @@ -13987,6 +15041,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", @@ -14029,7 +15093,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -14274,6 +15337,24 @@ "license": "MIT", "peer": true }, + "node_modules/schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -14342,6 +15423,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, "node_modules/serve-static": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.1.0.tgz", @@ -14434,7 +15525,6 @@ "version": "1.8.2", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -14543,8 +15633,7 @@ "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, "node_modules/slash": { "version": "5.1.0", @@ -14653,7 +15742,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -15014,7 +16102,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, + "devOptional": true, "engines": { "node": ">=8" }, @@ -15033,6 +16121,21 @@ "integrity": "sha512-nMIjMrd5Z2nuB2RZCKJfFMjgS3fygbeyGk9PxPPaJR1RIcyN9yn4A63Isovzm3ZtQuEkLBVgMdPup8UeLH7aQw==", "dev": true }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -15049,7 +16152,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -15089,6 +16191,150 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/terser": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", + "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz", + "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "serialize-javascript": "^6.0.2", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT", + "peer": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT", + "peer": true + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -15157,8 +16403,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "node_modules/through": { "version": "2.3.8", @@ -15180,6 +16425,15 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -15290,7 +16544,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, + "devOptional": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -15311,7 +16565,7 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, + "devOptional": true, "engines": { "node": ">=10" }, @@ -15437,7 +16691,6 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", - "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15543,7 +16796,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -15573,7 +16825,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -15651,6 +16902,20 @@ "makeerror": "1.0.12" } }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "license": "MIT", + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -15679,6 +16944,144 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, + "node_modules/webpack": { + "version": "5.98.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.98.0.tgz", + "integrity": "sha512-UFynvx+gM44Gv9qFgj0acCQK2VE1CtdfwFdimkapco3hlPCJ/zeq73n2yVKimVbtm+TnApIugGhLJnkU6gjYXA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.11", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT", + "peer": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", + "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", @@ -15986,7 +17389,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -16149,8 +17552,7 @@ "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" }, "node_modules/yaml": { "version": "2.6.1", @@ -16239,7 +17641,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 5591e198123..a58d2773e71 100644 --- a/package.json +++ b/package.json @@ -393,6 +393,7 @@ "pretty-bytes": "^6.1.1", "puppeteer-chromium-resolver": "^23.0.0", "puppeteer-core": "^23.4.0", + "react-dev-inspector": "^2.0.1", "react-tooltip": "^5.28.0", "reconnecting-eventsource": "^1.6.4", "say": "^0.16.0", diff --git a/src/activate/registerCommands.ts b/src/activate/registerCommands.ts index d271a054349..9955ca27140 100644 --- a/src/activate/registerCommands.ts +++ b/src/activate/registerCommands.ts @@ -85,6 +85,48 @@ const getCommandsMap = ({ context, outputChannel, provider }: RegisterCommandOpt "roo-cline.registerHumanRelayCallback": registerHumanRelayCallback, "roo-cline.unregisterHumanRelayCallback": unregisterHumanRelayCallback, "roo-cline.handleHumanRelayResponse": handleHumanRelayResponse, + "roo-cline.createInAgent": async (args: any) => { + const sidebarProvider = ClineProvider.getSidebarInstance() + if (sidebarProvider) { + // Start a new chat in the sidebar + vscode.commands.executeCommand("pearai-roo-cline.SidebarProvider.focus") + await sidebarProvider.handleModeSwitch("code", args.creatorMode) + await sidebarProvider.postStateToWebview() + await sidebarProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) + + await sidebarProvider.initClineWithTask(args.text, undefined, undefined, args.creatorMode) + } + }, + "roo-cline.executeCreatorPlan": async (args: any) => { + const sidebarProvider = ClineProvider.getSidebarInstance() + if (sidebarProvider) { + // Start a new chat in the sidebar + vscode.commands.executeCommand("pearai-roo-cline.SidebarProvider.focus") + await sidebarProvider.handleModeSwitch("code") + await sidebarProvider.postStateToWebview() + await sidebarProvider.postMessageToWebview({ type: "action", action: "chatButtonClicked" }) + + // Create the template message using the args + // Todo: add structure to it i.e. You should have these sections: Architecutre, Features, etc. + let executePlanTemplate = `This file contains detailed plan to my task. please read it and Execute the plan accordingly. + File: ${args.filePath || "No file specified"}` + + if (args.code) { + executePlanTemplate += `Code: \`\`\` + ${args.code} + \`\`\` + ` + } + + if (args.context) { + executePlanTemplate += `Additional context: ${args.context}` + } + + args.text = executePlanTemplate + + await sidebarProvider.initClineWithTask(args.text, undefined, undefined, true) + } + }, } } @@ -93,20 +135,20 @@ const openClineInNewTab = async ({ context, outputChannel }: Omit editor.viewColumn || 0)) // Check if there are any visible text editors, otherwise open a new group // to the right. - const hasVisibleEditors = vscode.window.visibleTextEditors.length > 0 + // const hasVisibleEditors = vscode.window.visibleTextEditors.length > 0 - if (!hasVisibleEditors) { - await vscode.commands.executeCommand("workbench.action.newGroupRight") - } + // if (!hasVisibleEditors) { + // await vscode.commands.executeCommand("workbench.action.newGroupRight") + // } - const targetCol = hasVisibleEditors ? Math.max(lastCol + 1, 1) : vscode.ViewColumn.Two + // const targetCol = hasVisibleEditors ? Math.max(lastCol + 1, 1) : vscode.ViewColumn.Two - const newPanel = vscode.window.createWebviewPanel(ClineProvider.tabPanelId, "Roo Code", targetCol, { + const newPanel = vscode.window.createWebviewPanel(ClineProvider.tabPanelId, "Roo Code", vscode.ViewColumn.One, { enableScripts: true, retainContextWhenHidden: true, localResourceRoots: [context.extensionUri], @@ -131,5 +173,5 @@ const openClineInNewTab = async ({ context, outputChannel }: Omit { // (have to do this for partial and complete since sending content in thinking tags to markdown renderer will automatically be removed) // Remove end substrings of (with optional line break after) and (with optional line break before) // - Needs to be separate since we dont want to remove the line break before the first tag // - Needs to happen before the xml parsing below @@ -1390,6 +1390,7 @@ export class Cline extends EventEmitter { return `[${block.name} in ${modeName} mode: '${message}']` } } + return `[${block.name}]` } if (this.didRejectTool) { diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts index 865a336bf39..61353801d62 100644 --- a/src/core/webview/ClineProvider.ts +++ b/src/core/webview/ClineProvider.ts @@ -67,6 +67,13 @@ import { getUri } from "./getUri" import { telemetryService } from "../../services/telemetry/TelemetryService" import { TelemetrySetting } from "../../shared/TelemetrySetting" import { getWorkspacePath } from "../../utils/path" +import { readWorkspaceFile, writeWorkspaceFile } from "../../integrations/misc/workspace-files" + +/* +https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts + +https://github.com/KumarVariable/vscode-extension-sidebar-html/blob/master/src/customSidebarViewProvider.ts +*/ /** * https://github.com/microsoft/vscode-webview-ui-toolkit-samples/blob/main/default/weather-webview/src/providers/WeatherViewProvider.ts @@ -91,6 +98,7 @@ export class ClineProvider extends EventEmitter implements private contextProxy: ContextProxy configManager: ConfigManager customModesManager: CustomModesManager + private isCreatorView: boolean = false get cwd() { return getWorkspacePath() } @@ -98,9 +106,13 @@ export class ClineProvider extends EventEmitter implements readonly context: vscode.ExtensionContext, private readonly outputChannel: vscode.OutputChannel, private readonly renderContext: "sidebar" | "editor" = "sidebar", + isCreatorView: boolean = false, ) { super() - + this.outputChannel.appendLine(`creator = ${isCreatorView}`) + this.isCreatorView = isCreatorView + console.dir("CREATOR") + console.dir(this.isCreatorView) this.outputChannel.appendLine("ClineProvider instantiated") this.contextProxy = new ContextProxy(context) ClineProvider.activeInstances.add(this) @@ -236,6 +248,16 @@ export class ClineProvider extends EventEmitter implements McpServerManager.unregisterProvider(this) } + public static getSidebarInstance(): ClineProvider | undefined { + const sidebar = Array.from(this.activeInstances).find((instance) => !instance.isCreatorView) + + if (!sidebar?.view?.visible) { + vscode.commands.executeCommand("pearai-roo-cline.SidebarProvider.focus") + } + + return sidebar + } + public static getVisibleInstance(): ClineProvider | undefined { return findLast(Array.from(this.activeInstances), (instance) => instance.view?.visible === true) } @@ -455,7 +477,7 @@ export class ClineProvider extends EventEmitter implements // when initializing a new task, (not from history but from a tool command new_task) there is no need to remove the previouse task // since the new task is a sub task of the previous one, and when it finishes it is removed from the stack and the caller is resumed // in this way we can have a chain of tasks, each one being a sub task of the previous one until the main task is finished - public async initClineWithTask(task?: string, images?: string[], parentTask?: Cline) { + public async initClineWithTask(task?: string, images?: string[], parentTask?: Cline, creatorMode?: boolean) { const { apiConfiguration, customModePrompts, @@ -473,7 +495,10 @@ export class ClineProvider extends EventEmitter implements const cline = new Cline({ provider: this, - apiConfiguration, + apiConfiguration: { + ...apiConfiguration, + creatorMode: creatorMode, + }, customInstructions: effectiveInstructions, enableDiff, enableCheckpoints, @@ -494,7 +519,10 @@ export class ClineProvider extends EventEmitter implements return cline } - public async initClineWithHistoryItem(historyItem: HistoryItem & { rootTask?: Cline; parentTask?: Cline }) { + public async initClineWithHistoryItem( + historyItem: HistoryItem & { rootTask?: Cline; parentTask?: Cline }, + creatorMode?: boolean, + ) { await this.removeClineFromStack() const { @@ -540,7 +568,10 @@ export class ClineProvider extends EventEmitter implements const cline = new Cline({ provider: this, - apiConfiguration, + apiConfiguration: { + ...apiConfiguration, + creatorMode: creatorMode, + }, customInstructions: effectiveInstructions, enableDiff, ...checkpoints, @@ -603,6 +634,7 @@ export class ClineProvider extends EventEmitter implements window.$RefreshReg$ = () => {} window.$RefreshSig$ = () => (type) => type window.__vite_plugin_react_preamble_installed__ = true + window.isCreator="${this.isCreatorView}"; ` @@ -615,6 +647,8 @@ export class ClineProvider extends EventEmitter implements `connect-src https://* https://*.posthog.com ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort} http://localhost:8000 http://0.0.0.0:8000 https://stingray-app-gb2an.ondigitalocean.app`, ] + console.dir("CREATORRRRRR") + console.dir(this.isCreatorView) return /*html*/ ` @@ -2033,6 +2067,47 @@ export class ClineProvider extends EventEmitter implements ), ) break + case "readWorkspaceFile": + if (message.values?.relativePath) { + const result = await readWorkspaceFile(message.values.relativePath, { + create: message.values.create, + ensureDirectory: message.values.ensureDirectory, + content: message.values.content, + }) + await this.postMessageToWebview(result) + } + break + case "writeWorkspaceFile": + if (message.values?.relativePath && message.values?.content !== undefined) { + const result = await writeWorkspaceFile(message.values.relativePath, { + create: message.values.create, + ensureDirectory: message.values.ensureDirectory, + content: message.values.content, + }) + await this.postMessageToWebview(result) + } + break + case "invoke": + switch (message.invoke) { + case "sendMessage": + if (message.text) { + await this.getCurrentCline()?.ask("followup", message.text, false) + } + break + case "setChatBoxMessage": + if (message.text) { + await this.getCurrentCline()?.ask("followup", message.text, false) + } + break + case "executeCommand": + if (message.command) { + await vscode.commands.executeCommand(message.command, message.args) + } + break + default: + console.warn("Unknown invoke:", message.invoke) + } + break } }, null, @@ -2096,7 +2171,7 @@ export class ClineProvider extends EventEmitter implements * Handle switching to a new mode, including updating the associated API configuration * @param newMode The mode to switch to */ - public async handleModeSwitch(newMode: Mode) { + public async handleModeSwitch(newMode: Mode, creatorMode?: boolean) { // Capture mode switch telemetry event const currentTaskId = this.getCurrentCline()?.taskId if (currentTaskId) { diff --git a/src/extension.ts b/src/extension.ts index 41cd1f305a3..5609e8554cd 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -62,7 +62,7 @@ export function activate(context: vscode.ExtensionContext) { context.globalState.update("allowedCommands", defaultCommands) } - const provider = new ClineProvider(context, outputChannel, "sidebar") + const provider = new ClineProvider(context, outputChannel, "sidebar", false) telemetryService.setProvider(provider) context.subscriptions.push( @@ -177,7 +177,7 @@ export function activate(context: vscode.ExtensionContext) { // Lock the editor group so clicking on files doesn't open them over the panel await delay(100) - await vscode.commands.executeCommand("workbench.action.lockEditorGroup") + // await vscode.commands.executeCommand("workbench.action.lockEditorGroup") } // context.subscriptions.push(vscode.commands.registerCommand("roo-cline.popoutButtonClicked", openClineInNewTab)) diff --git a/src/integrations/editor/DiffViewProvider.ts b/src/integrations/editor/DiffViewProvider.ts index 0bf494854a4..ac17d88d667 100644 --- a/src/integrations/editor/DiffViewProvider.ts +++ b/src/integrations/editor/DiffViewProvider.ts @@ -163,7 +163,7 @@ export class DiffViewProvider { Getting diagnostics before and after the file edit is a better approach than automatically tracking problems in real-time. This method ensures we only report new problems that are a direct result of this specific edit. - Since these are new problems resulting from Roo's edit, we know they're + Since these are new problems resulting from Agent's edit, we know they're directly related to the work he's doing. This eliminates the risk of Roo going off-task or getting distracted by unrelated issues, which was a problem with the previous auto-debug approach. Some users' machines may be slow to @@ -299,7 +299,7 @@ export class DiffViewProvider { query: Buffer.from(this.originalContent ?? "").toString("base64"), }), uri, - `${fileName}: ${fileExists ? "Original ↔ Roo's Changes" : "New File"} (Editable)`, + `${fileName}: ${fileExists ? "Original ↔ Agent's Changes" : "New File"} (Editable)`, ) // This may happen on very slow machines ie project idx setTimeout(() => { diff --git a/src/integrations/misc/workspace-files.ts b/src/integrations/misc/workspace-files.ts new file mode 100644 index 00000000000..95e7ffe18de --- /dev/null +++ b/src/integrations/misc/workspace-files.ts @@ -0,0 +1,105 @@ +import * as vscode from "vscode" +import * as path from "path" +import { ExtensionMessage } from "../../shared/ExtensionMessage" + +export async function readWorkspaceFile( + relativePath: string, + options: { create?: boolean; ensureDirectory?: boolean; content?: string } = {}, +): Promise { + try { + // Get workspace root + const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath + console.log("Workspace root:", workspaceRoot) + + // If no workspace root, try to use the current working directory + const effectiveRoot = workspaceRoot || process.cwd() + console.log("Effective root:", effectiveRoot) + + // Resolve the full path + const fullPath = path.join(effectiveRoot, relativePath) + console.log("Full path:", fullPath) + const uri = vscode.Uri.file(fullPath) + console.log("URI:", uri.toString()) + + // Check if file exists + try { + const fileContent = await vscode.workspace.fs.readFile(uri) + return { + type: "fileContent", + content: Buffer.from(fileContent).toString("utf8"), + } + } catch { + // File doesn't exist + if (!options.create) { + throw new Error("File does not exist") + } + + // If we should create directories + if (options.ensureDirectory) { + const dirPath = path.dirname(fullPath) + try { + await vscode.workspace.fs.createDirectory(vscode.Uri.file(dirPath)) + } catch (err) { + // Directory might already exist, that's fine + } + } + + // Create with provided content or empty string + const content = options.content || "" + await vscode.workspace.fs.writeFile(uri, Buffer.from(content, "utf8")) + return { + type: "fileContent", + content, + } + } + } catch (error) { + return { + type: "error", + error: error instanceof Error ? error.message : "Unknown error occurred", + } + } +} + +export async function writeWorkspaceFile( + relativePath: string, + options: { create?: boolean; ensureDirectory?: boolean; content: string }, +): Promise { + try { + // Get workspace root + const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath + console.log("Workspace root (write):", workspaceRoot) + + // If no workspace root, try to use the current working directory + const effectiveRoot = workspaceRoot || process.cwd() + console.log("Effective root (write):", effectiveRoot) + + // Resolve the full path + const fullPath = path.join(effectiveRoot, relativePath) + console.log("Full path (write):", fullPath) + const uri = vscode.Uri.file(fullPath) + console.log("URI (write):", uri.toString()) + + // If we should create directories + if (options.ensureDirectory) { + const dirPath = path.dirname(fullPath) + try { + await vscode.workspace.fs.createDirectory(vscode.Uri.file(dirPath)) + } catch (err) { + // Directory might already exist, that's fine + } + } + + // Write the file + await vscode.workspace.fs.writeFile(uri, Buffer.from(options.content, "utf8")) + + return { + type: "fileContent", + content: options.content, + } + } catch (error) { + return { + type: "error", + error: error instanceof Error ? error.message : "Unknown error occurred", + } + } +} diff --git a/src/shared/ExtensionMessage.ts b/src/shared/ExtensionMessage.ts index b7219de2f85..43dcf511dc0 100644 --- a/src/shared/ExtensionMessage.ts +++ b/src/shared/ExtensionMessage.ts @@ -58,6 +58,9 @@ export interface ExtensionMessage { | "ttsStop" | "maxReadFileLine" | "fileSearchResults" + | "creator" + | "fileContent" + | "error" text?: string action?: | "chatButtonClicked" @@ -66,6 +69,7 @@ export interface ExtensionMessage { | "historyButtonClicked" | "promptsButtonClicked" | "didBecomeVisible" + | "generateActionPlan" invoke?: "newChat" | "sendMessage" | "primaryButtonClick" | "secondaryButtonClick" | "setChatBoxMessage" state?: ExtensionState images?: string[] @@ -99,6 +103,7 @@ export interface ExtensionMessage { type: "file" | "folder" label?: string }> + content?: string error?: string } @@ -185,6 +190,7 @@ export interface ClineSayTool { | "switchMode" | "newTask" | "finishTask" + | "showTaskPlan" path?: string diff?: string content?: string diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index 3e6356de3d7..122f884c2f8 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -39,6 +39,8 @@ export interface WebviewMessage { | "requestLmStudioModels" | "openImage" | "openFile" + | "readWorkspaceFile" + | "writeWorkspaceFile" | "openMention" | "cancelTask" | "refreshOpenRouterModels" @@ -117,6 +119,9 @@ export interface WebviewMessage { | "language" | "maxReadFileLine" | "searchFiles" + | "creator" + | "generateActionPlan" + | "invoke" text?: string disabled?: boolean askResponse?: ClineAskResponse @@ -133,7 +138,12 @@ export interface WebviewMessage { promptMode?: PromptMode customPrompt?: PromptComponent dataUrls?: string[] - values?: Record + values?: { + create?: boolean + ensureDirectory?: boolean + content?: string + relativePath?: string + } & Record query?: string slug?: string modeConfig?: ModeConfig @@ -142,6 +152,9 @@ export interface WebviewMessage { source?: "global" | "project" requestId?: string ids?: string[] + invoke?: "sendMessage" | "setChatBoxMessage" | "executeCommand" + command?: string + args?: any } export const checkoutDiffPayloadSchema = z.object({ diff --git a/src/shared/api.ts b/src/shared/api.ts index 362ea95a362..7b20cefff8d 100644 --- a/src/shared/api.ts +++ b/src/shared/api.ts @@ -22,6 +22,7 @@ export type ApiProvider = export interface ApiHandlerOptions { apiModelId?: string + creatorMode?: boolean apiKey?: string // anthropic anthropicBaseUrl?: string vsCodeLmModelSelector?: vscode.LanguageModelChatSelector diff --git a/src/shared/creator-mode.ts b/src/shared/creator-mode.ts new file mode 100644 index 00000000000..350deea3f39 --- /dev/null +++ b/src/shared/creator-mode.ts @@ -0,0 +1,10 @@ +export const CREATOR_MODE_PLANNING_PROMPT = ` +Depending on the user's request, you may need to do some information gathering (for example using read_file or search_files) to get more context about the task. +You may also ask the user clarifying questions to get a better understanding of the task. +Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. +Focus on breaking down complex tasks into manageable steps, considering technical requirements, potential challenges, and best practices. +The plan should be clear enough that it can be directly implemented by switching to Code mode afterward. +(Directly write the plan to a markdown file instead of showing it as normal response.)\n\n +Once you create and write the plan, you mark the task as completed. +You only make plans and you should not ask or switch to any other mode. +Keep the plan brief, mainly feature based (include a feature list), and no steps, a product outline.` diff --git a/src/shared/experiments.ts b/src/shared/experiments.ts index f4decc324c1..a687abdd797 100644 --- a/src/shared/experiments.ts +++ b/src/shared/experiments.ts @@ -29,7 +29,7 @@ export const experimentConfigsMap: Record = { enabled: false, }, MULTI_SEARCH_AND_REPLACE: { - enabled: false, + enabled: true, }, } diff --git a/src/shared/modes.ts b/src/shared/modes.ts index 374958f7434..de106d27c19 100644 --- a/src/shared/modes.ts +++ b/src/shared/modes.ts @@ -1,6 +1,7 @@ import * as vscode from "vscode" import { TOOL_GROUPS, ToolGroup, ALWAYS_AVAILABLE_TOOLS } from "./tool-groups" import { addCustomInstructions } from "../core/prompts/sections/custom-instructions" +import { CREATOR_MODE_PLANNING_PROMPT } from "./creator-mode" // Mode types export type Mode = string @@ -78,6 +79,14 @@ export function getToolsForMode(groups: readonly GroupEntry[]): string[] { // Main modes configuration as an ordered array export const modes: readonly ModeConfig[] = [ + { + slug: "creator", + name: "Creator", + roleDefinition: + "You are PearAI Agent (Powered by Roo Code / Cline), a creative and systematic software architect focused on turning high-level ideas into actionable plans. Your primary goal is to help users transform their ideas into structured action plans.", + groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "browser", "mcp"], + customInstructions: CREATOR_MODE_PLANNING_PROMPT, + }, { slug: "code", name: "Code", diff --git a/webview-ui/src/App.tsx b/webview-ui/src/App.tsx index b0c84b200a1..b15e943768a 100644 --- a/webview-ui/src/App.tsx +++ b/webview-ui/src/App.tsx @@ -14,6 +14,8 @@ import SettingsView, { SettingsViewRef } from "./components/settings/SettingsVie import McpView from "./components/mcp/McpView" import PromptsView from "./components/prompts/PromptsView" import { HumanRelayDialog } from "./components/human-relay/HumanRelayDialog" +import { Inspector } from "react-dev-inspector" +import Creator from "./creator/Creator" type Tab = "settings" | "history" | "mcp" | "prompts" | "chat" @@ -120,13 +122,14 @@ const App = () => { ) } +const tempIsCreator: boolean = true const queryClient = new QueryClient() const AppWithProviders = () => ( - + {window.isCreator === "true" ? : } diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx index aa050221a72..2fae5fe1829 100644 --- a/webview-ui/src/components/chat/ChatView.tsx +++ b/webview-ui/src/components/chat/ChatView.tsx @@ -1169,7 +1169,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie ...
-
PearAI Coding Agent
+
PearAI Casdfoding Agent
Powered by Roo Code / Cline
diff --git a/webview-ui/src/components/ui/pearaiindex.tsx b/webview-ui/src/components/ui/pearaiindex.tsx index 2ff5b679e43..51a30e9656a 100644 --- a/webview-ui/src/components/ui/pearaiindex.tsx +++ b/webview-ui/src/components/ui/pearaiindex.tsx @@ -1,4 +1,3 @@ -import { Tooltip } from "react-tooltip" import styled, { keyframes } from "styled-components" const FONT_SIZE = 13 @@ -183,10 +182,6 @@ const TooltipStyles = { overflow: "hidden", } -export function StyledTooltip(props: any) { - return -} - export const TextArea = styled.textarea` padding: 8px; font-family: inherit; diff --git a/webview-ui/src/creator/ChatRow.tsx b/webview-ui/src/creator/ChatRow.tsx new file mode 100644 index 00000000000..5b270b9a47f --- /dev/null +++ b/webview-ui/src/creator/ChatRow.tsx @@ -0,0 +1,1128 @@ +import { CheckpointSaved } from "@/components/chat/checkpoints/CheckpointSaved" +import { ReasoningBlock } from "@/components/chat/ReasoningBlock" +import { highlightMentions } from "@/components/chat/TaskHeader" +import { removeLeadingNonAlphanumeric } from "@/components/common/CodeAccordian" +import CodeAccordian from "./CodeAccordian" +import CodeBlock, { CODE_BLOCK_BG_COLOR } from "@/components/common/CodeBlock" +import MarkdownBlock from "@/components/common/MarkdownBlock" +import Thumbnails from "@/components/common/Thumbnails" +import McpResourceRow from "@/components/mcp/McpResourceRow" +import McpToolRow from "@/components/mcp/McpToolRow" +import { vscEditorBackground } from "@/components/ui" +import { Tail2 } from "@/components/ui/tail" +import { useExtensionState } from "@/context/ExtensionStateContext" +import { findMatchingResourceOrTemplate } from "@/utils/mcp" +import { vscode } from "@/utils/vscode" +import { ViewfinderCircleIcon } from "@heroicons/react/24/outline" +import { OpenInNewWindowIcon } from "@radix-ui/react-icons" +import { VSCodeProgressRing, VSCodeButton } from "@vscode/webview-ui-toolkit/react" +import { PencilIcon, ServerIcon, PlusCircleIcon } from "lucide-react" +import React, { memo, useRef, useEffect, useState, useMemo } from "react" +import { useSize } from "react-use" +import { COMMAND_OUTPUT_STRING } from "../../../src/shared/combineCommandSequences" +import { ClineMessage, ClineApiReqInfo, ClineAskUseMcpServer, ClineSayTool } from "../../../src/shared/ExtensionMessage" +import { useCopyToClipboard } from "@/utils/clipboard" +import deepEqual from "fast-deep-equal" + +interface ChatRowProps { + message: ClineMessage + isExpanded: boolean + onToggleExpand: () => void + lastModifiedMessage: ClineMessage | undefined + isLast: boolean + onHeightChange: (isTaller: boolean) => void + isStreaming: boolean + onEditPlan?: (path: string) => void +} + +interface ChatRowContentProps extends Omit {} + +const ChatRow = memo( + (props: ChatRowProps) => { + const { isLast, onHeightChange, message } = props + // Store the previous height to compare with the current height + // This allows us to detect changes without causing re-renders + const prevHeightRef = useRef(0) + + const [chatrow, { height }] = useSize( +
+ +
, + ) + + useEffect(() => { + // used for partials, command output, etc. + // NOTE: it's important we don't distinguish between partial or complete here since our scroll effects in chatview need to handle height change during partial -> complete + const isInitialRender = prevHeightRef.current === 0 // prevents scrolling when new element is added since we already scroll for that + // height starts off at Infinity + if (isLast && height !== 0 && height !== Infinity && height !== prevHeightRef.current) { + if (!isInitialRender) { + onHeightChange(height > prevHeightRef.current) + } + prevHeightRef.current = height + } + }, [height, isLast, onHeightChange, message]) + + // we cannot return null as virtuoso does not support it, so we use a separate visibleMessages array to filter out messages that should not be rendered + return chatrow + }, + // memo does shallow comparison of props, so we need to do deep comparison of arrays/objects whose properties might change + deepEqual, +) + +export default ChatRow + +export const ChatRowContent = ({ + message, + isExpanded, + onToggleExpand, + lastModifiedMessage, + isLast, + isStreaming, + onEditPlan, +}: ChatRowContentProps) => { + const { mcpServers, alwaysAllowMcp, currentCheckpoint } = useExtensionState() + const [reasoningCollapsed, setReasoningCollapsed] = useState(false) + + // Auto-collapse reasoning when new messages arrive + useEffect(() => { + if (!isLast && message.say === "reasoning") { + setReasoningCollapsed(true) + } + }, [isLast, message.say]) + const [cost, apiReqCancelReason, apiReqStreamingFailedMessage] = useMemo(() => { + if (message.text !== null && message.text !== undefined && message.say === "api_req_started") { + const info: ClineApiReqInfo = JSON.parse(message.text) + return [info.cost, info.cancelReason, info.streamingFailedMessage] + } + return [undefined, undefined, undefined] + }, [message.text, message.say]) + // when resuming task, last wont be api_req_failed but a resume_task message, so api_req_started will show loading spinner. that's why we just remove the last api_req_started that failed without streaming anything + const apiRequestFailedMessage = + isLast && lastModifiedMessage?.ask === "api_req_failed" // if request is retried then the latest message is a api_req_retried + ? lastModifiedMessage?.text + : undefined + const isCommandExecuting = + isLast && lastModifiedMessage?.ask === "command" && lastModifiedMessage?.text?.includes(COMMAND_OUTPUT_STRING) + + const isMcpServerResponding = isLast && lastModifiedMessage?.say === "mcp_server_request_started" + + const type = message.type === "ask" ? message.ask : message.say + + const normalColor = "var(--vscode-foreground)" + const errorColor = "var(--vscode-errorForeground)" + const successColor = "var(--vscode-charts-green)" + const cancelledColor = "var(--vscode-descriptionForeground)" + + const [icon, title] = useMemo(() => { + switch (type) { + case "error": + return [ + , + Error, + ] + case "mistake_limit_reached": + return [ + , + Roo is having trouble..., + ] + case "command": + return [ + isCommandExecuting ? ( + + ) : ( + + ), + + Agent wants to execute this command: + , + ] + case "use_mcp_server": + const mcpServerUse = JSON.parse(message.text || "{}") as ClineAskUseMcpServer + return [ + isMcpServerResponding ? ( + + ) : ( + + ), + + Agent wants to {mcpServerUse.type === "use_mcp_tool" ? "use a tool" : "access a resource"} on + the {mcpServerUse.serverName} MCP server: + , + ] + case "completion_result": + return [ + // + // , +
+ + Task Completed +
, + ] + case "api_req_retry_delayed": + return [] + case "api_req_started": + const getIconSpan = (iconName: string, color: string) => ( +
+ +
+ ) + return [ + apiReqCancelReason !== null && apiReqCancelReason !== undefined ? ( + apiReqCancelReason === "user_cancelled" ? ( + getIconSpan("error", cancelledColor) + ) : ( + getIconSpan("error", errorColor) + ) + ) : cost !== null && cost !== undefined ? ( + getIconSpan("check", successColor) + ) : apiRequestFailedMessage ? ( + getIconSpan("error", errorColor) + ) : ( + + ), + apiReqCancelReason !== null && apiReqCancelReason !== undefined ? ( + apiReqCancelReason === "user_cancelled" ? ( + API Request Cancelled + ) : ( + API Streaming Failed + ) + ) : cost != null && cost !== undefined ? ( + <> + ) : // + // + // API REQUEST + // + apiRequestFailedMessage ? ( + API Request Failed + ) : ( + API Request... + ), + ] + case "followup": + return [ +
+ + ,Roo has a question:, +
, + ] + default: + return [null, null] + } + }, [type, isCommandExecuting, message, isMcpServerResponding, apiReqCancelReason, cost, apiRequestFailedMessage]) + + const headerStyle: React.CSSProperties = { + display: "flex", + alignItems: "center", + gap: "10px", + marginBottom: "10px", + } + + const pStyle: React.CSSProperties = { + margin: 0, + whiteSpace: "pre-wrap", + wordBreak: "break-word", + overflowWrap: "anywhere", + } + + const tool = useMemo(() => { + if (message.ask === "tool" || message.say === "tool") { + return JSON.parse(message.text || "{}") as ClineSayTool + } + return null + }, [message.ask, message.say, message.text]) + + if (tool) { + const toolIcon = (name: string) => ( + + ) + + switch (tool.tool) { + case "editedExistingFile": + case "appliedDiff": + return ( + <> +
+ +
+ Agent wants to edit + + + {removeLeadingNonAlphanumeric(tool.path ?? "") + "\u200E"} + +
+
+ + + ) + case "newFileCreated": + return ( +
+ {/*
+ + Agent wants to create a new file +
*/} + +
+ ) + case "readFile": + return ( + <> + {/* */} +
+ {/* + // @ts-ignore */} + +
+ + {message.type === "ask" ? "Agent wants to read this file" : "Roo read this file:"} + +
{ + vscode.postMessage({ type: "openFile", text: tool.content }) + }}> + {tool.path?.startsWith(".") && .} + + {removeLeadingNonAlphanumeric(tool.path ?? "") + "\u200E"} + +
+ {/* + */} +
+
+ { + vscode.postMessage({ type: "openFile", text: tool.content }) + }} + /> +
+ + ) + case "listFilesTopLevel": + return ( + <> +
+ {toolIcon("folder-opened")} + + {message.type === "ask" + ? "Agent wants to view the top level files in this directory:" + : "Roo viewed the top level files in this directory:"} + +
+ + + ) + case "listFilesRecursive": + return ( + <> +
+ {toolIcon("folder-opened")} + + {message.type === "ask" + ? "Agent wants to recursively view all files in this directory:" + : "Roo recursively viewed all files in this directory:"} + +
+ + + ) + case "listCodeDefinitionNames": + return ( + <> +
+ {toolIcon("file-code")} + + {message.type === "ask" + ? "Agent wants to view source code definition names used in this directory:" + : "Roo viewed source code definition names used in this directory:"} + +
+ + + ) + case "searchFiles": + return ( + <> +
+ {toolIcon("search")} + + {message.type === "ask" ? ( + <> + Agent wants to search this directory for {tool.regex}: + + ) : ( + <> + Roo searched this directory for {tool.regex}: + + )} + +
+ + + ) + // case "inspectSite": + // const isInspecting = + // isLast && lastModifiedMessage?.say === "inspect_site_result" && !lastModifiedMessage?.images + // return ( + // <> + //
+ // {isInspecting ? : toolIcon("inspect")} + // + // {message.type === "ask" ? ( + // <>Agent wants to inspect this website: + // ) : ( + // <>Roo is inspecting this website: + // )} + // + //
+ //
+ // + //
+ // + // ) + case "switchMode": + return ( + <> +
+ {toolIcon("symbol-enum")} + + {message.type === "ask" ? ( + <> + Agent wants to switch to {tool.mode} mode + {tool.reason ? ` because: ${tool.reason}` : ""} + + ) : ( + <> + Roo switched to {tool.mode} mode + {tool.reason ? ` because: ${tool.reason}` : ""} + + )} + +
+ + ) + case "newTask": + return ( + <> +
+ {toolIcon("new-file")} + + Agent wants to create a new task in {tool.mode} mode: + +
+
+ {tool.content} +
+ + ) + default: + return null + } + } + + switch (message.type) { + case "say": + switch (message.say) { + case "reasoning": + return ( + setReasoningCollapsed(!reasoningCollapsed)} + /> + ) + case "api_req_started": + return ( + <> +
+ {/* 0 ? 1 : 0 }} className=""> */} +
+
+
+ {title}${Number(cost || 0)?.toFixed(4)} +
+ {/* */} +
+ {isStreaming && ( +
+ +
+ )} +
+ {/*
*/} +
+ {(((cost === null || cost === undefined) && apiRequestFailedMessage) || + apiReqStreamingFailedMessage) && ( + <> +

+ {apiRequestFailedMessage || apiReqStreamingFailedMessage} + {apiRequestFailedMessage?.toLowerCase().includes("powershell") && ( + <> +
+
+ It seems like you're having Windows PowerShell issues, please see this{" "} + + troubleshooting guide + + . + + )} +

+ + {/* {apiProvider === "" && ( +
+ + + Uh-oh, this could be a problem on end. We've been alerted and + will resolve this ASAP. You can also{" "} + + contact us + + . + +
+ )} */} + + )} + + {isExpanded && ( +
+ +
+ )} + + ) + case "api_req_finished": + return null // we should never see this message type + case "text": + return ( +
+ +
+ ) + case "user_feedback": + return ( +
+ +
+ + {highlightMentions(message.text)} + + + { + e.stopPropagation() + vscode.postMessage({ + type: "deleteMessage", + value: message.ts, + }) + }}> + + +
+ {message.images && message.images.length > 0 && ( + + )} +
+ ) + case "user_feedback_diff": + const tool = JSON.parse(message.text || "{}") as ClineSayTool + return ( +
+ +
+ ) + case "error": + return ( + <> + {title && ( +
+ {icon} + {title} +
+ )} +

{message.text}

+ + ) + case "completion_result": + return ( +
+ {/*
+ {icon} + {title} +
*/} +
+ +
+
+ ) + case "shell_integration_warning": + return ( + <> +
+
+ + + Shell Integration Unavailable + +
+
+ Roo won't be able to view the command's output. Please update VSCode ( + CMD/CTRL + Shift + P → "Update") and make sure you're using a supported + shell: zsh, bash, fish, or PowerShell (CMD/CTRL + Shift + P → + "Terminal: Select Default Profile").{" "} + + Still having trouble? + +
+
+ + ) + case "mcp_server_response": + return ( + <> +
+
+ Response +
+ +
+ + ) + case "checkpoint_saved": + return ( + + ) + default: + return ( + <> + {title && ( +
+ {icon} + {title} +
+ )} +
+ +
+ + ) + } + case "ask": + switch (message.ask) { + case "mistake_limit_reached": + return ( + <> +
+ {icon} + {title} +
+

{message.text}

+ + ) + case "command": + const splitMessage = (text: string) => { + const outputIndex = text.indexOf(COMMAND_OUTPUT_STRING) + if (outputIndex === -1) { + return { command: text, output: "" } + } + return { + command: text.slice(0, outputIndex).trim(), + output: text + .slice(outputIndex + COMMAND_OUTPUT_STRING.length) + .trim() + .split("") + .map((char) => { + switch (char) { + case "\t": + return "→ " + case "\b": + return "⌫" + case "\f": + return "⏏" + case "\v": + return "⇳" + default: + return char + } + }) + .join(""), + } + } + + const { command, output } = splitMessage(message.text || "") + return ( + <> +
+ {icon} + {title} +
+ {/* 0} + /> */} +
+ + {output.length > 0 && ( +
+
+ + Command Output +
+ {isExpanded && } +
+ )} +
+ + ) + case "use_mcp_server": + const useMcpServer = JSON.parse(message.text || "{}") as ClineAskUseMcpServer + const server = mcpServers.find((server) => server.name === useMcpServer.serverName) + return ( + <> +
+ {icon} + {title} +
+ +
+ {useMcpServer.type === "access_mcp_resource" && ( + + )} + + {useMcpServer.type === "use_mcp_tool" && ( + <> +
e.stopPropagation()}> + tool.name === useMcpServer.toolName, + )?.description || "", + alwaysAllow: + server?.tools?.find( + (tool) => tool.name === useMcpServer.toolName, + )?.alwaysAllow || false, + }} + serverName={useMcpServer.serverName} + alwaysAllowMcp={alwaysAllowMcp} + /> +
+ {useMcpServer.arguments && useMcpServer.arguments !== "{}" && ( +
+
+ Arguments +
+ +
+ )} + + )} +
+ + ) + case "completion_result": + if (message.text) { + return ( +
+
+ {icon} + {title} +
+
+ +
+
+ ) + } else { + return null // Don't render anything when we get a completion_result ask without text + } + case "followup": + return ( + <> + {title && ( +
+ {icon} + {title} +
+ )} +
+ +
+ + ) + default: + return null + } + } +} + +export const ProgressIndicator = () => ( +
+
+ +
+
+) + +const Markdown = memo(({ markdown, partial }: { markdown?: string; partial?: boolean }) => { + const [isHovering, setIsHovering] = useState(false) + const { copyWithFeedback } = useCopyToClipboard(200) // shorter feedback duration for copy button flash + + return ( +
setIsHovering(true)} + onMouseLeave={() => setIsHovering(false)} + style={{ position: "relative" }}> +
+ +
+ {markdown && !partial && isHovering && ( +
+ + { + const success = await copyWithFeedback(markdown) + if (success) { + const button = document.activeElement as HTMLElement + if (button) { + button.style.background = "var(--vscode-button-background)" + setTimeout(() => { + button.style.background = "" + }, 200) + } + } + }} + title="Copy as markdown"> + + +
+ )} +
+ ) +}) diff --git a/webview-ui/src/creator/ChatTextArea.tsx b/webview-ui/src/creator/ChatTextArea.tsx new file mode 100644 index 00000000000..ab381c3e4d7 --- /dev/null +++ b/webview-ui/src/creator/ChatTextArea.tsx @@ -0,0 +1,1067 @@ +import ContextMenu from "@/components/chat/ContextMenu" +import { ChevronDown } from "lucide-react" +import Thumbnails from "@/components/common/Thumbnails" +import { + vscEditorBackground, + getFontSize, + lightGray, + vscForeground, + vscInputBackground, + vscInputBorder, + Button, +} from "@/components/ui" +import { useExtensionState } from "@/context/ExtensionStateContext" +import { + ContextMenuOptionType, + insertMention, + getContextMenuOptions, + removeMention, + shouldShowContextMenu, +} from "@/utils/context-mentions" +import { convertToMentionPath } from "@/utils/path-mentions" +import { vscode } from "@/utils/vscode" +import { Listbox } from "@headlessui/react" +import { ArrowTurnDownLeftIcon } from "@heroicons/react/24/outline" +import { TrashIcon, ImageIcon } from "lucide-react" +import React, { forwardRef, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react" +import DynamicTextArea from "react-textarea-autosize" +import styled from "styled-components" +import { mentionRegex, mentionRegexGlobal } from "../../../src/shared/context-mentions" +import { getAllModes, Mode } from "../../../src/shared/modes" +import { WebviewMessage } from "../../../src/shared/WebviewMessage" +import { MAX_IMAGES_PER_MESSAGE } from "./Creator" + +const StyledListboxButton = styled(Listbox.Button)` + border: none; + background-color: ${vscEditorBackground}; + border-radius: 8px; + padding: 8px; + display: flex; + align-items: center; + gap: 2px; + user-select: none; + cursor: pointer; + font-size: ${getFontSize() - 3}px; + color: ${lightGray}; + &:focus { + outline: none; + } +` + +const StyledListboxOptions = styled(Listbox.Options)<{ newSession: boolean }>` + position: absolute; + bottom: 100%; + left: 0; + margin-bottom: 4px; + list-style: none; + padding: 6px; + white-space: nowrap; + cursor: default; + z-index: 50; + border: 1px solid ${lightGray}10; + border-radius: 10px; + background-color: ${vscEditorBackground}; + max-height: 300px; + min-width: 100px; + overflow-y: auto; + + font-size: ${getFontSize() - 2}px; + user-select: none; + outline: none; + + &::-webkit-scrollbar { + display: none; + } + + scrollbar-width: none; + -ms-overflow-style: none; + + & > * { + margin: 4px 0; + } +` + +interface ListboxOptionProps { + isCurrentModel?: boolean +} + +const StyledListboxOption = styled(Listbox.Option)` + cursor: pointer; + border-radius: 6px; + padding: 5px 4px; + + &:hover { + background: ${(props) => (props.isCurrentModel ? `${lightGray}66` : `${lightGray}33`)}; + } + + background: ${(props) => (props.isCurrentModel ? `${lightGray}66` : "transparent")}; +` + +const StyledTrashIcon = styled(TrashIcon as React.ComponentType)` + cursor: pointer; + flex-shrink: 0; + margin-left: 8px; + &:hover { + color: red; + } +` + +const Divider = styled.div` + height: 2px; + background-color: ${lightGray}35; + margin: 0px 4px; +` + +const ListboxWrapper = styled.div` + position: relative; + display: inline-block; +` + +interface ChatTextAreaProps { + inputValue: string + setInputValue: (value: string) => void + textAreaDisabled: boolean + placeholderText: string + selectedImages: string[] + setSelectedImages: React.Dispatch> + onSend: () => void + onSelectImages: () => void + shouldDisableImages: boolean + onHeightChange?: (height: number) => void + mode: Mode + setMode: (value: Mode) => void + isNewTask: boolean +} + +const ChatTextArea = forwardRef( + ( + { + inputValue, + setInputValue, + textAreaDisabled, + placeholderText, + selectedImages, + setSelectedImages, + onSend, + onSelectImages, + shouldDisableImages, + onHeightChange, + mode, + setMode, + isNewTask, + }, + ref, + ) => { + const { filePaths, openedTabs, currentApiConfigName, listApiConfigMeta, customModes, cwd } = useExtensionState() + const [gitCommits, setGitCommits] = useState([]) + const [showDropdown, setShowDropdown] = useState(false) + + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (showDropdown) { + setShowDropdown(false) + } + } + document.addEventListener("mousedown", handleClickOutside) + return () => document.removeEventListener("mousedown", handleClickOutside) + }, [showDropdown]) + + // Handle enhanced prompt response + useEffect(() => { + const messageHandler = (event: MessageEvent) => { + const message = event.data + if (message.type === "enhancedPrompt") { + if (message.text) { + setInputValue(message.text) + } + setIsEnhancingPrompt(false) + } else if (message.type === "commitSearchResults") { + const commits = message.commits.map((commit: any) => ({ + type: ContextMenuOptionType.Git, + value: commit.hash, + label: commit.subject, + description: `${commit.shortHash} by ${commit.author} on ${commit.date}`, + icon: "$(git-commit)", + })) + setGitCommits(commits) + } + } + window.addEventListener("message", messageHandler) + return () => window.removeEventListener("message", messageHandler) + }, [setInputValue]) + + const [thumbnailsHeight, setThumbnailsHeight] = useState(0) + const [textAreaBaseHeight, setTextAreaBaseHeight] = useState(undefined) + const [showContextMenu, setShowContextMenu] = useState(false) + const [cursorPosition, setCursorPosition] = useState(0) + const [searchQuery, setSearchQuery] = useState("") + const textAreaRef = useRef(null) + const [isMouseDownOnMenu, setIsMouseDownOnMenu] = useState(false) + const highlightLayerRef = useRef(null) + const [selectedMenuIndex, setSelectedMenuIndex] = useState(-1) + const [selectedType, setSelectedType] = useState(null) + const [justDeletedSpaceAfterMention, setJustDeletedSpaceAfterMention] = useState(false) + const [intendedCursorPosition, setIntendedCursorPosition] = useState(null) + const contextMenuContainerRef = useRef(null) + const [isEnhancingPrompt, setIsEnhancingPrompt] = useState(false) + const [isFocused, setIsFocused] = useState(false) + + // Fetch git commits when Git is selected or when typing a hash + useEffect(() => { + if (selectedType === ContextMenuOptionType.Git || /^[a-f0-9]+$/i.test(searchQuery)) { + const message: WebviewMessage = { + type: "searchCommits", + query: searchQuery || "", + } as const + vscode.postMessage(message) + } + }, [selectedType, searchQuery]) + + const handleEnhancePrompt = useCallback(() => { + if (!textAreaDisabled) { + const trimmedInput = inputValue.trim() + if (trimmedInput) { + setIsEnhancingPrompt(true) + const message = { + type: "enhancePrompt" as const, + text: trimmedInput, + } + vscode.postMessage(message) + } else { + const promptDescription = + "The 'Enhance Prompt' button helps improve your prompt by providing additional context, clarification, or rephrasing. Try typing a prompt in here and clicking the button again to see how it works." + setInputValue(promptDescription) + } + } + }, [inputValue, textAreaDisabled, setInputValue]) + + const queryItems = useMemo(() => { + return [ + { type: ContextMenuOptionType.Problems, value: "problems" }, + { type: ContextMenuOptionType.Terminal, value: "terminal" }, + ...gitCommits, + ...openedTabs + .filter((tab) => tab.path) + .map((tab) => ({ + type: ContextMenuOptionType.OpenedFile, + value: "/" + tab.path, + })), + ...filePaths + .map((file) => "/" + file) + .filter((path) => !openedTabs.some((tab) => tab.path && "/" + tab.path === path)) // Filter out paths that are already in openedTabs + .map((path) => ({ + type: path.endsWith("/") ? ContextMenuOptionType.Folder : ContextMenuOptionType.File, + value: path, + })), + ] + }, [filePaths, gitCommits, openedTabs]) + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + contextMenuContainerRef.current && + !contextMenuContainerRef.current.contains(event.target as Node) + ) { + setShowContextMenu(false) + } + } + + if (showContextMenu) { + document.addEventListener("mousedown", handleClickOutside) + } + + return () => { + document.removeEventListener("mousedown", handleClickOutside) + } + }, [showContextMenu, setShowContextMenu]) + + const handleMentionSelect = useCallback( + (type: ContextMenuOptionType, value?: string) => { + if (type === ContextMenuOptionType.NoResults) { + return + } + + if (type === ContextMenuOptionType.Mode && value) { + // Handle mode selection + setMode(value) + setInputValue("") + setShowContextMenu(false) + vscode.postMessage({ + type: "mode", + text: value, + }) + return + } + + if ( + type === ContextMenuOptionType.File || + type === ContextMenuOptionType.Folder || + type === ContextMenuOptionType.Git + ) { + if (!value) { + setSelectedType(type) + setSearchQuery("") + setSelectedMenuIndex(0) + return + } + } + + setShowContextMenu(false) + setSelectedType(null) + if (textAreaRef.current) { + let insertValue = value || "" + if (type === ContextMenuOptionType.URL) { + insertValue = value || "" + } else if (type === ContextMenuOptionType.File || type === ContextMenuOptionType.Folder) { + insertValue = value || "" + } else if (type === ContextMenuOptionType.Problems) { + insertValue = "problems" + } else if (type === ContextMenuOptionType.Terminal) { + insertValue = "terminal" + } else if (type === ContextMenuOptionType.Git) { + insertValue = value || "" + } + + const { newValue, mentionIndex } = insertMention( + textAreaRef.current.value, + cursorPosition, + insertValue, + ) + + setInputValue(newValue) + const newCursorPosition = newValue.indexOf(" ", mentionIndex + insertValue.length) + 1 + setCursorPosition(newCursorPosition) + setIntendedCursorPosition(newCursorPosition) + + // scroll to cursor + setTimeout(() => { + if (textAreaRef.current) { + textAreaRef.current.blur() + textAreaRef.current.focus() + } + }, 0) + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [setInputValue, cursorPosition], + ) + + const handleKeyDown = useCallback( + (event: React.KeyboardEvent) => { + if (showContextMenu) { + if (event.key === "Escape") { + setSelectedType(null) + setSelectedMenuIndex(3) // File by default + return + } + + if (event.key === "ArrowUp" || event.key === "ArrowDown") { + event.preventDefault() + setSelectedMenuIndex((prevIndex) => { + const direction = event.key === "ArrowUp" ? -1 : 1 + const options = getContextMenuOptions(searchQuery, selectedType, queryItems) + const optionsLength = options.length + + if (optionsLength === 0) return prevIndex + + // Find selectable options (non-URL types) + const selectableOptions = options.filter( + (option) => + option.type !== ContextMenuOptionType.URL && + option.type !== ContextMenuOptionType.NoResults, + ) + + if (selectableOptions.length === 0) return -1 // No selectable options + + // Find the index of the next selectable option + const currentSelectableIndex = selectableOptions.findIndex( + (option) => option === options[prevIndex], + ) + + const newSelectableIndex = + (currentSelectableIndex + direction + selectableOptions.length) % + selectableOptions.length + + // Find the index of the selected option in the original options array + return options.findIndex((option) => option === selectableOptions[newSelectableIndex]) + }) + return + } + if ((event.key === "Enter" || event.key === "Tab") && selectedMenuIndex !== -1) { + event.preventDefault() + const selectedOption = getContextMenuOptions(searchQuery, selectedType, queryItems)[ + selectedMenuIndex + ] + if ( + selectedOption && + selectedOption.type !== ContextMenuOptionType.URL && + selectedOption.type !== ContextMenuOptionType.NoResults + ) { + handleMentionSelect(selectedOption.type, selectedOption.value) + } + return + } + } + + const isComposing = event.nativeEvent?.isComposing ?? false + if (event.key === "Enter" && !event.shiftKey && !isComposing) { + event.preventDefault() + onSend() + } + + if (event.key === "Backspace" && !isComposing) { + const charBeforeCursor = inputValue[cursorPosition - 1] + const charAfterCursor = inputValue[cursorPosition + 1] + + const charBeforeIsWhitespace = + charBeforeCursor === " " || charBeforeCursor === "\n" || charBeforeCursor === "\r\n" + const charAfterIsWhitespace = + charAfterCursor === " " || charAfterCursor === "\n" || charAfterCursor === "\r\n" + // checks if char before cusor is whitespace after a mention + if ( + charBeforeIsWhitespace && + inputValue.slice(0, cursorPosition - 1).match(new RegExp(mentionRegex.source + "$")) // "$" is added to ensure the match occurs at the end of the string + ) { + const newCursorPosition = cursorPosition - 1 + // if mention is followed by another word, then instead of deleting the space separating them we just move the cursor to the end of the mention + if (!charAfterIsWhitespace) { + event.preventDefault() + textAreaRef.current?.setSelectionRange(newCursorPosition, newCursorPosition) + setCursorPosition(newCursorPosition) + } + setCursorPosition(newCursorPosition) + setJustDeletedSpaceAfterMention(true) + } else if (justDeletedSpaceAfterMention) { + const { newText, newPosition } = removeMention(inputValue, cursorPosition) + if (newText !== inputValue) { + event.preventDefault() + setInputValue(newText) + setIntendedCursorPosition(newPosition) // Store the new cursor position in state + } + setJustDeletedSpaceAfterMention(false) + setShowContextMenu(false) + } else { + setJustDeletedSpaceAfterMention(false) + } + } + }, + [ + onSend, + showContextMenu, + searchQuery, + selectedMenuIndex, + handleMentionSelect, + selectedType, + inputValue, + cursorPosition, + setInputValue, + justDeletedSpaceAfterMention, + queryItems, + ], + ) + + useLayoutEffect(() => { + if (intendedCursorPosition !== null && textAreaRef.current) { + textAreaRef.current.setSelectionRange(intendedCursorPosition, intendedCursorPosition) + setIntendedCursorPosition(null) // Reset the state + } + }, [inputValue, intendedCursorPosition]) + + const handleInputChange = useCallback( + (e: React.ChangeEvent) => { + const newValue = e.target.value + const newCursorPosition = e.target.selectionStart + setInputValue(newValue) + setCursorPosition(newCursorPosition) + const showMenu = shouldShowContextMenu(newValue, newCursorPosition) + + setShowContextMenu(showMenu) + if (showMenu) { + if (newValue.startsWith("/")) { + // Handle slash command + const query = newValue + setSearchQuery(query) + setSelectedMenuIndex(0) + } else { + // Existing @ mention handling + const lastAtIndex = newValue.lastIndexOf("@", newCursorPosition - 1) + const query = newValue.slice(lastAtIndex + 1, newCursorPosition) + setSearchQuery(query) + if (query.length > 0) { + setSelectedMenuIndex(0) + } else { + setSelectedMenuIndex(3) // Set to "File" option by default + } + } + } else { + setSearchQuery("") + setSelectedMenuIndex(-1) + } + }, + [setInputValue], + ) + + useEffect(() => { + if (!showContextMenu) { + setSelectedType(null) + } + }, [showContextMenu]) + + const handleBlur = useCallback(() => { + // Only hide the context menu if the user didn't click on it + if (!isMouseDownOnMenu) { + setShowContextMenu(false) + } + setIsFocused(false) + }, [isMouseDownOnMenu]) + + const handlePaste = useCallback( + async (e: React.ClipboardEvent) => { + const items = e.clipboardData.items + + const pastedText = e.clipboardData.getData("text") + // Check if the pasted content is a URL, add space after so user can easily delete if they don't want it + const urlRegex = /^\S+:\/\/\S+$/ + if (urlRegex.test(pastedText.trim())) { + e.preventDefault() + const trimmedUrl = pastedText.trim() + const newValue = + inputValue.slice(0, cursorPosition) + trimmedUrl + " " + inputValue.slice(cursorPosition) + setInputValue(newValue) + const newCursorPosition = cursorPosition + trimmedUrl.length + 1 + setCursorPosition(newCursorPosition) + setIntendedCursorPosition(newCursorPosition) + setShowContextMenu(false) + + // Scroll to new cursor position + setTimeout(() => { + if (textAreaRef.current) { + textAreaRef.current.blur() + textAreaRef.current.focus() + } + }, 0) + + return + } + + const acceptedTypes = ["png", "jpeg", "webp"] + const imageItems = Array.from(items).filter((item) => { + const [type, subtype] = item.type.split("/") + return type === "image" && acceptedTypes.includes(subtype) + }) + if (!shouldDisableImages && imageItems.length > 0) { + e.preventDefault() + const imagePromises = imageItems.map((item) => { + return new Promise((resolve) => { + const blob = item.getAsFile() + if (!blob) { + resolve(null) + return + } + const reader = new FileReader() + reader.onloadend = () => { + if (reader.error) { + console.error("Error reading file:", reader.error) + resolve(null) + } else { + const result = reader.result + resolve(typeof result === "string" ? result : null) + } + } + reader.readAsDataURL(blob) + }) + }) + const imageDataArray = await Promise.all(imagePromises) + const dataUrls = imageDataArray.filter((dataUrl): dataUrl is string => dataUrl !== null) + if (dataUrls.length > 0) { + setSelectedImages((prevImages) => [...prevImages, ...dataUrls].slice(0, MAX_IMAGES_PER_MESSAGE)) + } else { + console.warn("No valid images were processed") + } + } + }, + [shouldDisableImages, setSelectedImages, cursorPosition, setInputValue, inputValue], + ) + + const handleThumbnailsHeightChange = useCallback((height: number) => { + setThumbnailsHeight(height) + }, []) + + useEffect(() => { + if (selectedImages.length === 0) { + setThumbnailsHeight(0) + } + }, [selectedImages]) + + const handleMenuMouseDown = useCallback(() => { + setIsMouseDownOnMenu(true) + }, []) + + const updateHighlights = useCallback(() => { + if (!textAreaRef.current || !highlightLayerRef.current) return + + const text = textAreaRef.current.value + + highlightLayerRef.current.innerHTML = text + .replace(/\n$/, "\n\n") + .replace(/[<>&]/g, (c) => ({ "<": "<", ">": ">", "&": "&" })[c] || c) + .replace(mentionRegexGlobal, '$&') + + highlightLayerRef.current.scrollTop = textAreaRef.current.scrollTop + highlightLayerRef.current.scrollLeft = textAreaRef.current.scrollLeft + }, []) + + useLayoutEffect(() => { + updateHighlights() + }, [inputValue, updateHighlights]) + + const updateCursorPosition = useCallback(() => { + if (textAreaRef.current) { + setCursorPosition(textAreaRef.current.selectionStart) + } + }, []) + + const handleKeyUp = useCallback( + (e: React.KeyboardEvent) => { + if (["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"].includes(e.key)) { + updateCursorPosition() + } + }, + [updateCursorPosition], + ) + + return ( + <> +
{ + e.preventDefault() + const files = Array.from(e.dataTransfer.files) + const text = e.dataTransfer.getData("text") + if (text) { + // Split text on newlines to handle multiple files + const lines = text.split(/\r?\n/).filter((line) => line.trim() !== "") + + if (lines.length > 0) { + // Process each line as a separate file path + let newValue = inputValue.slice(0, cursorPosition) + let totalLength = 0 + + lines.forEach((line, index) => { + // Convert each path to a mention-friendly format + const mentionText = convertToMentionPath(line, cwd) + newValue += mentionText + totalLength += mentionText.length + + // Add space after each mention except the last one + if (index < lines.length - 1) { + newValue += " " + totalLength += 1 + } + }) + + // Add space after the last mention and append the rest of the input + newValue += " " + inputValue.slice(cursorPosition) + totalLength += 1 + + setInputValue(newValue) + const newCursorPosition = cursorPosition + totalLength + setCursorPosition(newCursorPosition) + setIntendedCursorPosition(newCursorPosition) + } + return + } + + const acceptedTypes = ["png", "jpeg", "webp"] + const imageFiles = files.filter((file) => { + const [type, subtype] = file.type.split("/") + return type === "image" && acceptedTypes.includes(subtype) + }) + + if (!shouldDisableImages && imageFiles.length > 0) { + const imagePromises = imageFiles.map((file) => { + return new Promise((resolve) => { + const reader = new FileReader() + reader.onloadend = () => { + if (reader.error) { + console.error("Error reading file:", reader.error) + resolve(null) + } else { + const result = reader.result + resolve(typeof result === "string" ? result : null) + } + } + reader.readAsDataURL(file) + }) + }) + const imageDataArray = await Promise.all(imagePromises) + const dataUrls = imageDataArray.filter((dataUrl): dataUrl is string => dataUrl !== null) + if (dataUrls.length > 0) { + setSelectedImages((prevImages) => + [...prevImages, ...dataUrls].slice(0, MAX_IMAGES_PER_MESSAGE), + ) + if (typeof vscode !== "undefined") { + vscode.postMessage({ + type: "draggedImages", + dataUrls: dataUrls, + }) + } + } else { + console.warn("No valid images were processed") + } + } + }} + onDragOver={(e) => { + e.preventDefault() + }}> + {showContextMenu && ( +
+ +
+ )} + {showContextMenu && ( +
+ +
+ )} + + {showContextMenu && ( +
+ +
+ )} + + {inputValue && ( +
+
+ + !shouldDisableImages && onSelectImages()} + /> +
+
+ )} + +
+
0 ? `${thumbnailsHeight + 16}px` : 0, + zIndex: 1, + }} + /> + { + if (typeof ref === "function") { + ref(el) + } else if (ref) { + ref.current = el + } + textAreaRef.current = el + }} + value={inputValue} + disabled={textAreaDisabled} + onChange={(e) => { + handleInputChange(e) + updateHighlights() + }} + onFocus={() => setIsFocused(true)} + onKeyDown={handleKeyDown} + onKeyUp={handleKeyUp} + onBlur={handleBlur} + onPaste={handlePaste} + onSelect={updateCursorPosition} + onMouseUp={updateCursorPosition} + onHeightChange={(height) => { + if (textAreaBaseHeight === undefined || height < textAreaBaseHeight) { + setTextAreaBaseHeight(height) + } + onHeightChange?.(height) + }} + placeholder={placeholderText} + minRows={isNewTask ? 3 : 1} + maxRows={15} + autoFocus={true} + style={{ + width: "100%", + outline: "none", + boxSizing: "border-box", + backgroundColor: "transparent", + color: "var(--vscode-input-foreground)", + borderRadius: 2, + fontFamily: "var(--vscode-font-family)", + fontSize: "var(--vscode-editor-font-size)", + lineHeight: "var(--vscode-editor-line-height)", + resize: "none", + overflowX: "hidden", + overflowY: "auto", + border: "none", + padding: "2px", + paddingTop: "8px", + paddingBottom: "8px", + paddingRight: "8px", + marginBottom: thumbnailsHeight > 0 ? `${thumbnailsHeight + 16}px` : 0, + cursor: textAreaDisabled ? "not-allowed" : undefined, + flex: "0 1 auto", + zIndex: 2, + scrollbarWidth: "none", + }} + onScroll={() => updateHighlights()} + /> +
+ + {selectedImages.length > 0 && ( + + )} + + {inputValue && ( +
+
+ +
+
+ {isEnhancingPrompt ? ( + + ) : ( + !textAreaDisabled && handleEnhancePrompt()} + style={{ fontSize: 16.5 }} + /> + )} +
+ + +
+
+ )} +
+
+ + { + if (value === "prompts-action") { + window.postMessage({ type: "action", action: "promptsButtonClicked" }) + return + } + setMode(value as Mode) + vscode.postMessage({ + type: "mode", + text: value, + }) + }} + disabled={textAreaDisabled}> + + {getAllModes(customModes).find((m) => m.slug === mode)?.name} + + + + {getAllModes(customModes).map((mode) => ( + + {mode.name} + + ))} + + + Edit... + + + + + + + { + if (value === "settings-action") { + window.postMessage({ type: "action", action: "settingsButtonClicked" }) + return + } + vscode.postMessage({ + type: "loadApiConfiguration", + text: value, + }) + }} + disabled={textAreaDisabled}> + + {currentApiConfigName} + + + + {(listApiConfigMeta || []).map((config) => ( + + {config.name} + + ))} + + + Edit... + + + + +
+ + ) + }, +) + +export default ChatTextArea diff --git a/webview-ui/src/creator/CodeAccordian.tsx b/webview-ui/src/creator/CodeAccordian.tsx new file mode 100644 index 00000000000..7f6d5f93282 --- /dev/null +++ b/webview-ui/src/creator/CodeAccordian.tsx @@ -0,0 +1,144 @@ +import CodeBlock, { CODE_BLOCK_BG_COLOR } from "./CodeBlock" +import { getLanguageFromPath } from "@/utils/getLanguageFromPath" +import { useMemo, memo } from "react" +import { Button } from "@/components/ui" + +interface CodeAccordianProps { + code?: string + diff?: string + language?: string | undefined + path?: string + isFeedback?: boolean + isConsoleLogs?: boolean + isExpanded: boolean + onToggleExpand: () => void + isLoading?: boolean + onEditPlan?: (path: string) => void +} + +/* +We need to remove leading non-alphanumeric characters from the path in order for our leading ellipses trick to work. +^: Anchors the match to the start of the string. +[^a-zA-Z0-9]+: Matches one or more characters that are not alphanumeric. +The replace method removes these matched characters, effectively trimming the string up to the first alphanumeric character. +*/ +export const removeLeadingNonAlphanumeric = (path: string): string => path.replace(/^[^a-zA-Z0-9]+/, "") + +const CodeAccordian = ({ + code, + diff, + language, + path, + isFeedback, + isConsoleLogs, + isExpanded, + onToggleExpand, + isLoading, + onEditPlan, +}: CodeAccordianProps) => { + const inferredLanguage = useMemo( + () => code && (language ?? (path ? getLanguageFromPath(path) : undefined)), + [path, language, code], + ) + + return ( +
+ {(path || isFeedback || isConsoleLogs) && ( +
+ {isFeedback || isConsoleLogs ? ( +
+ + + {isFeedback ? "User Edits" : "Console Logs"} + +
+ ) : ( + <> + {path?.startsWith(".") && .} + + {/* {removeLeadingNonAlphanumeric(path ?? "") + "\u200E"} */} + {path} + + + )} +
+ {path && !isFeedback && !isConsoleLogs && ( + + )} + +
+ )} + {(!(path || isFeedback || isConsoleLogs) || isExpanded) && ( +
+ +
+ )} +
+ ) +} + +// memo does shallow comparison of props, so if you need it to re-render when a nested object changes, you need to pass a custom comparison function +export default memo(CodeAccordian) diff --git a/webview-ui/src/creator/CodeBlock.tsx b/webview-ui/src/creator/CodeBlock.tsx new file mode 100644 index 00000000000..7b861f9043e --- /dev/null +++ b/webview-ui/src/creator/CodeBlock.tsx @@ -0,0 +1,161 @@ +import { useExtensionState } from "@/context/ExtensionStateContext" +import { memo, useEffect } from "react" +import { useRemark } from "react-remark" +import rehypeHighlight, { Options } from "rehype-highlight" +import styled from "styled-components" +import { visit } from "unist-util-visit" + +export const CODE_BLOCK_BG_COLOR = "var(--vscode-sideBar-background, --vscode-editor-background, rgb(30 30 30))" + +/* +overflowX: auto + inner div with padding results in an issue where the top/left/bottom padding renders but the right padding inside does not count as overflow as the width of the element is not exceeded. Once the inner div is outside the boundaries of the parent it counts as overflow. +https://stackoverflow.com/questions/60778406/why-is-padding-right-clipped-with-overflowscroll/77292459#77292459 +this fixes the issue of right padding clipped off +“ideal” size in a given axis when given infinite available space--allows the syntax highlighter to grow to largest possible width including its padding +minWidth: "max-content", +*/ + +interface CodeBlockProps { + source?: string + forceWrap?: boolean +} + +const StyledMarkdown = styled.div<{ forceWrap: boolean }>` + ${({ forceWrap }) => + forceWrap && + ` + pre, code { + white-space: pre-wrap; + word-break: break-all; + overflow-wrap: anywhere; + padding: 12px 12px; + } + `} + + pre { + background-color: ${CODE_BLOCK_BG_COLOR}; + border-radius: 5px; + margin: 0; + min-width: ${({ forceWrap }) => (forceWrap ? "auto" : "max-content")}; + padding: 10px 10px; + } + + pre > code { + .hljs-deletion { + background-color: var(--vscode-diffEditor-removedTextBackground); + display: inline-block; + width: 100%; + } + .hljs-addition { + background-color: var(--vscode-diffEditor-insertedTextBackground); + display: inline-block; + width: 100%; + } + } + + code { + span.line:empty { + display: none; + } + word-wrap: break-word; + border-radius: 5px; + background-color: ${CODE_BLOCK_BG_COLOR}; + font-size: var(--vscode-editor-font-size, var(--vscode-font-size, 12px)); + font-family: var(--vscode-editor-font-family); + } + + code:not(pre > code) { + font-family: var(--vscode-editor-font-family); + color: #f78383; + } + + background-color: ${CODE_BLOCK_BG_COLOR}; + font-family: + var(--vscode-font-family), + system-ui, + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + Oxygen, + Ubuntu, + Cantarell, + "Open Sans", + "Helvetica Neue", + sans-serif; + font-size: var(--vscode-editor-font-size, var(--vscode-font-size, 12px)); + color: var(--vscode-editor-foreground, #fff); + + p, + li, + ol, + ul { + line-height: 1.5; + } +` + +const StyledPre = styled.pre<{ theme: any }>` + & .hljs { + color: var(--vscode-editor-foreground, #fff); + } + + ${(props) => + Object.keys(props.theme) + .map((key, index) => { + return ` + & ${key} { + color: ${props.theme[key]}; + } + ` + }) + .join("")} +` + +const CodeBlock = memo(({ source, forceWrap = false }: CodeBlockProps) => { + const { theme } = useExtensionState() + const [reactContent, setMarkdownSource] = useRemark({ + remarkPlugins: [ + () => { + return (tree) => { + visit(tree, "code", (node: any) => { + if (!node.lang) { + node.lang = "javascript" + } else if (node.lang.includes(".")) { + // if the language is a file, get the extension + node.lang = node.lang.split(".").slice(-1)[0] + } + }) + } + }, + ], + rehypePlugins: [ + rehypeHighlight as any, + { + // languages: {}, + } as Options, + ], + rehypeReactOptions: { + components: { + pre: ({ node, ...preProps }: any) => , + }, + }, + }) + + useEffect(() => { + setMarkdownSource(source || "") + }, [source, setMarkdownSource, theme]) + + return ( +
+ {reactContent} +
+ ) +}) + +export default CodeBlock diff --git a/webview-ui/src/creator/Creator.tsx b/webview-ui/src/creator/Creator.tsx new file mode 100644 index 00000000000..21ddf2c4659 --- /dev/null +++ b/webview-ui/src/creator/Creator.tsx @@ -0,0 +1,1303 @@ +import { VSCodeButton, VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react" +import debounce from "debounce" +import { useCallback, useEffect, useMemo, useRef, useState } from "react" +import { useDeepCompareEffect, useEvent, useMount } from "react-use" +import { Virtuoso, type VirtuosoHandle } from "react-virtuoso" +import styled from "styled-components" + +import splashIcon from "../../../assets/icons/pearai-agent-splash.svg" +import AutoApproveMenu from "@/components/chat/AutoApproveMenu" +import BrowserSessionRow from "@/components/chat/BrowserSessionRow" +import ChatRow from "./ChatRow" +import ChatTextArea from "./ChatTextArea" +import TaskHeader from "./TaskHeader" +import HistoryPreview from "@/components/history/HistoryPreview" +import { normalizeApiConfiguration } from "@/components/settings/ApiOptions" +import { Button, vscBackground, vscButtonBackground, vscEditorBackground, vscSidebarBorder } from "@/components/ui" +import { useExtensionState } from "@/context/ExtensionStateContext" +import { usePearAiModels } from "@/hooks/usePearAiModels" +import { validateCommand } from "@/utils/command-validation" +import { vscode } from "@/utils/vscode" +import { findLast } from "../../../src/shared/array" +import { combineApiRequests } from "../../../src/shared/combineApiRequests" +import { combineCommandSequences } from "../../../src/shared/combineCommandSequences" +import { + ClineAsk, + ClineSayTool, + ExtensionMessage, + ClineMessage, + ClineSayBrowserAction, +} from "../../../src/shared/ExtensionMessage" +import { getApiMetrics } from "../../../src/shared/getApiMetrics" +import { McpServer, McpTool } from "../../../src/shared/mcp" +import { AudioType } from "../../../src/shared/WebviewMessage" +import SplitView from "./SplitView" +import { set } from "zod" + +interface ChatViewProps { + isHidden?: boolean + showAnnouncement?: boolean + hideAnnouncement?: () => void + showHistoryView?: () => void +} + +export const MAX_IMAGES_PER_MESSAGE = 20 // Anthropic limits to 20 images + +const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryView }: ChatViewProps) => { + const { + version, + clineMessages: messages, + taskHistory, + apiConfiguration, + mcpServers, + alwaysAllowBrowser, + alwaysAllowReadOnly, + alwaysAllowWrite, + alwaysAllowExecute, + alwaysAllowMcp, + allowedCommands, + writeDelayMs, + mode, + setMode, + autoApprovalEnabled, + alwaysAllowModeSwitch, + } = useExtensionState() + + //const task = messages.length > 0 ? (messages[0].say === "task" ? messages[0] : undefined) : undefined) : undefined + const task = useMemo(() => messages.at(0), [messages]) // leaving this less safe version here since if the first message is not a task, then the extension is in a bad state and needs to be debugged (see Cline.abort) + const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages]) + // has to be after api_req_finished are all reduced into api_req_started messages + const apiMetrics = useMemo(() => getApiMetrics(modifiedMessages), [modifiedMessages]) + + const [inputValue, setInputValue] = useState("") + const textAreaRef = useRef(null) + const [textAreaDisabled, setTextAreaDisabled] = useState(false) + const [selectedImages, setSelectedImages] = useState([]) + + // we need to hold on to the ask because useEffect > lastMessage will always let us know when an ask comes in and handle it, but by the time handleMessage is called, the last message might not be the ask anymore (it could be a say that followed) + const [clineAsk, setClineAsk] = useState(undefined) + const [enableButtons, setEnableButtons] = useState(false) + const [primaryButtonText, setPrimaryButtonText] = useState(undefined) + const [secondaryButtonText, setSecondaryButtonText] = useState(undefined) + const [didClickCancel, setDidClickCancel] = useState(false) + const virtuosoRef = useRef(null) + const [expandedRows, setExpandedRows] = useState>({}) + const scrollContainerRef = useRef(null) + const disableAutoScrollRef = useRef(false) + const [showScrollToBottom, setShowScrollToBottom] = useState(false) + const [isAtBottom, setIsAtBottom] = useState(false) + + const [wasStreaming, setWasStreaming] = useState(false) + const [editingFilePath, setEditingFilePath] = useState(() => { + return null + }) + const [includePlanningPhase, setIncludePlanningPhase] = useState(true) + + // UI layout depends on the last 2 messages + // (since it relies on the content of these messages, we are deep comparing. i.e. the button state after hitting button sets enableButtons to false, and this effect otherwise would have to true again even if messages didn't change + const lastMessage = useMemo(() => messages.at(-1), [messages]) + const secondLastMessage = useMemo(() => messages.at(-2), [messages]) + + const handleEditPlan = useCallback((path: string) => { + setEditingFilePath(path) + }, []) + + function playSound(audioType: AudioType) { + vscode.postMessage({ type: "playSound", audioType }) + } + + useDeepCompareEffect(() => { + // if last message is an ask, show user ask UI + // if user finished a task, then start a new task with a new conversation history since in this moment that the extension is waiting for user response, the user could close the extension and the conversation history would be lost. + // basically as long as a task is active, the conversation history will be persisted + if (lastMessage) { + switch (lastMessage.type) { + case "ask": + const isPartial = lastMessage.partial === true + switch (lastMessage.ask) { + case "api_req_failed": + playSound("progress_loop") + setTextAreaDisabled(true) + setClineAsk("api_req_failed") + setEnableButtons(true) + setPrimaryButtonText("Retry") + setSecondaryButtonText("Start New Task") + break + case "mistake_limit_reached": + playSound("progress_loop") + setTextAreaDisabled(false) + setClineAsk("mistake_limit_reached") + setEnableButtons(true) + setPrimaryButtonText("Proceed Anyways") + setSecondaryButtonText("Start New Task") + break + case "followup": + setTextAreaDisabled(isPartial) + setClineAsk("followup") + setEnableButtons(isPartial) + // setPrimaryButtonText(undefined) + // setSecondaryButtonText(undefined) + break + case "tool": + if (!isAutoApproved(lastMessage)) { + playSound("notification") + } + setTextAreaDisabled(isPartial) + setClineAsk("tool") + setEnableButtons(!isPartial) + const tool = JSON.parse(lastMessage.text || "{}") as ClineSayTool + switch (tool.tool) { + case "editedExistingFile": + case "appliedDiff": + case "newFileCreated": + setPrimaryButtonText("Save") + setSecondaryButtonText("Reject") + break + default: + setPrimaryButtonText("Approve") + setSecondaryButtonText("Reject") + break + } + break + case "browser_action_launch": + if (!isAutoApproved(lastMessage)) { + playSound("notification") + } + setTextAreaDisabled(isPartial) + setClineAsk("browser_action_launch") + setEnableButtons(!isPartial) + setPrimaryButtonText("Approve") + setSecondaryButtonText("Reject") + break + case "command": + if (!isAutoApproved(lastMessage)) { + playSound("notification") + } + setTextAreaDisabled(isPartial) + setClineAsk("command") + setEnableButtons(!isPartial) + setPrimaryButtonText("Run Command") + setSecondaryButtonText("Reject") + break + case "command_output": + setTextAreaDisabled(false) + setClineAsk("command_output") + setEnableButtons(true) + setPrimaryButtonText("Proceed While Running") + setSecondaryButtonText(undefined) + break + case "use_mcp_server": + setTextAreaDisabled(isPartial) + setClineAsk("use_mcp_server") + setEnableButtons(!isPartial) + setPrimaryButtonText("Approve") + setSecondaryButtonText("Reject") + break + case "completion_result": + // extension waiting for feedback. but we can just present a new task button + playSound("celebration") + setTextAreaDisabled(isPartial) + setClineAsk("completion_result") + setEnableButtons(!isPartial) + setPrimaryButtonText("Create!") + setSecondaryButtonText(undefined) + break + case "resume_task": + setTextAreaDisabled(false) + setClineAsk("resume_task") + setEnableButtons(true) + setPrimaryButtonText("Resume Task") + setSecondaryButtonText("Terminate") + setDidClickCancel(false) // special case where we reset the cancel button state + break + case "resume_completed_task": + setTextAreaDisabled(false) + setClineAsk("resume_completed_task") + setEnableButtons(true) + setPrimaryButtonText("Create!") + setSecondaryButtonText(undefined) + setDidClickCancel(false) + break + } + break + case "say": + // don't want to reset since there could be a "say" after an "ask" while ask is waiting for response + switch (lastMessage.say) { + case "api_req_retry_delayed": + setTextAreaDisabled(true) + break + case "api_req_started": + if (secondLastMessage?.ask === "command_output") { + // if the last ask is a command_output, and we receive an api_req_started, then that means the command has finished and we don't need input from the user anymore (in every other case, the user has to interact with input field or buttons to continue, which does the following automatically) + setInputValue("") + setTextAreaDisabled(true) + setSelectedImages([]) + setClineAsk(undefined) + setEnableButtons(false) + } + break + case "api_req_finished": + case "task": + case "error": + case "text": + case "browser_action": + case "browser_action_result": + case "command_output": + case "mcp_server_request_started": + case "mcp_server_response": + case "completion_result": + case "tool": + break + } + break + } + } else { + // this would get called after sending the first message, so we have to watch messages.length instead + // No messages, so user has to submit a task + // setTextAreaDisabled(false) + // setClineAsk(undefined) + // setPrimaryButtonText(undefined) + // setSecondaryButtonText(undefined) + } + }, [lastMessage, secondLastMessage]) + + useEffect(() => { + if (messages.length === 0) { + setTextAreaDisabled(false) + setClineAsk(undefined) + setEnableButtons(false) + setPrimaryButtonText(undefined) + setSecondaryButtonText(undefined) + } + }, [messages.length]) + + useEffect(() => { + setExpandedRows({}) + }, [task?.ts]) + + const isStreaming = useMemo(() => { + const isLastAsk = !!modifiedMessages.at(-1)?.ask // checking clineAsk isn't enough since messages effect may be called again for a tool for example, set clineAsk to its value, and if the next message is not an ask then it doesn't reset. This is likely due to how much more often we're updating messages as compared to before, and should be resolved with optimizations as it's likely a rendering bug. but as a final guard for now, the cancel button will show if the last message is not an ask + const isToolCurrentlyAsking = + isLastAsk && clineAsk !== undefined && enableButtons && primaryButtonText !== undefined + if (isToolCurrentlyAsking) { + return false + } + + const isLastMessagePartial = modifiedMessages.at(-1)?.partial === true + if (isLastMessagePartial) { + return true + } else { + const lastApiReqStarted = findLast(modifiedMessages, (message) => message.say === "api_req_started") + if ( + lastApiReqStarted && + lastApiReqStarted.text !== null && + lastApiReqStarted.text !== undefined && + lastApiReqStarted.say === "api_req_started" + ) { + const cost = JSON.parse(lastApiReqStarted.text).cost + if (cost === undefined) { + // api request has not finished yet + return true + } + } + } + + return false + }, [modifiedMessages, clineAsk, enableButtons, primaryButtonText]) + + const handleSendMessage = useCallback( + (text: string, images: string[]) => { + // ALways set mode to creator in creator mode + if (window.isCreator) { + setMode("creator") + vscode.postMessage({ type: "mode", text: "creator" }) + } + + text = text.trim() + if (text || images.length > 0) { + if (messages.length === 0) { + if (includePlanningPhase) { + console.log("Starting new task with planning phase") + vscode.postMessage({ type: "newTask", text, images }) + } else { + console.log("Skipping planning phase, sending directly to agent") + vscode.postMessage({ + type: "invoke", + invoke: "executeCommand", + command: "roo-cline.createInAgent", + args: { + text, + mode: "code", + creatorMode: true, + }, + }) + } + } else if (clineAsk) { + switch (clineAsk) { + case "followup": + case "tool": + case "browser_action_launch": + case "command": // user can provide feedback to a tool or command use + case "command_output": // user can send input to command stdin + case "use_mcp_server": + case "completion_result": // if this happens then the user has feedback for the completion result + case "resume_task": + case "resume_completed_task": + case "mistake_limit_reached": + vscode.postMessage({ + type: "askResponse", + askResponse: "messageResponse", + text, + images, + }) + break + // there is no other case that a textfield should be enabled + } + } + // Only reset message-specific state, preserving mode + setInputValue("") + setTextAreaDisabled(true) + setSelectedImages([]) + setClineAsk(undefined) + setEnableButtons(false) + // Do not reset mode here as it should persist + // setPrimaryButtonText(undefined) + // setSecondaryButtonText(undefined) + disableAutoScrollRef.current = false + } + }, + [messages.length, clineAsk, setMode, includePlanningPhase], + ) + + const handleSetChatBoxMessage = useCallback( + (text: string, images: string[]) => { + // Avoid nested template literals by breaking down the logic + let newValue = text + if (inputValue !== "") { + newValue = inputValue + " " + text + } + + setInputValue(newValue) + setSelectedImages([...selectedImages, ...images]) + }, + [inputValue, selectedImages], + ) + + const startNewTask = useCallback(() => { + vscode.postMessage({ type: "clearTask" }) + }, []) + + /* + This logic depends on the useEffect[messages] above to set clineAsk, after which buttons are shown and we then send an askResponse to the extension. + */ + const handlePrimaryButtonClick = useCallback( + (text?: string, images?: string[]) => { + const trimmedInput = text?.trim() + switch (clineAsk) { + case "api_req_failed": + case "command": + case "command_output": + case "tool": + case "browser_action_launch": + case "use_mcp_server": + case "resume_task": + case "mistake_limit_reached": + // Only send text/images if they exist + if (trimmedInput || (images && images.length > 0)) { + vscode.postMessage({ + type: "askResponse", + askResponse: "yesButtonClicked", + text: trimmedInput, + images: images, + }) + } else { + vscode.postMessage({ + type: "askResponse", + askResponse: "yesButtonClicked", + }) + } + // Clear input state after sending + setInputValue("") + setSelectedImages([]) + break + case "completion_result": + case "resume_completed_task": + if (includePlanningPhase) { + vscode.postMessage({ + type: "invoke", + invoke: "executeCommand", + command: "roo-cline.executeCreatorPlan", + args: { + filePath: editingFilePath, + includePlanning: true, + }, + }) + } + break + } + setTextAreaDisabled(true) + setClineAsk(undefined) + setEnableButtons(false) + disableAutoScrollRef.current = false + }, + [clineAsk, editingFilePath, includePlanningPhase], + ) + + const handleSecondaryButtonClick = useCallback( + (text?: string, images?: string[]) => { + const trimmedInput = text?.trim() + if (isStreaming) { + vscode.postMessage({ type: "cancelTask" }) + setDidClickCancel(true) + return + } + + switch (clineAsk) { + case "api_req_failed": + case "mistake_limit_reached": + case "resume_task": + startNewTask() + break + case "command": + case "tool": + case "browser_action_launch": + case "use_mcp_server": + // Only send text/images if they exist + if (trimmedInput || (images && images.length > 0)) { + vscode.postMessage({ + type: "askResponse", + askResponse: "noButtonClicked", + text: trimmedInput, + images: images, + }) + } else { + // responds to the API with a "This operation failed" and lets it try again + vscode.postMessage({ + type: "askResponse", + askResponse: "noButtonClicked", + }) + } + // Clear input state after sending + setInputValue("") + setSelectedImages([]) + break + } + setTextAreaDisabled(true) + setClineAsk(undefined) + setEnableButtons(false) + disableAutoScrollRef.current = false + }, + [clineAsk, startNewTask, isStreaming], + ) + + const handleTaskCloseButtonClick = useCallback(() => { + startNewTask() + }, [startNewTask]) + + const pearAiModels = usePearAiModels(apiConfiguration) + + const { selectedModelInfo } = useMemo(() => { + return normalizeApiConfiguration(apiConfiguration, pearAiModels) + }, [apiConfiguration, pearAiModels]) + + const selectImages = useCallback(() => { + vscode.postMessage({ type: "selectImages" }) + }, []) + + const shouldDisableImages = + !selectedModelInfo.supportsImages || textAreaDisabled || selectedImages.length >= MAX_IMAGES_PER_MESSAGE + + const handleMessage = useCallback( + (e: MessageEvent) => { + const message: ExtensionMessage = e.data + switch (message.type) { + case "action": + switch (message.action!) { + case "didBecomeVisible": + if (!isHidden && !textAreaDisabled && !enableButtons) { + textAreaRef.current?.focus() + } + break + } + break + case "selectedImages": + const newImages = message.images ?? [] + if (newImages.length > 0) { + setSelectedImages((prevImages) => + [...prevImages, ...newImages].slice(0, MAX_IMAGES_PER_MESSAGE), + ) + } + break + case "invoke": + switch (message.invoke!) { + case "sendMessage": + handleSendMessage(message.text ?? "", message.images ?? []) + break + case "setChatBoxMessage": + handleSetChatBoxMessage(message.text ?? "", message.images ?? []) + break + case "primaryButtonClick": + handlePrimaryButtonClick(message.text ?? "", message.images ?? []) + break + case "secondaryButtonClick": + handleSecondaryButtonClick(message.text ?? "", message.images ?? []) + break + } + } + // textAreaRef.current is not explicitly required here since react gaurantees that ref will be stable across re-renders, and we're not using its value but its reference. + }, + [ + isHidden, + textAreaDisabled, + enableButtons, + handleSendMessage, + handleSetChatBoxMessage, + handlePrimaryButtonClick, + handleSecondaryButtonClick, + ], + ) + + useEvent("message", handleMessage) + + useMount(() => { + // NOTE: the vscode window needs to be focused for this to work + textAreaRef.current?.focus() + }) + + useEffect(() => { + const timer = setTimeout(() => { + if (!isHidden && !textAreaDisabled && !enableButtons) { + textAreaRef.current?.focus() + } + }, 50) + return () => { + clearTimeout(timer) + } + }, [isHidden, textAreaDisabled, enableButtons]) + + const visibleMessages = useMemo(() => { + return modifiedMessages.filter((message) => { + switch (message.ask) { + case "completion_result": + // don't show a chat row for a completion_result ask without text. This specific type of message only occurs if cline wants to execute a command as part of its completion result, in which case we interject the completion_result tool with the execute_command tool. + if (message.text === "") { + return false + } + break + case "api_req_failed": // this message is used to update the latest api_req_started that the request failed + case "resume_task": + case "resume_completed_task": + return false + } + switch (message.say) { + case "api_req_finished": // combineApiRequests removes this from modifiedMessages anyways + case "api_req_retried": // this message is used to update the latest api_req_started that the request was retried + case "api_req_deleted": // aggregated api_req metrics from deleted messages + return false + case "api_req_retry_delayed": + // Only show the retry message if it's the last message + return message === modifiedMessages.at(-1) + case "text": + // Sometimes cline returns an empty text message, we don't want to render these. (We also use a say text for user messages, so in case they just sent images we still render that) + if ((message.text ?? "") === "" && (message.images?.length ?? 0) === 0) { + return false + } + break + case "mcp_server_request_started": + return false + } + return true + }) + }, [modifiedMessages]) + + const isReadOnlyToolAction = useCallback((message: ClineMessage | undefined) => { + if (message?.type === "ask") { + if (!message.text) { + return true + } + const tool = JSON.parse(message.text) + return [ + "readFile", + "listFiles", + "listFilesTopLevel", + "listFilesRecursive", + "listCodeDefinitionNames", + "searchFiles", + ].includes(tool.tool) + } + return false + }, []) + + const isWriteToolAction = useCallback((message: ClineMessage | undefined) => { + if (message?.type === "ask") { + if (!message.text) { + return true + } + const tool = JSON.parse(message.text) + return ["editedExistingFile", "appliedDiff", "newFileCreated"].includes(tool.tool) + } + return false + }, []) + + const isMcpToolAlwaysAllowed = useCallback( + (message: ClineMessage | undefined) => { + if (message?.type === "ask" && message.ask === "use_mcp_server") { + if (!message.text) { + return true + } + const mcpServerUse = JSON.parse(message.text) as { type: string; serverName: string; toolName: string } + if (mcpServerUse.type === "use_mcp_tool") { + const server = mcpServers?.find((s: McpServer) => s.name === mcpServerUse.serverName) + const tool = server?.tools?.find((t: McpTool) => t.name === mcpServerUse.toolName) + return tool?.alwaysAllow || false + } + } + return false + }, + [mcpServers], + ) + + // Check if a command message is allowed + const isAllowedCommand = useCallback( + (message: ClineMessage | undefined): boolean => { + if (message?.type !== "ask") return false + return validateCommand(message.text || "", allowedCommands || []) + }, + [allowedCommands], + ) + + const isAutoApproved = useCallback( + (message: ClineMessage | undefined) => { + if (!autoApprovalEnabled || !message || message.type !== "ask") return false + + return ( + (alwaysAllowBrowser && message.ask === "browser_action_launch") || + (alwaysAllowReadOnly && message.ask === "tool" && isReadOnlyToolAction(message)) || + (alwaysAllowWrite && message.ask === "tool" && isWriteToolAction(message)) || + (alwaysAllowExecute && message.ask === "command" && isAllowedCommand(message)) || + (alwaysAllowMcp && message.ask === "use_mcp_server" && isMcpToolAlwaysAllowed(message)) || + (alwaysAllowModeSwitch && + message.ask === "tool" && + (JSON.parse(message.text || "{}")?.tool === "switchMode" || + JSON.parse(message.text || "{}")?.tool === "newTask")) + ) + }, + [ + autoApprovalEnabled, + alwaysAllowBrowser, + alwaysAllowReadOnly, + isReadOnlyToolAction, + alwaysAllowWrite, + isWriteToolAction, + alwaysAllowExecute, + isAllowedCommand, + alwaysAllowMcp, + isMcpToolAlwaysAllowed, + alwaysAllowModeSwitch, + ], + ) + + useEffect(() => { + // Only execute when isStreaming changes from true to false + if (wasStreaming && !isStreaming && lastMessage) { + // Play appropriate sound based on lastMessage content + if (lastMessage.type === "ask") { + // Don't play sounds for auto-approved actions + if (!isAutoApproved(lastMessage)) { + switch (lastMessage.ask) { + case "api_req_failed": + case "mistake_limit_reached": + playSound("progress_loop") + break + case "followup": + if (!lastMessage.partial) { + playSound("notification") + } + break + case "tool": + case "browser_action_launch": + case "resume_task": + case "use_mcp_server": + playSound("notification") + break + case "completion_result": + case "resume_completed_task": + playSound("celebration") + break + } + } + } + } + // Update previous value + setWasStreaming(isStreaming) + }, [isStreaming, lastMessage, wasStreaming, isAutoApproved]) + + const isBrowserSessionMessage = (message: ClineMessage): boolean => { + // which of visible messages are browser session messages, see above + if (message.type === "ask") { + return ["browser_action_launch"].includes(message.ask!) + } + if (message.type === "say") { + return ["api_req_started", "text", "browser_action", "browser_action_result"].includes(message.say!) + } + return false + } + + const groupedMessages = useMemo(() => { + const result: (ClineMessage | ClineMessage[])[] = [] + let currentGroup: ClineMessage[] = [] + let isInBrowserSession = false + + const endBrowserSession = () => { + if (currentGroup.length > 0) { + result.push([...currentGroup]) + currentGroup = [] + isInBrowserSession = false + } + } + + visibleMessages.forEach((message) => { + if (message.ask === "browser_action_launch") { + // complete existing browser session if any + endBrowserSession() + // start new + isInBrowserSession = true + currentGroup.push(message) + } else if (isInBrowserSession) { + // end session if api_req_started is cancelled + + if (message.say === "api_req_started") { + // get last api_req_started in currentGroup to check if it's cancelled. If it is then this api req is not part of the current browser session + const lastApiReqStarted = [...currentGroup].reverse().find((m) => m.say === "api_req_started") + if (lastApiReqStarted?.text !== null && lastApiReqStarted?.text !== undefined) { + const info = JSON.parse(lastApiReqStarted.text) + const isCancelled = info.cancelReason !== null && info.cancelReason !== undefined + if (isCancelled) { + endBrowserSession() + result.push(message) + return + } + } + } + + if (isBrowserSessionMessage(message)) { + currentGroup.push(message) + + // Check if this is a close action + if (message.say === "browser_action") { + const browserAction = JSON.parse(message.text || "{}") as ClineSayBrowserAction + if (browserAction.action === "close") { + endBrowserSession() + } + } + } else { + // complete existing browser session if any + endBrowserSession() + result.push(message) + } + } else { + result.push(message) + } + }) + + // Handle case where browser session is the last group + if (currentGroup.length > 0) { + result.push([...currentGroup]) + } + + return result + }, [visibleMessages]) + + // scrolling + + const scrollToBottomSmooth = useMemo( + () => + debounce( + () => { + virtuosoRef.current?.scrollTo({ + top: Number.MAX_SAFE_INTEGER, + behavior: "smooth", + }) + }, + 10, + { immediate: true }, + ), + [], + ) + + const scrollToBottomAuto = useCallback(() => { + virtuosoRef.current?.scrollTo({ + top: Number.MAX_SAFE_INTEGER, + behavior: "auto", // instant causes crash + }) + }, []) + + // scroll when user toggles certain rows + const toggleRowExpansion = useCallback( + (ts: number) => { + const isCollapsing = expandedRows[ts] ?? false + const lastGroup = groupedMessages.at(-1) + const isLast = Array.isArray(lastGroup) ? lastGroup[0].ts === ts : lastGroup?.ts === ts + const secondToLastGroup = groupedMessages.at(-2) + const isSecondToLast = Array.isArray(secondToLastGroup) + ? secondToLastGroup[0].ts === ts + : secondToLastGroup?.ts === ts + + const isLastCollapsedApiReq = + isLast && + !Array.isArray(lastGroup) && // Make sure it's not a browser session group + lastGroup?.say === "api_req_started" && + !expandedRows[lastGroup.ts] + + setExpandedRows((prev) => ({ + ...prev, + [ts]: !prev[ts], + })) + + // disable auto scroll when user expands row + if (!isCollapsing) { + disableAutoScrollRef.current = true + } + + if (isCollapsing && isAtBottom) { + const timer = setTimeout(() => { + scrollToBottomAuto() + }, 0) + return () => clearTimeout(timer) + } else if (isLast || isSecondToLast) { + if (isCollapsing) { + if (isSecondToLast && !isLastCollapsedApiReq) { + return + } + const timer = setTimeout(() => { + scrollToBottomAuto() + }, 0) + return () => clearTimeout(timer) + } else { + const timer = setTimeout(() => { + virtuosoRef.current?.scrollToIndex({ + index: groupedMessages.length - (isLast ? 1 : 2), + align: "start", + }) + }, 0) + return () => clearTimeout(timer) + } + } + }, + [groupedMessages, expandedRows, scrollToBottomAuto, isAtBottom], + ) + + const handleRowHeightChange = useCallback( + (isTaller: boolean) => { + if (!disableAutoScrollRef.current) { + if (isTaller) { + scrollToBottomSmooth() + } else { + setTimeout(() => { + scrollToBottomAuto() + }, 0) + } + } + }, + [scrollToBottomSmooth, scrollToBottomAuto], + ) + + useEffect(() => { + if (!disableAutoScrollRef.current) { + setTimeout(() => { + scrollToBottomSmooth() + }, 50) + // return () => clearTimeout(timer) // dont cleanup since if visibleMessages.length changes it cancels. + } + }, [groupedMessages.length, scrollToBottomSmooth]) + + const handleWheel = useCallback((event: Event) => { + const wheelEvent = event as WheelEvent + if (wheelEvent.deltaY && wheelEvent.deltaY < 0) { + if (scrollContainerRef.current?.contains(wheelEvent.target as Node)) { + // user scrolled up + disableAutoScrollRef.current = true + } + } + }, []) + useEvent("wheel", handleWheel, window, { passive: true }) // passive improves scrolling performance + + const placeholderText = useMemo(() => { + const baseText = task ? "Ask a follow up." : "What would you like do?" + const contextText = " Use @ to add context." + const imageText = shouldDisableImages ? "" : "\nhold shift to drag in images" + const helpText = imageText ? `\n${contextText}${imageText}` : `\n${contextText}` + return baseText + contextText + }, [task, shouldDisableImages]) + + const itemContent = useCallback( + (index: number, messageOrGroup: ClineMessage | ClineMessage[]) => { + // browser session group + if (Array.isArray(messageOrGroup)) { + return ( + expandedRows[messageTs] ?? false} + onToggleExpand={(messageTs: number) => { + setExpandedRows((prev) => ({ + ...prev, + [messageTs]: !prev[messageTs], + })) + }} + /> + ) + } + + // regular message + return ( + toggleRowExpansion(messageOrGroup.ts)} + lastModifiedMessage={modifiedMessages.at(-1)} + isLast={index === groupedMessages.length - 1} + onHeightChange={handleRowHeightChange} + isStreaming={isStreaming} + onEditPlan={handleEditPlan} + /> + ) + }, + [ + expandedRows, + modifiedMessages, + groupedMessages.length, + handleRowHeightChange, + isStreaming, + toggleRowExpansion, + handleEditPlan, + ], + ) + + useEffect(() => { + // Only proceed if we have an ask and buttons are enabled + if (!clineAsk || !enableButtons) return + + const autoApprove = async () => { + if (isAutoApproved(lastMessage)) { + // Add delay for write operations + if (lastMessage?.ask === "tool" && isWriteToolAction(lastMessage)) { + await new Promise((resolve) => setTimeout(resolve, writeDelayMs)) + } + handlePrimaryButtonClick() + } + } + autoApprove() + }, [ + clineAsk, + enableButtons, + handlePrimaryButtonClick, + alwaysAllowBrowser, + alwaysAllowReadOnly, + alwaysAllowWrite, + alwaysAllowExecute, + alwaysAllowMcp, + messages, + allowedCommands, + mcpServers, + isAutoApproved, + lastMessage, + writeDelayMs, + isWriteToolAction, + ]) + + return ( +
+
+ {!task && ( + <> +
+
+
+
+
+
+ + )} + {task && ( + + )} + + {/* */} + + {/* + // Flex layout explanation: + // 1. Content div above uses flex: "1 1 0" to: + // - Grow to fill available space (flex-grow: 1) + // - Shrink when AutoApproveMenu needs space (flex-shrink: 1) + // - Start from zero size (flex-basis: 0) to ensure proper distribution + // minHeight: 0 allows it to shrink below its content height + // + // 2. AutoApproveMenu uses flex: "0 1 auto" to: + // - Not grow beyond its content (flex-grow: 0) + // - Shrink when viewport is small (flex-shrink: 1) + // - Use its content size as basis (flex-basis: auto) + // This ensures it takes its natural height when there's space + // but becomes scrollable when the viewport is too small + */} + + {task && ( + <> +
+
, + }} + increaseViewportBy={{ top: 3_000, bottom: Number.MAX_SAFE_INTEGER }} + data={groupedMessages} + itemContent={(index, messageOrGroup) => { + if (Array.isArray(messageOrGroup)) { + return ( + expandedRows[messageTs] ?? false} + onToggleExpand={(messageTs: number) => { + setExpandedRows((prev) => ({ + ...prev, + [messageTs]: !prev[messageTs], + })) + }} + /> + ) + } + + return ( + toggleRowExpansion(messageOrGroup.ts)} + lastModifiedMessage={modifiedMessages.at(-1)} + isLast={index === groupedMessages.length - 1} + onHeightChange={handleRowHeightChange} + isStreaming={isStreaming} + onEditPlan={handleEditPlan} + /> + ) + }} + atBottomStateChange={(isAtBottom) => { + setIsAtBottom(isAtBottom) + if (isAtBottom) { + disableAutoScrollRef.current = false + } + setShowScrollToBottom(disableAutoScrollRef.current && !isAtBottom) + }} + atBottomThreshold={10} + initialTopMostItemIndex={groupedMessages.length - 1} + /> +
+ {showScrollToBottom ? ( +
+ { + scrollToBottomSmooth() + disableAutoScrollRef.current = false + }}> + + +
+ ) : ( +
+ {primaryButtonText && !isStreaming && ( + + )} + {(secondaryButtonText || isStreaming) && ( + + )} +
+ )} + + + )} + {/* */} + handleSendMessage(inputValue, selectedImages)} + onSelectImages={selectImages} + shouldDisableImages={shouldDisableImages} + onHeightChange={() => { + if (isAtBottom) { + scrollToBottomAuto() + } + }} + mode={mode} + setMode={setMode} + isNewTask={taskHistory.length === 0} + /> +
+
+ { + const newValue = !includePlanningPhase + setIncludePlanningPhase(newValue) + }}> + Include Planning Phase + +
+
+ {!task && ( + + )} +
+ {editingFilePath && {}} />} +
+ ) +} + +const ScrollToBottomButton = styled.div` + background-color: color-mix(in srgb, var(--vscode-toolbar-hoverBackground) 55%, transparent); + border-radius: 3px; + overflow: hidden; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + flex: 1; + height: 25px; + + &:hover { + background-color: color-mix(in srgb, var(--vscode-toolbar-hoverBackground) 90%, transparent); + } + + &:active { + background-color: color-mix(in srgb, var(--vscode-toolbar-hoverBackground) 70%, transparent); + } +` + +export default ChatView diff --git a/webview-ui/src/creator/SplitView.tsx b/webview-ui/src/creator/SplitView.tsx new file mode 100644 index 00000000000..e5c6de55bc5 --- /dev/null +++ b/webview-ui/src/creator/SplitView.tsx @@ -0,0 +1,248 @@ +import React, { useEffect, useState, useCallback } from "react" +import styled from "styled-components" +import { vscEditorBackground, vscButtonBackground, vscBackground } from "@/components/ui" +import { vscode } from "@/utils/vscode" +import CodeBlock from "./CodeBlock" +import { getLanguageFromPath, normalizePath } from "@/utils/getLanguageFromPath" +import { WebviewMessage } from "../../../src/shared/WebviewMessage" + +interface SplitViewProps { + filePath: string // This is workspace-relative path + onClose: () => void +} + +interface FileContentMessage { + type: "fileContent" | "error" + content?: string + error?: string +} + +const SplitViewContainer = styled.div` + padding: 12px 12px; + position: fixed; + top: 0; + right: 0; + bottom: 0; + width: 50%; + background-color: ${vscEditorBackground}; + overflow: hidden; + display: flex; + flex-direction: column; + z-index: 1000; + margin: 12px 12px; + // border: 2px solid red; + border-radius: 12px; +` + +const Header = styled.div` + display: flex; + align-items: center; + padding: 12px; + border-bottom: 1px solid var(--vscode-editorGroup-border); +` + +const Title = styled.div` + flex-grow: 1; + font-weight: bold; + margin-right: 12px; +` + +const Content = styled.div` + flex-grow: 1; + overflow: auto; + margin: 12px 0px; + border-radius: 12px; +` + +const StyledButton = styled.button` + background-color: ${vscButtonBackground}; + color: var(--vscode-button-foreground); + border: none; + padding: 6px 12px; + border-radius: 4px; + cursor: pointer; + margin-left: 8px; + + &:hover { + opacity: 0.9; + } +` + +const EmptyFileMessage = styled.div` + color: var(--vscode-descriptionForeground); + font-style: italic; + padding: 8px; + text-align: center; + border: 1px dashed var(--vscode-editorGroup-border); + border-radius: 4px; + margin: 8px 0; +` + +const SplitView: React.FC = ({ filePath, onClose }) => { + const [content, setContent] = useState("") + const [isEditing, setIsEditing] = useState(false) + const [editedContent, setEditedContent] = useState("") + const [error, setError] = useState(null) + + // Ensure the path has the correct directory structure for display + const normalizedPath = normalizePath(filePath) + + const handleMessage = useCallback((event: MessageEvent) => { + const message = event.data + console.log("SplitView received message:", message) + + if (message.type === "fileContent") { + if (message.content !== undefined) { + console.log("Setting content:", message.content) + // Use functional updates to access the current state + setIsEditing((currentIsEditing) => { + if (currentIsEditing) { + // This is a save confirmation + setContent(message.content) + setEditedContent(message.content) + console.log("Save operation completed successfully") + return false // Exit edit mode + } else { + // Initial file load + setContent(message.content) + setEditedContent(message.content) + return currentIsEditing // Keep current edit state + } + }) + setError(null) + } + } else if (message.type === "error") { + console.log("Received error:", message.error) + setIsEditing((currentIsEditing) => { + if (!currentIsEditing) { + // Only clear content if this was a read operation + console.log("Read operation failed, clearing content") + setContent("") + setEditedContent("") + } else { + console.log("Save operation failed") + } + return currentIsEditing // Keep current edit state + }) + setError(message.error || "Operation failed") + } + }, []) // Remove isEditing from dependencies + + // Log when the component mounts and unmounts + useEffect(() => { + console.log("SplitView mounted with filepath:", filePath) + return () => { + console.log("SplitView unmounted") + } + }, [filePath]) + + useEffect(() => { + console.log("Setting up message listener and initiating file read") + window.addEventListener("message", handleMessage) + + // Read the file + console.log("Sending readWorkspaceFile message for path:", filePath) + try { + vscode.postMessage({ + type: "readWorkspaceFile", + values: { + relativePath: filePath, + create: true, + ensureDirectory: true, + content: "", + }, + }) + console.log("Successfully sent readWorkspaceFile message") + } catch (error) { + console.error("Error sending readWorkspaceFile message:", error) + setError("Failed to send file read request") + } + + // Cleanup + return () => { + console.log("Cleaning up message listener") + window.removeEventListener("message", handleMessage) + } + }, [filePath, handleMessage]) + + const handleSave = useCallback(() => { + console.log("Initiating save for file:", filePath) + console.log("Content length:", editedContent.length) + + try { + // Don't exit edit mode until we get confirmation + const message: WebviewMessage = { + type: "writeWorkspaceFile", + values: { + relativePath: filePath, + create: true, + ensureDirectory: true, + content: editedContent, + }, + } + vscode.postMessage(message) + console.log("Successfully sent writeWorkspaceFile message") + } catch (error) { + console.error("Error sending writeWorkspaceFile message:", error) + setError("Failed to send file save request") + } + }, [filePath, editedContent]) + + const language = getLanguageFromPath(normalizedPath) + + return ( + +
+ {normalizedPath} + {isEditing ? ( + <> + Save + setIsEditing(false)}>Cancel + + ) : ( + setIsEditing(true)}>Edit + )} + Close +
+ + {error && !isEditing && ( +
{error}
+ )} + {isEditing ? ( + <> + {!editedContent && ( + + File is empty. Start typing to add content to {normalizedPath} + + )} +