diff --git a/package-lock.json b/package-lock.json index 3f57a08b3..a62134fb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1138,7 +1138,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -3115,7 +3114,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz", "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", @@ -3164,7 +3162,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.3.1.tgz", "integrity": "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", @@ -3191,7 +3188,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.4.11.tgz", "integrity": "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-css": "^6.0.0", @@ -3219,7 +3215,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz", "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.6.0", @@ -3420,7 +3415,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.1.tgz", "integrity": "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", @@ -3497,7 +3491,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.4.tgz", "integrity": "sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw==", "license": "MIT", - "peer": true, "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } @@ -3519,7 +3512,6 @@ "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.12.tgz", "integrity": "sha512-f+/VsHVn/kOA9lltk/GFzuYwVVAKmOnNjxbrhkk3tPHntFqjWeI2TbIXx006YkBkqC10wZ4NsnWXCQiFPeAISQ==", "license": "MIT", - "peer": true, "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", @@ -3575,7 +3567,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4359,7 +4350,6 @@ "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", @@ -4812,6 +4802,7 @@ "os": [ "aix" ], + "peer": true, "engines": { "node": ">=18" } @@ -4829,6 +4820,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -4846,6 +4838,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -4863,6 +4856,7 @@ "os": [ "android" ], + "peer": true, "engines": { "node": ">=18" } @@ -4880,6 +4874,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -4897,6 +4892,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=18" } @@ -4914,6 +4910,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -4931,6 +4928,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -4948,6 +4946,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -4965,6 +4964,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -4982,6 +4982,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -4999,6 +5000,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5016,6 +5018,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5033,6 +5036,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5050,6 +5054,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5067,6 +5072,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5084,6 +5090,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=18" } @@ -5101,6 +5108,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -5118,6 +5126,7 @@ "os": [ "netbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -5135,6 +5144,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -5152,6 +5162,7 @@ "os": [ "openbsd" ], + "peer": true, "engines": { "node": ">=18" } @@ -5169,6 +5180,7 @@ "os": [ "openharmony" ], + "peer": true, "engines": { "node": ">=18" } @@ -5186,6 +5198,7 @@ "os": [ "sunos" ], + "peer": true, "engines": { "node": ">=18" } @@ -5203,6 +5216,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -5220,6 +5234,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -5237,6 +5252,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=18" } @@ -5725,7 +5741,6 @@ "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.14.3.tgz", "integrity": "sha512-Iq8QQQ/7X3Sac15oB6p0FmUg/klxQvXLeileoqrTRGJYLV+/9tubbr9ipz0GKHjmXVsgFPo/+W+2cA8eNcR+XA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" @@ -6465,7 +6480,6 @@ "integrity": "sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^3.0.1", "@inquirer/confirm": "^4.0.1", @@ -7977,8 +7991,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.5.0.tgz", "integrity": "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@lezer/cpp": { "version": "1.1.5", @@ -8018,7 +8031,6 @@ "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.3.tgz", "integrity": "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==", "license": "MIT", - "peer": true, "dependencies": { "@lezer/common": "^1.3.0" } @@ -8050,7 +8062,6 @@ "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.5.4.tgz", "integrity": "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==", "license": "MIT", - "peer": true, "dependencies": { "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.1.3", @@ -8073,7 +8084,6 @@ "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.8.tgz", "integrity": "sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==", "license": "MIT", - "peer": true, "dependencies": { "@lezer/common": "^1.0.0" } @@ -8363,7 +8373,6 @@ "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", "license": "MIT", - "peer": true, "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", @@ -9273,7 +9282,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -9307,7 +9315,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.5.0.tgz", "integrity": "sha512-ka4H8OM6+DlUhSAZpONu0cPBtPPTQKxbxVzC4CzVx5+K4JnroJVBtDzLAMx4/3CDTJXRvVFhpFjtl4SaiTNoyQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -10272,7 +10279,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.5.0.tgz", "integrity": "sha512-F8W52ApePshpoSrfsSk1H2yJn9aKjCrbpQF1M9Qii0GHzbfVeFUB+rc3X4aggyZD8x9Gu3Slua+s6krmq6Dt8g==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@opentelemetry/core": "2.5.0", "@opentelemetry/semantic-conventions": "^1.29.0" @@ -10892,7 +10898,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-android-arm64": { "version": "4.57.1", @@ -10906,7 +10913,8 @@ "optional": true, "os": [ "android" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.57.1", @@ -10920,7 +10928,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-darwin-x64": { "version": "4.57.1", @@ -10934,7 +10943,8 @@ "optional": true, "os": [ "darwin" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-arm64": { "version": "4.57.1", @@ -10948,7 +10958,8 @@ "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-freebsd-x64": { "version": "4.57.1", @@ -10962,7 +10973,8 @@ "optional": true, "os": [ "freebsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { "version": "4.57.1", @@ -10976,7 +10988,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { "version": "4.57.1", @@ -10990,7 +11003,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-gnu": { "version": "4.57.1", @@ -11004,7 +11018,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-arm64-musl": { "version": "4.57.1", @@ -11018,7 +11033,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-gnu": { "version": "4.57.1", @@ -11032,7 +11048,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-loong64-musl": { "version": "4.57.1", @@ -11046,7 +11063,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { "version": "4.57.1", @@ -11060,7 +11078,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-ppc64-musl": { "version": "4.57.1", @@ -11074,7 +11093,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { "version": "4.57.1", @@ -11088,7 +11108,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-riscv64-musl": { "version": "4.57.1", @@ -11102,7 +11123,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-s390x-gnu": { "version": "4.57.1", @@ -11116,7 +11138,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.57.1", @@ -11130,7 +11153,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-linux-x64-musl": { "version": "4.57.1", @@ -11144,7 +11168,8 @@ "optional": true, "os": [ "linux" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openbsd-x64": { "version": "4.57.1", @@ -11158,7 +11183,8 @@ "optional": true, "os": [ "openbsd" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.57.1", @@ -11172,7 +11198,8 @@ "optional": true, "os": [ "openharmony" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-arm64-msvc": { "version": "4.57.1", @@ -11186,7 +11213,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-ia32-msvc": { "version": "4.57.1", @@ -11200,7 +11228,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-gnu": { "version": "4.57.1", @@ -11214,7 +11243,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.57.1", @@ -11228,7 +11258,8 @@ "optional": true, "os": [ "win32" - ] + ], + "peer": true }, "node_modules/@rtsao/scc": { "version": "1.1.0", @@ -12194,7 +12225,6 @@ "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.21.3", "@svgr/babel-preset": "8.1.0", @@ -12795,7 +12825,6 @@ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -12833,7 +12862,6 @@ "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -13054,7 +13082,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.10.tgz", "integrity": "sha512-+0/4J266CBGPUq/ELg7QUHhN25WYjE0wYTPSQJn1xeu8DOlIOPxXxrNGiLmfAWl7HMMgWFWXpt9IDjMWrF5Iow==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -13116,7 +13143,6 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.10.tgz", "integrity": "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw==", "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -13405,7 +13431,6 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -14142,7 +14167,6 @@ "integrity": "sha512-5/pJyG4GBd1Uyrx1GGhpcgmLDXWqy+B4fbDvaC/rZRbaZduwcPF/kdMmgoLK06WKh48Hd34nQXASd7rrDDEw/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.5", "@unocss/config": "66.6.0", @@ -14735,7 +14759,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -14829,7 +14852,6 @@ "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", @@ -16129,7 +16151,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -16626,7 +16647,6 @@ "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.0.3.tgz", "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@chevrotain/cst-dts-gen": "11.0.3", "@chevrotain/gast": "11.0.3", @@ -17657,7 +17677,6 @@ "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10" } @@ -18067,7 +18086,6 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -18606,7 +18624,6 @@ "integrity": "sha512-uOOBA3f+kW3o4KpSoMQ6SNpdXU7WtxlJRb9vCZgOvqhTz4b3GjcoWKstdisizNZLsylhTMv8TLHFPFW0Uxsj/g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "app-builder-lib": "26.7.0", "builder-util": "26.4.1", @@ -19911,6 +19928,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -19981,7 +19999,6 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -20038,7 +20055,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -20499,7 +20515,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -21254,7 +21269,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -22452,7 +22466,6 @@ "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.39.3.tgz", "integrity": "sha512-7arRRoOtOh9UwMwANZ475kJrWV6P3/EGNooeHlY0/SwZv4t3ZZ3Uiz9cAXK8Zg9xSdgmm8T21kx6n7SZaWvOcw==", "license": "MIT", - "peer": true, "dependencies": { "@grammyjs/types": "3.23.0", "abort-controller": "^3.0.0", @@ -23024,7 +23037,6 @@ "resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz", "integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==", "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } @@ -23472,7 +23484,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.23.2" } @@ -24588,7 +24599,6 @@ "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "30.2.0", "@jest/types": "30.2.0", @@ -27476,7 +27486,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@types/debug": "^4.0.0", "debug": "^4.0.0", @@ -28113,8 +28122,7 @@ "url": "https://opencollective.com/unified" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", @@ -28426,6 +28434,7 @@ "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", "license": "MIT", + "peer": true, "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" @@ -28436,6 +28445,7 @@ "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", "license": "MIT", + "peer": true, "bin": { "marked": "bin/marked.js" }, @@ -30369,7 +30379,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -30619,7 +30628,6 @@ "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -31130,7 +31138,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -31152,7 +31159,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -32375,6 +32381,7 @@ "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -35024,7 +35031,6 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -35103,8 +35109,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsyringe": { "version": "4.10.0", @@ -35293,7 +35298,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -35454,7 +35458,6 @@ "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", "license": "MIT", - "peer": true, "dependencies": { "@types/unist": "^3.0.0", "bail": "^2.0.0", @@ -35606,7 +35609,6 @@ "integrity": "sha512-B5QsMJzFKeTHPzF5Ehr8tSMuhxzbCR9n+XP0GyhK9/2jTcBdI0/T+rCDDr9m6vUz+lku/coCVz7VAQ2BRAbZJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@unocss/astro": "66.6.0", "@unocss/cli": "66.6.0", @@ -36371,7 +36373,6 @@ "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -36421,7 +36422,6 @@ "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", @@ -37374,8 +37374,7 @@ "integrity": "sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==", "deprecated": "This package is now deprecated. Move to @xterm/xterm instead.", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/xterm-addon-fit": { "version": "0.5.0", @@ -37521,7 +37520,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/src/agent/acp/AcpConnection.ts b/src/agent/acp/AcpConnection.ts index bc9780214..5a7b517f4 100644 --- a/src/agent/acp/AcpConnection.ts +++ b/src/agent/acp/AcpConnection.ts @@ -410,7 +410,8 @@ export class AcpConnection { return new Promise((resolve, reject) => { // Use longer timeout for session/prompt requests as they involve LLM processing // Complex tasks like document processing may need significantly more time - const timeoutDuration = method === 'session/prompt' ? 300000 : 60000; // 5 minutes for prompts, 1 minute for others + // 优化超时配置:LLM 请求 2 分钟,其他请求 30 秒,加快错误恢复 + const timeoutDuration = method === 'session/prompt' ? 120000 : 30000; // 2 minutes for prompts, 30 seconds for others const startTime = Date.now(); const createTimeoutHandler = () => { diff --git a/src/agent/acp/index.ts b/src/agent/acp/index.ts index 5d15d3e3a..863ef9948 100644 --- a/src/agent/acp/index.ts +++ b/src/agent/acp/index.ts @@ -187,7 +187,7 @@ export class AcpAgent { let connectTimeoutId: NodeJS.Timeout | null = null; const connectTimeoutPromise = new Promise((_, reject) => { - connectTimeoutId = setTimeout(() => reject(new Error('Connection timeout after 70 seconds')), 70000); + connectTimeoutId = setTimeout(() => reject(new Error('Connection timeout after 30 seconds')), 30000); }); try { @@ -217,7 +217,7 @@ export class AcpAgent { await this.connection.setSessionMode(sessionMode); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); - throw new Error(`[ACP] Failed to enable ${this.extra.backend} YOLO mode (${sessionMode}): ${errorMessage}`); + throw new Error(`[ACP] Failed to enable ${this.extra.backend.charAt(0).toUpperCase() + this.extra.backend.slice(1)} YOLO mode (${sessionMode}): ${errorMessage}`); } } } @@ -677,7 +677,7 @@ export class AcpAgent { this.pendingPermissions.delete(requestId); reject(new Error('Permission request timed out')); } - }, 70000); + }, 30000); }); } @@ -994,7 +994,7 @@ export class AcpAgent { const loginProcess = spawn(command, args, { stdio: 'pipe', // 避免干扰用户界面 - timeout: 70000, + timeout: 30000, }); await new Promise((resolve, reject) => { diff --git a/src/agent/gemini/cli/streamResilience.ts b/src/agent/gemini/cli/streamResilience.ts index fe03912ba..216342e1b 100644 --- a/src/agent/gemini/cli/streamResilience.ts +++ b/src/agent/gemini/cli/streamResilience.ts @@ -60,7 +60,7 @@ export const DEFAULT_STREAM_RESILIENCE_CONFIG: StreamResilienceConfig = { maxRetries: 3, initialRetryDelayMs: 1000, maxRetryDelayMs: 10000, - heartbeatTimeoutMs: 90000, // 90 seconds without data considered disconnected / 90秒无数据则认为断开 + heartbeatTimeoutMs: 30000, // 30 seconds without data considered disconnected / 30秒无数据则认为断开(优化:加快错误恢复) requestTimeoutMs: 120000, // 2 minutes request timeout / 2分钟请求超时 enableAutoReconnect: true, }; diff --git a/src/process/WorkerManage.ts b/src/process/WorkerManage.ts index 4c755529a..4666107b8 100644 --- a/src/process/WorkerManage.ts +++ b/src/process/WorkerManage.ts @@ -153,6 +153,36 @@ const kill = (id: string) => { taskList.splice(index, 1); }; +/** + * 清理对话相关的所有资源 + * 在对话关闭或删除时调用,防止内存泄漏 + * + * @param conversationId - 对话 ID + */ +const cleanupConversation = (conversationId: string) => { + console.log(`[WorkerManage] Cleaning up resources for conversation: ${conversationId}`); + + // 1. 清理 Worker 任务 + kill(conversationId); + + // 2. 清理消息管理缓存(如果存在) + // 通过访问 message.ts 的 Cache 来清理 + try { + // 动态导入以避免循环依赖 + // eslint-disable-next-line @typescript-eslint/no-var-requires + const { ConversationManageWithDB } = require('./message'); + const cache = (ConversationManageWithDB as any).Cache; + if (cache && cache.has(conversationId)) { + cache.delete(conversationId); + console.log(`[WorkerManage] Cleaned up message cache for conversation: ${conversationId}`); + } + } catch (error) { + console.warn(`[WorkerManage] Failed to cleanup message cache:`, error); + } + + console.log(`[WorkerManage] Cleanup completed for conversation: ${conversationId}`); +}; + const clear = () => { taskList.forEach((item) => { item.task.kill(); @@ -181,6 +211,7 @@ const WorkerManage = { listTasks, kill, clear, + cleanupConversation, }; export default WorkerManage; diff --git a/src/process/bridge/conversationBridge.ts b/src/process/bridge/conversationBridge.ts index 52f39a0c0..aef6c3ebb 100644 --- a/src/process/bridge/conversationBridge.ts +++ b/src/process/bridge/conversationBridge.ts @@ -218,6 +218,9 @@ export function initConversationBridge(): void { return false; } + // 清理对话相关的 Worker 任务和缓存,防止内存泄漏 + WorkerManage.cleanupConversation(id); + return true; } catch (error) { console.error('[conversationBridge] Failed to remove conversation:', error); diff --git a/src/process/bridge/databaseBridge.ts b/src/process/bridge/databaseBridge.ts index a1771485e..a3e2e23e1 100644 --- a/src/process/bridge/databaseBridge.ts +++ b/src/process/bridge/databaseBridge.ts @@ -12,7 +12,7 @@ import { migrateConversationToDatabase } from './migrationUtils'; export function initDatabaseBridge(): void { // Get conversation messages from database - ipcBridge.database.getConversationMessages.provider(({ conversation_id, page = 0, pageSize = 10000 }) => { + ipcBridge.database.getConversationMessages.provider(({ conversation_id, page = 0, pageSize = 50 }) => { try { const db = getDatabase(); const result = db.getConversationMessages(conversation_id, page, pageSize); @@ -24,7 +24,7 @@ export function initDatabaseBridge(): void { }); // Get user conversations from database with lazy migration from file storage - ipcBridge.database.getUserConversations.provider(async ({ page = 0, pageSize = 10000 }) => { + ipcBridge.database.getUserConversations.provider(async ({ page = 0, pageSize = 50 }) => { try { const db = getDatabase(); const result = db.getUserConversations(undefined, page, pageSize); diff --git a/src/process/bridge/fsBridge.ts b/src/process/bridge/fsBridge.ts index 60133ae06..d7e2b9d9b 100644 --- a/src/process/bridge/fsBridge.ts +++ b/src/process/bridge/fsBridge.ts @@ -443,48 +443,67 @@ export function initFsBridge(): void { // 确保工作空间目录存在 / Ensure workspace directory exists await fs.mkdir(workspace, { recursive: true }); - for (const filePath of filePaths) { - try { - let targetPath: string; + // 批量并发处理文件复制,提升性能 + const CONCURRENCY = 5; // 并发数,避免同时打开过多文件句柄 + const chunks: (typeof filePaths)[] = []; + for (let i = 0; i < filePaths.length; i += CONCURRENCY) { + chunks.push(filePaths.slice(i, i + CONCURRENCY)); + } - if (sourceRoot) { - // Preserve directory structure / 保留目录结构 - const relativePath = path.relative(sourceRoot, filePath); - targetPath = path.join(workspace, relativePath); + for (const chunk of chunks) { + const chunkPromises = chunk.map(async (filePath) => { + try { + let targetPath: string; + + if (sourceRoot) { + // Preserve directory structure / 保留目录结构 + const relativePath = path.relative(sourceRoot, filePath); + targetPath = path.join(workspace, relativePath); + + // Ensure parent directory exists / 确保父目录存在 + await fs.mkdir(path.dirname(targetPath), { recursive: true }); + } else { + // Flatten to root (legacy behavior) / 扁平化到根目录(旧行为) + const fileName = path.basename(filePath); + targetPath = path.join(workspace, fileName); + } - // Ensure parent directory exists / 确保父目录存在 - await fs.mkdir(path.dirname(targetPath), { recursive: true }); - } else { - // Flatten to root (legacy behavior) / 扁平化到根目录(旧行为) - const fileName = path.basename(filePath); - targetPath = path.join(workspace, fileName); - } + // 检查目标文件是否已存在 + const exists = await fs + .access(targetPath) + .then(() => true) + .catch(() => false); + + let finalTargetPath = targetPath; + if (exists) { + // 如果文件已存在,添加时间戳后缀 / Append timestamp when target file already exists + const timestamp = Date.now(); + const ext = path.extname(targetPath); + const name = path.basename(targetPath, ext); + // Construct new path in the same directory / 在同一目录下构建新路径 + const dir = path.dirname(targetPath); + const newFileName = `${name}${AIONUI_TIMESTAMP_SEPARATOR}${timestamp}${ext}`; + finalTargetPath = path.join(dir, newFileName); + } - // 检查目标文件是否已存在 - const exists = await fs - .access(targetPath) - .then(() => true) - .catch(() => false); - - let finalTargetPath = targetPath; - if (exists) { - // 如果文件已存在,添加时间戳后缀 / Append timestamp when target file already exists - const timestamp = Date.now(); - const ext = path.extname(targetPath); - const name = path.basename(targetPath, ext); - // Construct new path in the same directory / 在同一目录下构建新路径 - const dir = path.dirname(targetPath); - const newFileName = `${name}${AIONUI_TIMESTAMP_SEPARATOR}${timestamp}${ext}`; - finalTargetPath = path.join(dir, newFileName); + await fs.copyFile(filePath, finalTargetPath); + return { success: true, path: finalTargetPath }; + } catch (error) { + // 记录失败的文件路径与错误信息,前端可以用来提示用户 / Record failed file info so UI can warn user + const message = error instanceof Error ? error.message : String(error); + return { success: false, path: filePath, error: message }; } + }); + + const results = await Promise.all(chunkPromises); - await fs.copyFile(filePath, finalTargetPath); - copiedFiles.push(finalTargetPath); - } catch (error) { - // 记录失败的文件路径与错误信息,前端可以用来提示用户 / Record failed file info so UI can warn user - const message = error instanceof Error ? error.message : String(error); - console.error(`Failed to copy file ${filePath}:`, message); - failedFiles.push({ path: filePath, error: message }); + // 处理结果 + for (const result of results) { + if (result.success) { + copiedFiles.push(result.path); + } else { + failedFiles.push({ path: result.path, error: result.error || 'Unknown error' }); + } } } diff --git a/src/process/message.ts b/src/process/message.ts index ede82b48b..02750ccbc 100644 --- a/src/process/message.ts +++ b/src/process/message.ts @@ -9,6 +9,7 @@ import { composeMessage } from '@/common/chatLib'; import type { AcpBackend } from '@/types/acpTypes'; import { getDatabase } from './database/export'; import { ProcessChat } from './initStorage'; +import { streamingBuffer } from './database/StreamingMessageBuffer'; const Cache = new Map(); @@ -30,15 +31,25 @@ class ConversationManageWithDB { return manage; } sync(type: 'insert' | 'accumulate', message: TMessage) { - this.stack.push([type, message]); - clearTimeout(this.timer); - if (type === 'insert') { - this.save2DataBase(); + // 对于 accumulate 类型,直接使用 StreamingMessageBuffer 进行批量更新 + // 这可以显著减少数据库 I/O 操作(从每个 chunk 一次查询减少到每 300ms 或 20 个 chunk 一次) + if (type === 'accumulate') { + const msgId = message.msg_id || message.id; + // 只处理包含 content.content 属性的消息类型 + let content = ''; + if (message.type === 'text' || message.type === 'tips') { + content = message.content.content || ''; + } + streamingBuffer.append(message.id, msgId, this.conversation_id, content, 'accumulate'); + // 仍然保存到 stack,以便在需要时处理其他逻辑 + this.stack.push([type, message]); return; } - this.timer = setTimeout(() => { - this.save2DataBase(); - }, 2000); + + // 对于 insert 类型,使用原有的批量处理机制 + this.stack.push([type, message]); + clearTimeout(this.timer); + this.save2DataBase(); } private save2DataBase() { @@ -46,7 +57,7 @@ class ConversationManageWithDB { .then(() => { const stack = this.stack.slice(); this.stack = []; - const messages = this.db.getConversationMessages(this.conversation_id, 0, 50, 'DESC'); // + const messages = this.db.getConversationMessages(this.conversation_id, 0, 50, 'DESC'); let messageList = messages.data.reverse(); let updateMessage = stack.shift(); while (updateMessage) { @@ -54,6 +65,7 @@ class ConversationManageWithDB { this.db.insertMessage(updateMessage[1]); messageList.push(updateMessage[1]); } else { + // accumulate 类型已经由 StreamingMessageBuffer 处理,这里只处理需要 compose 的情况 messageList = composeMessage(updateMessage[1], messageList, (type, message) => { if (type === 'insert') this.db.insertMessage(message); if (type === 'update') { diff --git a/src/process/utils.ts b/src/process/utils.ts index 8e51ddc0a..9b954285b 100644 --- a/src/process/utils.ts +++ b/src/process/utils.ts @@ -96,21 +96,32 @@ export const generateHashWithFullName = (fullName: string): string => { }; // 递归读取目录内容,返回树状结构 + export async function readDirectoryRecursive( dirPath: string, + options?: { root?: string; + abortController?: AbortController; + fileService?: { shouldIgnoreFile(path: string): boolean }; + maxDepth?: number; + + concurrency?: number; // 并发控制参数 + search?: { text: string; + onProcess?(result: { file: number; dir: number; match?: IDirOrFile }): void; + process?: { file: number; dir: number }; }; } ): Promise { - const { root = dirPath, maxDepth = 1, fileService, search, abortController } = options || {}; + const { root = dirPath, maxDepth = 1, fileService, search, abortController, concurrency = 10 } = options || {}; + const { text: searchText, onProcess: onSearchProcess = () => {}, process = { file: 0, dir: 1 } } = search || {}; const matchSearch = searchText ? (fullPath: string) => fullPath.includes(searchText) : (_: string) => false; @@ -120,79 +131,139 @@ export async function readDirectoryRecursive( }; const stats = await fs.stat(dirPath); + if (!stats.isDirectory()) { return null; } + const result: IDirOrFile = { name: path.basename(dirPath), + fullPath: dirPath, + relativePath: path.relative(root, dirPath), + isDir: true, + isFile: false, + children: [], }; + let searchResult = matchSearch(result.name); + onSearchProcess({ ...process, + match: searchResult ? result : undefined, }); + if (maxDepth === 0 || searchResult) return result; + checkStatus(); + const items = await fs.readdir(dirPath); + checkStatus(); - for (const item of items) { - checkStatus(); - if (item === 'node_modules') continue; + // 过滤掉需要忽略的项 + + const filteredItems = items.filter((item) => { + if (item === 'node_modules') return false; + const itemPath = path.join(dirPath, item); - if (fileService && fileService.shouldIgnoreFile(itemPath)) continue; - - const itemStats = await fs.stat(itemPath); - if (itemStats.isDirectory()) { - process.dir += 1; - const child = await readDirectoryRecursive(itemPath, { - ...options, - maxDepth: searchText ? maxDepth : maxDepth - 1, - root, - search: { - ...search, - process, - onProcess(searchResult) { - if (searchResult.match) { - if (!result.children.find((v) => v.fullPath === searchResult.match.fullPath)) { - result.children.push(searchResult.match); + + if (fileService && fileService.shouldIgnoreFile(itemPath)) return false; + + return true; + }); + + // 批量并发处理文件和目录 + + const chunks: (typeof filteredItems)[] = []; + + for (let i = 0; i < filteredItems.length; i += concurrency) { + chunks.push(filteredItems.slice(i, i + concurrency)); + } + + for (const chunk of chunks) { + checkStatus(); + + // 并发处理一批文件/目录 + + const chunkPromises = chunk.map(async (item) => { + checkStatus(); + + const itemPath = path.join(dirPath, item); + + const itemStats = await fs.stat(itemPath); + + if (itemStats.isDirectory()) { + process.dir += 1; + + const child = await readDirectoryRecursive(itemPath, { + ...options, + + maxDepth: searchText ? maxDepth : maxDepth - 1, + + root, + + concurrency, + + search: { + ...search, + + process, + + onProcess(searchResult) { + if (searchResult.match) { + if (!result.children.find((v) => v.fullPath === searchResult.match.fullPath)) { + result.children.push(searchResult.match); + } + + onSearchProcess({ ...process, match: result }); } - onSearchProcess({ ...process, match: result }); - } + }, }, - }, - }); - if (child && !searchText) { - result.children.push(child); - } - } else { - const children = { - name: item, - relativePath: path.relative(root, itemPath), - fullPath: itemPath, - isDir: false, - isFile: true, - }; - if (!searchText) { - result.children.push(children); - continue; + }); + + return child; + } else { + const children = { + name: item, + + relativePath: path.relative(root, itemPath), + + fullPath: itemPath, + + isDir: false, + + isFile: true, + }; + + if (searchText) { + searchResult = matchSearch(children.name); + } + + return children; } - searchResult = matchSearch(children.name); - if (searchResult) { - result.children.push(children); + }); + + const results = await Promise.all(chunkPromises); + + // 处理结果 + + for (const itemResult of results) { + if (!itemResult) continue; + + if (itemResult.isDir && !searchText) { + result.children.push(itemResult); + } else if (!itemResult.isDir && !searchText) { + result.children.push(itemResult); } - process.file += 1; - onSearchProcess({ - ...process, - match: searchResult ? result : undefined, - }); } } + result.children.sort((a, b) => { if (a.isDir && !b.isDir) return -1; if (!a.isDir && b.isDir) return 1;