mirror of
https://github.com/cline/cline.git
synced 2026-09-19 02:05:44 +08:00
fix: stabilize subagent command UX and suppress nested command rows
This commit is contained in:
Generated
+78
-43
@@ -3128,7 +3128,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"
|
||||
@@ -4031,7 +4030,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",
|
||||
@@ -4107,7 +4105,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"
|
||||
}
|
||||
@@ -5798,7 +5795,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.57.1",
|
||||
@@ -5811,7 +5809,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.57.1",
|
||||
@@ -5824,7 +5823,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.57.1",
|
||||
@@ -5837,7 +5837,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.57.1",
|
||||
@@ -5850,7 +5851,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.57.1",
|
||||
@@ -5863,7 +5865,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.57.1",
|
||||
@@ -5876,7 +5879,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.57.1",
|
||||
@@ -5889,7 +5893,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.57.1",
|
||||
@@ -5902,7 +5907,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.57.1",
|
||||
@@ -5915,7 +5921,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.57.1",
|
||||
@@ -5928,7 +5935,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.57.1",
|
||||
@@ -5941,7 +5949,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.57.1",
|
||||
@@ -5954,7 +5963,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.57.1",
|
||||
@@ -5967,7 +5977,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.57.1",
|
||||
@@ -5980,7 +5991,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.57.1",
|
||||
@@ -5993,7 +6005,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.57.1",
|
||||
@@ -6006,7 +6019,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.57.1",
|
||||
@@ -6019,7 +6033,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.57.1",
|
||||
@@ -6032,7 +6047,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.57.1",
|
||||
@@ -6045,7 +6061,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.57.1",
|
||||
@@ -6058,7 +6075,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.57.1",
|
||||
@@ -6071,7 +6089,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.57.1",
|
||||
@@ -6084,7 +6103,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.57.1",
|
||||
@@ -6097,7 +6117,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.57.1",
|
||||
@@ -6110,7 +6131,8 @@
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@sap-ai-sdk/ai-api": {
|
||||
"version": "2.6.0",
|
||||
@@ -7782,7 +7804,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.32.tgz",
|
||||
"integrity": "sha512-Ez8QE4DMfhjjTsES9K2dwfV258qBui7qxUsoaixZDiTzbde4U12e1pXGNu/ECsUIOi5/zoCxAQxIhQnaUQ2VvA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
@@ -7845,7 +7866,6 @@
|
||||
"integrity": "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"csstype": "^3.2.2"
|
||||
}
|
||||
@@ -8780,7 +8800,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"
|
||||
},
|
||||
@@ -9745,7 +9764,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.9.0",
|
||||
"caniuse-lite": "^1.0.30001759",
|
||||
@@ -11144,8 +11162,7 @@
|
||||
"version": "0.0.1367902",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz",
|
||||
"integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "5.2.2",
|
||||
@@ -12162,7 +12179,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",
|
||||
@@ -13470,7 +13486,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"
|
||||
}
|
||||
@@ -13749,7 +13764,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@jrichman/ink/-/ink-6.4.7.tgz",
|
||||
"integrity": "sha512-QHyxhNF5VonF5cRmdAJD/UPucB9nRx3FozWMjQrDGfBxfAL9lpyu72/MlFPgloS1TMTGsOt7YN6dTPPA6mh0Aw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alcalzone/ansi-tokenize": "^0.2.1",
|
||||
"ansi-escapes": "^7.0.0",
|
||||
@@ -15003,7 +15017,6 @@
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
@@ -15353,7 +15366,6 @@
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz",
|
||||
"integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==",
|
||||
"license": "MPL-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
},
|
||||
@@ -19090,7 +19102,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"
|
||||
}
|
||||
@@ -21798,7 +21809,6 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -22120,7 +22130,6 @@
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
|
||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -22202,6 +22211,7 @@
|
||||
"os": [
|
||||
"aix"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22218,6 +22228,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22234,6 +22245,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22250,6 +22262,7 @@
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22266,6 +22279,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22282,6 +22296,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22298,6 +22313,7 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22314,6 +22330,7 @@
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22330,6 +22347,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22346,6 +22364,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22362,6 +22381,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22378,6 +22398,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22394,6 +22415,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22410,6 +22432,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22426,6 +22449,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22442,6 +22466,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22458,6 +22483,7 @@
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22474,6 +22500,7 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22490,6 +22517,7 @@
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22506,6 +22534,7 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22522,6 +22551,7 @@
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22538,6 +22568,7 @@
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22554,6 +22585,7 @@
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22570,6 +22602,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22586,6 +22619,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22602,6 +22636,7 @@
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -22657,6 +22692,7 @@
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
@@ -23591,7 +23627,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"
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { getHooksEnabledSafe } from "@core/hooks/hooks-utils"
|
||||
import { ClineIgnoreController } from "@core/ignore/ClineIgnoreController"
|
||||
import { CommandPermissionController } from "@core/permissions"
|
||||
import { DiffViewProvider } from "@integrations/editor/DiffViewProvider"
|
||||
import type { CommandExecutionOptions } from "@integrations/terminal"
|
||||
import { BrowserSession } from "@services/browser/BrowserSession"
|
||||
import { UrlContentFetcher } from "@services/browser/UrlContentFetcher"
|
||||
import { McpHub } from "@services/mcp/McpHub"
|
||||
@@ -117,7 +118,11 @@ export class ToolExecutor {
|
||||
private saveCheckpoint: (isAttemptCompletionMessage?: boolean, completionMessageTs?: number) => Promise<void>,
|
||||
private sayAndCreateMissingParamError: (toolName: ClineDefaultTool, paramName: string, relPath?: string) => Promise<any>,
|
||||
private removeLastPartialMessageIfExistsWithType: (type: "ask" | "say", askOrSay: ClineAsk | ClineSay) => Promise<void>,
|
||||
private executeCommandTool: (command: string, timeoutSeconds: number | undefined) => Promise<[boolean, any]>,
|
||||
private executeCommandTool: (
|
||||
command: string,
|
||||
timeoutSeconds: number | undefined,
|
||||
options?: CommandExecutionOptions,
|
||||
) => Promise<[boolean, any]>,
|
||||
private cancelRunningCommandTool: () => Promise<boolean>,
|
||||
private doesLatestTaskCompletionHaveNewChanges: () => Promise<boolean>,
|
||||
private updateFCListFromToolResponse: (taskProgress: string | undefined) => Promise<void>,
|
||||
|
||||
@@ -76,6 +76,7 @@ import { getSystemPrompt } from "@/core/prompts/system-prompt"
|
||||
import { HostProvider } from "@/hosts/host-provider"
|
||||
import { FileEditProvider } from "@/integrations/editor/FileEditProvider"
|
||||
import {
|
||||
type CommandExecutionOptions,
|
||||
CommandExecutor,
|
||||
CommandExecutorCallbacks,
|
||||
FullCommandExecutorConfig,
|
||||
@@ -1549,8 +1550,12 @@ export class Task {
|
||||
}
|
||||
|
||||
// Tools
|
||||
async executeCommandTool(command: string, timeoutSeconds: number | undefined): Promise<[boolean, ClineToolResponseContent]> {
|
||||
return this.commandExecutor.execute(command, timeoutSeconds)
|
||||
async executeCommandTool(
|
||||
command: string,
|
||||
timeoutSeconds: number | undefined,
|
||||
options?: CommandExecutionOptions,
|
||||
): Promise<[boolean, ClineToolResponseContent]> {
|
||||
return this.commandExecutor.execute(command, timeoutSeconds, options)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,7 +31,7 @@ export class UseSubagentsToolHandler implements IFullyManagedTool {
|
||||
readonly name = ClineDefaultTool.USE_SUBAGENTS
|
||||
|
||||
getDescription(_block: ToolUse): string {
|
||||
return "[subagent batch]"
|
||||
return "[subagents]"
|
||||
}
|
||||
|
||||
async handlePartialBlock(_block: ToolUse, _uiHelpers: StronglyTypedUIHelpers): Promise<void> {
|
||||
@@ -64,7 +64,6 @@ export class UseSubagentsToolHandler implements IFullyManagedTool {
|
||||
const didAutoApprove = !!autoApproveSafe
|
||||
|
||||
if (didAutoApprove) {
|
||||
await config.callbacks.say("use_subagents", approvalBody, undefined, undefined, false)
|
||||
telemetryService.captureToolUsage(
|
||||
config.ulid,
|
||||
this.name,
|
||||
@@ -115,6 +114,9 @@ export class UseSubagentsToolHandler implements IFullyManagedTool {
|
||||
toolCalls: 0,
|
||||
inputTokens: 0,
|
||||
outputTokens: 0,
|
||||
contextTokens: 0,
|
||||
contextWindow: 0,
|
||||
contextUsagePercentage: 0,
|
||||
}))
|
||||
|
||||
const emitStatus = async (status: ClineSaySubagentStatus["status"], partial: boolean) => {
|
||||
@@ -124,6 +126,9 @@ export class UseSubagentsToolHandler implements IFullyManagedTool {
|
||||
const toolCalls = entries.reduce((acc, entry) => acc + (entry.toolCalls || 0), 0)
|
||||
const inputTokens = entries.reduce((acc, entry) => acc + (entry.inputTokens || 0), 0)
|
||||
const outputTokens = entries.reduce((acc, entry) => acc + (entry.outputTokens || 0), 0)
|
||||
const contextWindow = entries.reduce((acc, entry) => Math.max(acc, entry.contextWindow || 0), 0)
|
||||
const maxContextTokens = entries.reduce((acc, entry) => Math.max(acc, entry.contextTokens || 0), 0)
|
||||
const maxContextUsagePercentage = entries.reduce((acc, entry) => Math.max(acc, entry.contextUsagePercentage || 0), 0)
|
||||
|
||||
const payload: ClineSaySubagentStatus = {
|
||||
status,
|
||||
@@ -134,14 +139,23 @@ export class UseSubagentsToolHandler implements IFullyManagedTool {
|
||||
toolCalls,
|
||||
inputTokens,
|
||||
outputTokens,
|
||||
contextWindow,
|
||||
maxContextTokens,
|
||||
maxContextUsagePercentage,
|
||||
items: entries,
|
||||
}
|
||||
|
||||
await config.callbacks.say("subagent", JSON.stringify(payload), undefined, undefined, partial)
|
||||
}
|
||||
|
||||
let statusUpdateQueue: Promise<void> = Promise.resolve()
|
||||
const queueStatusUpdate = (status: ClineSaySubagentStatus["status"], partial: boolean): Promise<void> => {
|
||||
statusUpdateQueue = statusUpdateQueue.catch(() => undefined).then(() => emitStatus(status, partial))
|
||||
return statusUpdateQueue
|
||||
}
|
||||
|
||||
await config.callbacks.removeLastPartialMessageIfExistsWithType("say", "subagent")
|
||||
await emitStatus("running", true)
|
||||
await queueStatusUpdate("running", true)
|
||||
|
||||
const runners = prompts.map(() => new SubagentRunner(config))
|
||||
const abortPollInterval = setInterval(() => {
|
||||
@@ -174,8 +188,11 @@ export class UseSubagentsToolHandler implements IFullyManagedTool {
|
||||
current.toolCalls = update.stats.toolCalls || 0
|
||||
current.inputTokens = update.stats.inputTokens || 0
|
||||
current.outputTokens = update.stats.outputTokens || 0
|
||||
current.contextTokens = update.stats.contextTokens || 0
|
||||
current.contextWindow = update.stats.contextWindow || 0
|
||||
current.contextUsagePercentage = update.stats.contextUsagePercentage || 0
|
||||
}
|
||||
await emitStatus("running", true)
|
||||
await queueStatusUpdate("running", true)
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -193,24 +210,27 @@ export class UseSubagentsToolHandler implements IFullyManagedTool {
|
||||
entries[index].toolCalls = result.value.stats.toolCalls || 0
|
||||
entries[index].inputTokens = result.value.stats.inputTokens || 0
|
||||
entries[index].outputTokens = result.value.stats.outputTokens || 0
|
||||
entries[index].contextTokens = result.value.stats.contextTokens || 0
|
||||
entries[index].contextWindow = result.value.stats.contextWindow || 0
|
||||
entries[index].contextUsagePercentage = result.value.stats.contextUsagePercentage || 0
|
||||
})
|
||||
|
||||
const failures = entries.filter((entry) => entry.status === "failed").length
|
||||
await emitStatus(failures > 0 ? "failed" : "completed", false)
|
||||
await queueStatusUpdate(failures > 0 ? "failed" : "completed", false)
|
||||
|
||||
const successCount = entries.length - failures
|
||||
const totalToolCalls = entries.reduce((acc, entry) => acc + (entry.toolCalls || 0), 0)
|
||||
const totalInputTokens = entries.reduce((acc, entry) => acc + (entry.inputTokens || 0), 0)
|
||||
const totalOutputTokens = entries.reduce((acc, entry) => acc + (entry.outputTokens || 0), 0)
|
||||
const maxContextUsagePercentage = entries.reduce((acc, entry) => Math.max(acc, entry.contextUsagePercentage || 0), 0)
|
||||
const maxContextTokens = entries.reduce((acc, entry) => Math.max(acc, entry.contextTokens || 0), 0)
|
||||
const contextWindow = entries.reduce((acc, entry) => Math.max(acc, entry.contextWindow || 0), 0)
|
||||
|
||||
const summary = [
|
||||
`Subagent batch complete.`,
|
||||
"Subagent results:",
|
||||
`Total: ${entries.length}`,
|
||||
`Succeeded: ${successCount}`,
|
||||
`Failed: ${failures}`,
|
||||
`Tool calls: ${totalToolCalls}`,
|
||||
`Input tokens: ${totalInputTokens}`,
|
||||
`Output tokens: ${totalOutputTokens}`,
|
||||
`Peak context usage: ${maxContextTokens.toLocaleString()} / ${contextWindow.toLocaleString()} (${maxContextUsagePercentage.toFixed(1)}%)`,
|
||||
"",
|
||||
...entries.map((entry) => {
|
||||
const header = `[${entry.index}] ${entry.status.toUpperCase()} - ${entry.prompt}`
|
||||
|
||||
@@ -147,6 +147,9 @@ describe("SubagentToolHandler", () => {
|
||||
outputTokens: 3,
|
||||
cacheWriteTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
contextTokens: 5,
|
||||
contextWindow: 200000,
|
||||
contextUsagePercentage: 0.0025,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -161,8 +164,8 @@ describe("SubagentToolHandler", () => {
|
||||
})
|
||||
|
||||
sinon.assert.notCalled(callbacks.ask)
|
||||
const approvalSayCalls = callbacks.say.getCalls().filter((call: any) => call.args[0] === "use_subagents")
|
||||
assert.ok(approvalSayCalls.length >= 1)
|
||||
const subagentStatusCalls = callbacks.say.getCalls().filter((call: any) => call.args[0] === "subagent")
|
||||
assert.ok(subagentStatusCalls.length >= 1)
|
||||
})
|
||||
|
||||
it("fans out prompts in parallel and emits aggregated status", async () => {
|
||||
@@ -175,7 +178,16 @@ describe("SubagentToolHandler", () => {
|
||||
maxActiveRuns = Math.max(maxActiveRuns, activeRuns)
|
||||
onProgress({
|
||||
status: "running",
|
||||
stats: { toolCalls: 0, inputTokens: 0, outputTokens: 0, cacheWriteTokens: 0, cacheReadTokens: 0 },
|
||||
stats: {
|
||||
toolCalls: 0,
|
||||
inputTokens: 0,
|
||||
outputTokens: 0,
|
||||
cacheWriteTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
contextTokens: 0,
|
||||
contextWindow: 200000,
|
||||
contextUsagePercentage: 0,
|
||||
},
|
||||
})
|
||||
await delay(10)
|
||||
activeRuns--
|
||||
@@ -188,6 +200,9 @@ describe("SubagentToolHandler", () => {
|
||||
outputTokens: 3,
|
||||
cacheWriteTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
contextTokens: 5,
|
||||
contextWindow: 200000,
|
||||
contextUsagePercentage: 0.0025,
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -228,6 +243,9 @@ describe("SubagentToolHandler", () => {
|
||||
outputTokens: 0,
|
||||
cacheWriteTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
contextTokens: 0,
|
||||
contextWindow: 200000,
|
||||
contextUsagePercentage: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -240,6 +258,9 @@ describe("SubagentToolHandler", () => {
|
||||
outputTokens: 0,
|
||||
cacheWriteTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
contextTokens: 0,
|
||||
contextWindow: 200000,
|
||||
contextUsagePercentage: 0,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -46,6 +46,9 @@ interface SubagentRunStats {
|
||||
outputTokens: number
|
||||
cacheWriteTokens: number
|
||||
cacheReadTokens: number
|
||||
contextTokens: number
|
||||
contextWindow: number
|
||||
contextUsagePercentage: number
|
||||
}
|
||||
|
||||
interface SubagentToolCall {
|
||||
@@ -172,6 +175,9 @@ export class SubagentRunner {
|
||||
outputTokens: 0,
|
||||
cacheWriteTokens: 0,
|
||||
cacheReadTokens: 0,
|
||||
contextTokens: 0,
|
||||
contextWindow: 0,
|
||||
contextUsagePercentage: 0,
|
||||
}
|
||||
|
||||
onProgress({ status: "running", stats })
|
||||
@@ -191,6 +197,7 @@ export class SubagentRunner {
|
||||
mode,
|
||||
customPrompt: this.baseConfig.services.stateManager.getGlobalSettingsKey("customPrompt"),
|
||||
}
|
||||
stats.contextWindow = providerInfo.model.info.contextWindow || 0
|
||||
const useNativeToolCalls =
|
||||
providerInfo.model.info.apiFormat === ApiFormat.OPENAI_RESPONSES ||
|
||||
!!this.baseConfig.services.stateManager.getGlobalStateKey("nativeToolCallEnabled")
|
||||
@@ -244,6 +251,10 @@ export class SubagentRunner {
|
||||
while (true) {
|
||||
const streamHandler = new StreamResponseHandler()
|
||||
const { toolUseHandler } = streamHandler.getHandlers()
|
||||
let requestInputTokens = 0
|
||||
let requestOutputTokens = 0
|
||||
let requestCacheWriteTokens = 0
|
||||
let requestCacheReadTokens = 0
|
||||
|
||||
let assistantText = ""
|
||||
let assistantTextSignature: string | undefined
|
||||
@@ -259,6 +270,14 @@ export class SubagentRunner {
|
||||
stats.outputTokens += chunk.outputTokens || 0
|
||||
stats.cacheWriteTokens += chunk.cacheWriteTokens || 0
|
||||
stats.cacheReadTokens += chunk.cacheReadTokens || 0
|
||||
requestInputTokens += chunk.inputTokens || 0
|
||||
requestOutputTokens += chunk.outputTokens || 0
|
||||
requestCacheWriteTokens += chunk.cacheWriteTokens || 0
|
||||
requestCacheReadTokens += chunk.cacheReadTokens || 0
|
||||
stats.contextTokens =
|
||||
requestInputTokens + requestOutputTokens + requestCacheWriteTokens + requestCacheReadTokens
|
||||
stats.contextUsagePercentage =
|
||||
stats.contextWindow > 0 ? (stats.contextTokens / stats.contextWindow) * 100 : 0
|
||||
onProgress({ stats: { ...stats } })
|
||||
break
|
||||
case "text":
|
||||
@@ -438,12 +457,19 @@ export class SubagentRunner {
|
||||
...this.baseConfig,
|
||||
taskState: state,
|
||||
isSubagentExecution: true,
|
||||
vscodeTerminalExecutionMode: "backgroundExec",
|
||||
callbacks: {
|
||||
...baseCallbacks,
|
||||
say: async () => undefined,
|
||||
sayAndCreateMissingParamError: async (_toolName, paramName) =>
|
||||
formatResponse.toolError(formatResponse.missingToolParameterError(paramName)),
|
||||
executeCommandTool: async (command: string, timeoutSeconds: number | undefined) => {
|
||||
this.activeCommandExecutions += 1
|
||||
try {
|
||||
return await baseCallbacks.executeCommandTool(command, timeoutSeconds)
|
||||
return await baseCallbacks.executeCommandTool(command, timeoutSeconds, {
|
||||
useBackgroundExecution: true,
|
||||
suppressUserInteraction: true,
|
||||
})
|
||||
} finally {
|
||||
this.activeCommandExecutions = Math.max(0, this.activeCommandExecutions - 1)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { FileContextTracker } from "@core/context/context-tracking/FileCont
|
||||
import type { ClineIgnoreController } from "@core/ignore/ClineIgnoreController"
|
||||
import type { CommandPermissionController } from "@core/permissions"
|
||||
import type { DiffViewProvider } from "@integrations/editor/DiffViewProvider"
|
||||
import type { CommandExecutionOptions } from "@integrations/terminal"
|
||||
import type { BrowserSession } from "@services/browser/BrowserSession"
|
||||
import type { UrlContentFetcher } from "@services/browser/UrlContentFetcher"
|
||||
import type { McpHub } from "@services/mcp/McpHub"
|
||||
@@ -105,7 +106,11 @@ export interface TaskCallbacks {
|
||||
|
||||
removeLastPartialMessageIfExistsWithType: (type: "ask" | "say", askOrSay: ClineAsk | ClineSay) => Promise<void>
|
||||
|
||||
executeCommandTool: (command: string, timeoutSeconds: number | undefined) => Promise<[boolean, any]>
|
||||
executeCommandTool: (
|
||||
command: string,
|
||||
timeoutSeconds: number | undefined,
|
||||
options?: CommandExecutionOptions,
|
||||
) => Promise<[boolean, any]>
|
||||
cancelRunningCommandTool?: () => Promise<boolean>
|
||||
|
||||
doesLatestTaskCompletionHaveNewChanges: () => Promise<boolean>
|
||||
|
||||
@@ -19,6 +19,7 @@ import { Logger } from "@/shared/services/Logger"
|
||||
import { orchestrateCommandExecution } from "./CommandOrchestrator"
|
||||
import { StandaloneTerminalManager } from "./standalone/StandaloneTerminalManager"
|
||||
import type {
|
||||
CommandExecutionOptions,
|
||||
CommandExecutorCallbacks,
|
||||
CommandExecutorConfig,
|
||||
ITerminalManager,
|
||||
@@ -94,7 +95,11 @@ export class CommandExecutor {
|
||||
* @param timeoutSeconds Optional timeout in seconds
|
||||
* @returns [userRejected, result] tuple
|
||||
*/
|
||||
async execute(command: string, timeoutSeconds: number | undefined): Promise<[boolean, ClineToolResponseContent]> {
|
||||
async execute(
|
||||
command: string,
|
||||
timeoutSeconds: number | undefined,
|
||||
options?: CommandExecutionOptions,
|
||||
): Promise<[boolean, ClineToolResponseContent]> {
|
||||
// Strip leading `cd` to workspace from command
|
||||
const workspaceCdPrefix = `cd ${this.cwd} && `
|
||||
if (command.startsWith(workspaceCdPrefix)) {
|
||||
@@ -102,7 +107,7 @@ export class CommandExecutor {
|
||||
}
|
||||
|
||||
// Select the appropriate terminal manager
|
||||
const useStandalone = this.terminalExecutionMode === "backgroundExec"
|
||||
const useStandalone = options?.useBackgroundExecution || this.terminalExecutionMode === "backgroundExec"
|
||||
const manager = useStandalone ? this.standaloneManager : this.terminalManager
|
||||
Logger.info(`Executing command in ${useStandalone ? "standalone" : "VSCode"} terminal: ${command}`)
|
||||
|
||||
@@ -125,6 +130,7 @@ export class CommandExecutor {
|
||||
const result = await orchestrateCommandExecution(process, manager, this.callbacks, {
|
||||
command,
|
||||
timeoutSeconds,
|
||||
suppressUserInteraction: options?.suppressUserInteraction,
|
||||
// When "Proceed While Running" is triggered, track the command in the manager
|
||||
// Returns the log file path so the orchestrator can send it to the UI
|
||||
// existingOutput contains all output lines captured so far
|
||||
|
||||
@@ -61,8 +61,35 @@ export async function orchestrateCommandExecution(
|
||||
showShellIntegrationSuggestion,
|
||||
onProceedWhileRunning,
|
||||
terminalType = "vscode",
|
||||
suppressUserInteraction = false,
|
||||
} = options
|
||||
|
||||
const say = async (
|
||||
type: Parameters<CommandExecutorCallbacks["say"]>[0],
|
||||
text?: Parameters<CommandExecutorCallbacks["say"]>[1],
|
||||
images?: Parameters<CommandExecutorCallbacks["say"]>[2],
|
||||
files?: Parameters<CommandExecutorCallbacks["say"]>[3],
|
||||
partial?: Parameters<CommandExecutorCallbacks["say"]>[4],
|
||||
): Promise<Awaited<ReturnType<CommandExecutorCallbacks["say"]>>> => {
|
||||
if (suppressUserInteraction) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return callbacks.say(type, text, images, files, partial)
|
||||
}
|
||||
|
||||
const ask = async (
|
||||
type: Parameters<CommandExecutorCallbacks["ask"]>[0],
|
||||
text?: Parameters<CommandExecutorCallbacks["ask"]>[1],
|
||||
partial?: Parameters<CommandExecutorCallbacks["ask"]>[2],
|
||||
): Promise<Awaited<ReturnType<CommandExecutorCallbacks["ask"]>> | undefined> => {
|
||||
if (suppressUserInteraction) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return callbacks.ask(type, text, partial)
|
||||
}
|
||||
|
||||
// Track command execution state
|
||||
callbacks.updateBackgroundCommandState(true)
|
||||
|
||||
@@ -121,7 +148,11 @@ export async function orchestrateCommandExecution(
|
||||
try {
|
||||
// Use ask() to present output and wait for user response
|
||||
// This enables "Proceed While Running" button functionality
|
||||
const { response, text, images, files } = await callbacks.ask("command_output", chunk)
|
||||
const interaction = await ask("command_output", chunk)
|
||||
if (!interaction) {
|
||||
return
|
||||
}
|
||||
const { response, text, images, files } = interaction
|
||||
|
||||
if (response === "yesButtonClicked") {
|
||||
// Track when user clicks "Proceed While Running"
|
||||
@@ -167,7 +198,7 @@ export async function orchestrateCommandExecution(
|
||||
// Send log file message to UI BEFORE resuming the process
|
||||
// This ensures the message appears before any new output lines
|
||||
if (trackingResult?.logFilePath) {
|
||||
await callbacks.say("command_output", `\n📋 Output is being logged to: ${trackingResult.logFilePath}`)
|
||||
await say("command_output", `\n📋 Output is being logged to: ${trackingResult.logFilePath}`)
|
||||
}
|
||||
|
||||
// Now resume the process - any new lines will be handled by the background tracker
|
||||
@@ -186,7 +217,7 @@ export async function orchestrateCommandExecution(
|
||||
outputBufferSize = 0
|
||||
// Send cancellation message BEFORE resuming the process
|
||||
// This ensures the message appears before any new output lines
|
||||
await callbacks.say("command_output", "Command cancelled")
|
||||
await say("command_output", "Command cancelled")
|
||||
// Now resume the process
|
||||
process.continue()
|
||||
} else {
|
||||
@@ -209,7 +240,7 @@ export async function orchestrateCommandExecution(
|
||||
}
|
||||
} else {
|
||||
// After "Proceed While Running": stream output directly to UI
|
||||
await callbacks.say("command_output", chunk)
|
||||
await say("command_output", chunk)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +276,7 @@ export async function orchestrateCommandExecution(
|
||||
outputBufferSize = 0
|
||||
if (!didContinue) {
|
||||
// Use say() instead of ask() since we're transitioning to file mode
|
||||
await callbacks.say("command_output", chunk)
|
||||
await say("command_output", chunk)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,7 +302,7 @@ export async function orchestrateCommandExecution(
|
||||
lastLines = outputLines.slice(-SUMMARY_LINES_TO_KEEP)
|
||||
|
||||
// FINALLY: Notify user (now this will appear at the end after all buffered output)
|
||||
await callbacks.say(
|
||||
await say(
|
||||
"command_output",
|
||||
`\n📋 Output is large (${outputLines.length} lines, ${Math.round(totalOutputBytes / 1024)}KB). Writing to: ${largeOutputLogPath}`,
|
||||
)
|
||||
@@ -346,7 +377,7 @@ export async function orchestrateCommandExecution(
|
||||
// After "Proceed While Running" (without background tracking): stream output directly to UI
|
||||
// But throttle if we're in file mode to avoid flooding UI
|
||||
if (!isWritingToFile) {
|
||||
await callbacks.say("command_output", line)
|
||||
await say("command_output", line)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -383,9 +414,9 @@ export async function orchestrateCommandExecution(
|
||||
|
||||
process.once("no_shell_integration", async () => {
|
||||
if (showShellIntegrationSuggestion) {
|
||||
await callbacks.say("shell_integration_warning_with_suggestion")
|
||||
await say("shell_integration_warning_with_suggestion")
|
||||
} else {
|
||||
await callbacks.say("shell_integration_warning")
|
||||
await say("shell_integration_warning")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -435,7 +466,7 @@ export async function orchestrateCommandExecution(
|
||||
|
||||
// Send log file message to UI BEFORE resuming the process
|
||||
if (trackingResult?.logFilePath) {
|
||||
await callbacks.say(
|
||||
await say(
|
||||
"command_output",
|
||||
`\n⏱️ Command timed out. Output is being logged to: ${trackingResult.logFilePath}`,
|
||||
)
|
||||
@@ -523,7 +554,7 @@ export async function orchestrateCommandExecution(
|
||||
}
|
||||
|
||||
if (userFeedback) {
|
||||
await callbacks.say("user_feedback", userFeedback.text, userFeedback.images, userFeedback.files)
|
||||
await say("user_feedback", userFeedback.text, userFeedback.images, userFeedback.files)
|
||||
|
||||
let fileContentString = ""
|
||||
if (userFeedback.files && userFeedback.files.length > 0) {
|
||||
|
||||
@@ -36,6 +36,7 @@ export type {
|
||||
// Command Executor types
|
||||
ActiveBackgroundCommand,
|
||||
AskResponse,
|
||||
CommandExecutionOptions,
|
||||
CommandExecutorCallbacks,
|
||||
CommandExecutorConfig,
|
||||
FullCommandExecutorConfig,
|
||||
|
||||
@@ -341,6 +341,22 @@ export interface CommandExecutorCallbacks {
|
||||
addToUserMessageContent: (content: { type: string; text: string }) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional per-command execution behavior overrides.
|
||||
*/
|
||||
export interface CommandExecutionOptions {
|
||||
/**
|
||||
* Force command execution in standalone/background terminal mode for this command.
|
||||
* This is useful for subagent runs and headless-style execution flows.
|
||||
*/
|
||||
useBackgroundExecution?: boolean
|
||||
/**
|
||||
* Suppress command interaction/output UI messages (ask/say) for this command execution.
|
||||
* Command output is still captured and returned as the tool result.
|
||||
*/
|
||||
suppressUserInteraction?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for CommandExecutor
|
||||
*/
|
||||
@@ -388,6 +404,11 @@ export interface OrchestrationOptions {
|
||||
* Defaults to "vscode" for backward compatibility.
|
||||
*/
|
||||
terminalType?: "vscode" | "standalone"
|
||||
/**
|
||||
* If true, suppresses command-output ask/say UI interactions.
|
||||
* Output is still collected and included in the final result.
|
||||
*/
|
||||
suppressUserInteraction?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,7 +37,6 @@ export type Platform = "aix" | "darwin" | "freebsd" | "linux" | "openbsd" | "sun
|
||||
export const DEFAULT_PLATFORM = "unknown"
|
||||
|
||||
export const COMMAND_CANCEL_TOKEN = "__cline_command_cancel__"
|
||||
|
||||
export interface ExtensionState {
|
||||
isNewUser: boolean
|
||||
welcomeViewCompleted: boolean
|
||||
@@ -279,6 +278,9 @@ export interface SubagentStatusItem {
|
||||
toolCalls: number
|
||||
inputTokens: number
|
||||
outputTokens: number
|
||||
contextTokens: number
|
||||
contextWindow: number
|
||||
contextUsagePercentage: number
|
||||
result?: string
|
||||
error?: string
|
||||
}
|
||||
@@ -292,6 +294,9 @@ export interface ClineSaySubagentStatus {
|
||||
toolCalls: number
|
||||
inputTokens: number
|
||||
outputTokens: number
|
||||
contextWindow: number
|
||||
maxContextTokens: number
|
||||
maxContextUsagePercentage: number
|
||||
items: SubagentStatusItem[]
|
||||
}
|
||||
|
||||
|
||||
Generated
+12
-35
@@ -160,7 +160,6 @@
|
||||
"version": "7.28.4",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.27.1",
|
||||
"@babel/generator": "^7.28.3",
|
||||
@@ -501,7 +500,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -523,7 +521,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -531,7 +528,6 @@
|
||||
"node_modules/@emotion/is-prop-valid": {
|
||||
"version": "1.2.2",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@emotion/memoize": "^0.8.1"
|
||||
}
|
||||
@@ -1037,7 +1033,6 @@
|
||||
"node_modules/@firebase/app": {
|
||||
"version": "0.13.2",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@firebase/component": "0.6.18",
|
||||
"@firebase/logger": "0.4.4",
|
||||
@@ -1094,7 +1089,6 @@
|
||||
"node_modules/@firebase/app-compat": {
|
||||
"version": "0.4.2",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@firebase/app": "0.13.2",
|
||||
"@firebase/component": "0.6.18",
|
||||
@@ -1108,8 +1102,7 @@
|
||||
},
|
||||
"node_modules/@firebase/app-types": {
|
||||
"version": "0.9.3",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/@firebase/auth-compat": {
|
||||
"version": "0.5.28",
|
||||
@@ -1496,7 +1489,6 @@
|
||||
"version": "1.12.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
},
|
||||
@@ -2593,7 +2585,6 @@
|
||||
"node_modules/@heroui/system": {
|
||||
"version": "2.4.22",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@heroui/react-utils": "2.1.13",
|
||||
"@heroui/system-rsc": "2.3.19",
|
||||
@@ -2678,7 +2669,6 @@
|
||||
"node_modules/@heroui/theme": {
|
||||
"version": "2.4.22",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@heroui/shared-utils": "2.1.11",
|
||||
"clsx": "^1.2.1",
|
||||
@@ -6361,7 +6351,8 @@
|
||||
"node_modules/@types/aria-query": {
|
||||
"version": "5.0.4",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
@@ -6738,7 +6729,6 @@
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.18",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^3.0.2"
|
||||
@@ -6748,7 +6738,6 @@
|
||||
"version": "18.3.7",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.0.0"
|
||||
}
|
||||
@@ -7140,7 +7129,6 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.8.3",
|
||||
"caniuse-lite": "^1.0.30001741",
|
||||
@@ -7270,7 +7258,6 @@
|
||||
"node_modules/chevrotain": {
|
||||
"version": "11.0.3",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@chevrotain/cst-dts-gen": "11.0.3",
|
||||
"@chevrotain/gast": "11.0.3",
|
||||
@@ -7541,7 +7528,6 @@
|
||||
"node_modules/cytoscape": {
|
||||
"version": "3.33.1",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
@@ -7874,7 +7860,6 @@
|
||||
"node_modules/d3-selection": {
|
||||
"version": "3.0.0",
|
||||
"license": "ISC",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
@@ -8101,7 +8086,8 @@
|
||||
"node_modules/dom-accessibility-api": {
|
||||
"version": "0.5.16",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.2.7",
|
||||
@@ -8164,7 +8150,6 @@
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
@@ -8445,7 +8430,6 @@
|
||||
"node_modules/framer-motion": {
|
||||
"version": "12.23.18",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"motion-dom": "^12.23.18",
|
||||
"motion-utils": "^12.23.6",
|
||||
@@ -9388,7 +9372,6 @@
|
||||
"version": "26.1.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"cssstyle": "^4.2.1",
|
||||
"data-urls": "^5.0.0",
|
||||
@@ -9859,6 +9842,7 @@
|
||||
"version": "1.5.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"lz-string": "bin/bin.js"
|
||||
}
|
||||
@@ -11761,6 +11745,7 @@
|
||||
"version": "27.5.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1",
|
||||
"ansi-styles": "^5.0.0",
|
||||
@@ -11774,6 +11759,7 @@
|
||||
"version": "5.2.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
@@ -11836,7 +11822,6 @@
|
||||
"node_modules/react": {
|
||||
"version": "18.3.1",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -11875,7 +11860,6 @@
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.3.1",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -11887,7 +11871,8 @@
|
||||
"node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/react-markdown": {
|
||||
"version": "10.1.0",
|
||||
@@ -12551,7 +12536,6 @@
|
||||
"version": "4.52.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
@@ -12875,7 +12859,6 @@
|
||||
"version": "9.1.17",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@storybook/global": "^5.0.0",
|
||||
"@testing-library/jest-dom": "^6.6.3",
|
||||
@@ -13141,7 +13124,6 @@
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "3.3.1",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/dcastil"
|
||||
@@ -13166,8 +13148,7 @@
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "4.1.13",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tailwindcss-animate": {
|
||||
"version": "1.0.7",
|
||||
@@ -13379,14 +13360,12 @@
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"license": "0BSD",
|
||||
"peer": true
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.9.2",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -13739,7 +13718,6 @@
|
||||
"version": "7.2.2",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -13861,7 +13839,6 @@
|
||||
"version": "3.2.4",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/expect": "3.2.4",
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { ClineMessage, ClineSaySubagentStatus, SubagentExecutionStatus } from "@shared/ExtensionMessage"
|
||||
import { CheckIcon, CircleSlashIcon, CircleXIcon, LoaderCircleIcon } from "lucide-react"
|
||||
import { useMemo } from "react"
|
||||
import {
|
||||
BotIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronRightIcon,
|
||||
CircleSlashIcon,
|
||||
CircleXIcon,
|
||||
LoaderCircleIcon,
|
||||
} from "lucide-react"
|
||||
import { useMemo, useState } from "react"
|
||||
|
||||
interface SubagentStatusRowProps {
|
||||
message: ClineMessage
|
||||
@@ -8,7 +16,9 @@ interface SubagentStatusRowProps {
|
||||
lastModifiedMessage?: ClineMessage
|
||||
}
|
||||
|
||||
const statusLabel = (status: SubagentExecutionStatus): string => {
|
||||
type DisplayStatus = SubagentExecutionStatus | "cancelled"
|
||||
|
||||
const statusLabel = (status: DisplayStatus): string => {
|
||||
switch (status) {
|
||||
case "pending":
|
||||
return "Pending"
|
||||
@@ -18,21 +28,25 @@ const statusLabel = (status: SubagentExecutionStatus): string => {
|
||||
return "Completed"
|
||||
case "failed":
|
||||
return "Failed"
|
||||
case "cancelled":
|
||||
return "Cancelled"
|
||||
default:
|
||||
return "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
const aggregateIcon = (status: ClineSaySubagentStatus["status"]) => {
|
||||
const statusIcon = (status: DisplayStatus) => {
|
||||
switch (status) {
|
||||
case "running":
|
||||
return <LoaderCircleIcon className="size-2 mr-2 animate-spin text-link" />
|
||||
return <LoaderCircleIcon className="size-2 animate-spin text-link shrink-0 mt-[1px]" />
|
||||
case "completed":
|
||||
return <CheckIcon className="size-2 mr-2 text-success" />
|
||||
return <CheckIcon className="size-2 text-success shrink-0 mt-[1px]" />
|
||||
case "failed":
|
||||
return <CircleXIcon className="size-2 mr-2 text-error" />
|
||||
return <CircleXIcon className="size-2 text-error shrink-0 mt-[1px]" />
|
||||
case "cancelled":
|
||||
return <CircleSlashIcon className="size-2 text-foreground shrink-0 mt-[1px]" />
|
||||
default:
|
||||
return <LoaderCircleIcon className="size-2 mr-2 animate-spin text-link" />
|
||||
return <BotIcon className="size-2 text-foreground/70 shrink-0 mt-[1px]" />
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +59,7 @@ const formatCount = (value: number | undefined): string => {
|
||||
}
|
||||
|
||||
export default function SubagentStatusRow({ message, isLast, lastModifiedMessage }: SubagentStatusRowProps) {
|
||||
const [expandedItems, setExpandedItems] = useState<Record<number, boolean>>({})
|
||||
const data = useMemo(() => {
|
||||
try {
|
||||
if (!message.text) {
|
||||
@@ -63,45 +78,66 @@ export default function SubagentStatusRow({ message, isLast, lastModifiedMessage
|
||||
const wasCancelled =
|
||||
data.status === "running" &&
|
||||
(!isLast || lastModifiedMessage?.ask === "resume_task" || lastModifiedMessage?.ask === "resume_completed_task")
|
||||
const displayStatus: ClineSaySubagentStatus["status"] = wasCancelled ? "failed" : data.status
|
||||
|
||||
const singular = data.items.length === 1
|
||||
const title = singular ? "Cline wants to use a subagent:" : "Cline wants to use subagents:"
|
||||
const toggleItem = (index: number) => {
|
||||
setExpandedItems((prev) => ({
|
||||
...prev,
|
||||
[index]: !prev[index],
|
||||
}))
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-code border border-editor-group-border rounded-sm py-2.5 px-3">
|
||||
<div className="flex items-center">
|
||||
{wasCancelled ? <CircleSlashIcon className="size-2 mr-2" /> : aggregateIcon(displayStatus)}
|
||||
<span className="font-semibold text-foreground">Subagent batch</span>
|
||||
{wasCancelled && <span className="ml-2 text-xs opacity-80">Cancelled</span>}
|
||||
<div className="ml-2 text-xs opacity-80">
|
||||
{data.completed}/{data.total} complete, {data.successes} succeeded, {data.failures} failed
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 text-xs opacity-75">
|
||||
{formatCount(data.toolCalls)} tool calls, {formatCount(data.inputTokens)} input tokens,{" "}
|
||||
{formatCount(data.outputTokens)} output tokens
|
||||
</div>
|
||||
<div className="text-sm text-foreground">{title}</div>
|
||||
<div className="mt-2 space-y-2">
|
||||
{data.items.map((entry) => (
|
||||
<div
|
||||
className="rounded-xs border border-editor-group-border bg-vscode-editor-background px-2 py-1.5"
|
||||
key={entry.index}>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="text-xs font-medium text-foreground">
|
||||
[{entry.index}] {statusLabel(entry.status)}
|
||||
</div>
|
||||
<div className="text-[11px] opacity-70">
|
||||
{formatCount(entry.toolCalls || 0)} tools, {formatCount(entry.inputTokens || 0)} in,{" "}
|
||||
{formatCount(entry.outputTokens || 0)} out
|
||||
{data.items.map((entry) => {
|
||||
const displayStatus: DisplayStatus =
|
||||
wasCancelled && (entry.status === "running" || entry.status === "pending") ? "cancelled" : entry.status
|
||||
const hasDetails = Boolean(
|
||||
(entry.result && entry.status === "completed") || (entry.error && entry.status === "failed"),
|
||||
)
|
||||
const isExpanded = expandedItems[entry.index] === true
|
||||
return (
|
||||
<div
|
||||
className="rounded-xs border border-editor-group-border bg-vscode-editor-background px-2 py-1.5"
|
||||
key={entry.index}>
|
||||
<div className="flex items-start gap-2">
|
||||
{statusIcon(displayStatus)}
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-xs font-medium text-foreground whitespace-pre-wrap break-words">
|
||||
Subagent: "{entry.prompt}"
|
||||
</div>
|
||||
<div className="mt-1 text-[11px] opacity-70">
|
||||
#{entry.index} | {statusLabel(displayStatus)} | {formatCount(entry.toolCalls)} tools
|
||||
called | {formatCount(entry.contextTokens)} tokens used
|
||||
</div>
|
||||
{hasDetails && (
|
||||
<button
|
||||
aria-label={isExpanded ? "Collapse subagent output" : "Expand subagent output"}
|
||||
className="mt-1 text-[11px] opacity-80 flex items-center gap-1.5 bg-transparent border-0 p-0 cursor-pointer text-left text-foreground"
|
||||
onClick={() => toggleItem(entry.index)}
|
||||
type="button">
|
||||
{isExpanded ? (
|
||||
<ChevronDownIcon className="size-2" />
|
||||
) : (
|
||||
<ChevronRightIcon className="size-2" />
|
||||
)}
|
||||
<span>{isExpanded ? "Hide output" : "Show output"}</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{isExpanded && entry.result && entry.status === "completed" && (
|
||||
<div className="mt-2 text-xs opacity-80 whitespace-pre-wrap break-words">{entry.result}</div>
|
||||
)}
|
||||
{isExpanded && entry.error && entry.status === "failed" && (
|
||||
<div className="mt-2 text-xs text-error whitespace-pre-wrap break-words">{entry.error}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-1 text-xs font-editor whitespace-pre-wrap break-words">{entry.prompt}</div>
|
||||
{entry.result && entry.status === "completed" && (
|
||||
<div className="mt-1 text-xs opacity-80 whitespace-pre-wrap break-words">{entry.result}</div>
|
||||
)}
|
||||
{entry.error && entry.status === "failed" && (
|
||||
<div className="mt-1 text-xs text-error whitespace-pre-wrap break-words">{entry.error}</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -63,6 +63,11 @@ export function filterVisibleMessages(messages: ClineMessage[]): ClineMessage[]
|
||||
case "resume_task":
|
||||
case "resume_completed_task":
|
||||
return false
|
||||
case "use_subagents":
|
||||
if (arr.slice(index + 1).some((candidate) => candidate.type === "say" && candidate.say === "subagent")) {
|
||||
return false
|
||||
}
|
||||
break
|
||||
}
|
||||
switch (message.say) {
|
||||
case "api_req_finished": // combineApiRequests removes this from modifiedMessages anyways
|
||||
@@ -93,6 +98,11 @@ export function filterVisibleMessages(messages: ClineMessage[]): ClineMessage[]
|
||||
break
|
||||
case "mcp_server_request_started":
|
||||
return false
|
||||
case "use_subagents":
|
||||
if (arr.slice(index + 1).some((candidate) => candidate.type === "say" && candidate.say === "subagent")) {
|
||||
return false
|
||||
}
|
||||
break
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user