mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 12:40:32 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
325c513f1b | ||
|
|
87fa0a23c0 | ||
|
|
c5a49e7481 | ||
|
|
c597cfae85 | ||
|
|
a31f4534dd | ||
|
|
2e9bb8e82b | ||
|
|
cfdb6463d6 | ||
|
|
adb495d5d3 | ||
|
|
11ca660dec | ||
|
|
32898580a5 | ||
|
|
a7794b5ffb | ||
|
|
8802888e39 | ||
|
|
e4cebeca96 | ||
|
|
45a539257b | ||
|
|
670fb18728 | ||
|
|
36ea238d76 | ||
|
|
8366864daf |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
node_modules
|
||||
dist
|
||||
.DS_Store
|
||||
.claude/*.local.*
|
||||
CLAUDE.local.md
|
||||
|
||||
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,5 +1,21 @@
|
||||
# Changelog
|
||||
|
||||
## 0.14.0
|
||||
|
||||
- Update to @anthropic-ai/claude-agent-sdk@0.2.29
|
||||
- Update to using the recommended `CLAUDE_CONFIG_DIR` env variable for setting where config files are kept
|
||||
- Support /context command
|
||||
- Fix incorrect context type mapping for tool calls
|
||||
- Fix glob metching for file permissions on Windows
|
||||
- Support the `IS_SANDBOX` env var for supporting bypass permissions in root mode
|
||||
- Fix missing notification for entering plan mode
|
||||
- Experimental unstable support for listing sessions
|
||||
|
||||
## 0.13.2
|
||||
|
||||
- Update to @anthropic-ai/claude-agent-sdk@0.2.22
|
||||
- Fix: return content from ACP write tool to help with issues with alternate providers.
|
||||
|
||||
## 0.13.1
|
||||
|
||||
- Update to @anthropic-ai/claude-agent-sdk@0.2.7
|
||||
|
||||
492
package-lock.json
generated
492
package-lock.json
generated
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "@zed-industries/claude-code-acp",
|
||||
"version": "0.13.1",
|
||||
"version": "0.14.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@zed-industries/claude-code-acp",
|
||||
"version": "0.13.1",
|
||||
"version": "0.14.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "0.13.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.7",
|
||||
"@modelcontextprotocol/sdk": "1.25.2",
|
||||
"@agentclientprotocol/sdk": "0.13.1",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.29",
|
||||
"@modelcontextprotocol/sdk": "1.25.3",
|
||||
"diff": "8.0.3",
|
||||
"minimatch": "10.1.1"
|
||||
},
|
||||
@@ -19,32 +19,32 @@
|
||||
"claude-code-acp": "dist/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "0.71.2",
|
||||
"@types/node": "25.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.53.0",
|
||||
"@typescript-eslint/parser": "8.53.0",
|
||||
"@anthropic-ai/sdk": "0.72.1",
|
||||
"@types/node": "25.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.54.0",
|
||||
"@typescript-eslint/parser": "8.54.0",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"globals": "17.0.0",
|
||||
"prettier": "3.8.0",
|
||||
"globals": "17.3.0",
|
||||
"prettier": "3.8.1",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.0.17"
|
||||
"vitest": "4.0.18"
|
||||
}
|
||||
},
|
||||
"node_modules/@agentclientprotocol/sdk": {
|
||||
"version": "0.13.0",
|
||||
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.13.0.tgz",
|
||||
"integrity": "sha512-Z6/Fp4cXLbYdMXr5AK752JM5qG2VKb6ShM0Ql6FimBSckMmLyK54OA20UhPYoH4C37FSFwUTARuwQOwQUToYrw==",
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.13.1.tgz",
|
||||
"integrity": "sha512-6byvu+F/xc96GBkdAx4hq6/tB3vT63DSBO4i3gYCz8nuyZMerVFna2Gkhm8EHNpZX0J9DjUxzZCW+rnHXUg0FA==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"zod": "^3.25.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk": {
|
||||
"version": "0.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.2.7.tgz",
|
||||
"integrity": "sha512-I1/zcnLah74kZeRkj/1QnDaC6ItJ2m/Bftlm25uoaRkZx7i7SkcpqM9jGE/r2A8PMxnw5WpabP60Xgj99CrTuw==",
|
||||
"version": "0.2.29",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.2.29.tgz",
|
||||
"integrity": "sha512-b+655n4ZqqAiMQEL3P44e9UurkI7WWanWTQQQTEcKngL5YCjjXExEPEJRxrmqp8mQXs0kLErZhObx0ZuwibOhA==",
|
||||
"license": "SEE LICENSE IN README.md",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
@@ -64,9 +64,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/sdk": {
|
||||
"version": "0.71.2",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz",
|
||||
"integrity": "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==",
|
||||
"version": "0.72.1",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.72.1.tgz",
|
||||
"integrity": "sha512-MiUnue7qN7DvLIoYHgkedN2z05mRf2CutBzjXXY2krzOhG2r/rIfISS2uVkNLikgToB5hYIzw+xp2jdOtRkqYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1152,12 +1152,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.25.2",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz",
|
||||
"integrity": "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==",
|
||||
"version": "1.25.3",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.3.tgz",
|
||||
"integrity": "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@hono/node-server": "^1.19.7",
|
||||
"@hono/node-server": "^1.19.9",
|
||||
"ajv": "^8.17.1",
|
||||
"ajv-formats": "^3.0.1",
|
||||
"content-type": "^1.0.5",
|
||||
@@ -1191,9 +1191,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz",
|
||||
"integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz",
|
||||
"integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1205,9 +1205,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz",
|
||||
"integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1219,9 +1219,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.1.tgz",
|
||||
"integrity": "sha512-p3grE2PHcQm2e8PSGZdzIhCKbMCw/xi9XvMPErPhwO17vxtvCN5FEA2mSLgmKlCjHGMQTP6phuQTYWUnKewwGg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1233,9 +1233,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz",
|
||||
"integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz",
|
||||
"integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1247,9 +1247,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz",
|
||||
"integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1261,9 +1261,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz",
|
||||
"integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz",
|
||||
"integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1275,9 +1275,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz",
|
||||
"integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz",
|
||||
"integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1289,9 +1289,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz",
|
||||
"integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz",
|
||||
"integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1303,9 +1303,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz",
|
||||
"integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1317,9 +1317,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz",
|
||||
"integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1331,9 +1331,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz",
|
||||
"integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1345,9 +1345,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loong64-musl": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz",
|
||||
"integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1359,9 +1359,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz",
|
||||
"integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1373,9 +1373,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-musl": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz",
|
||||
"integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1387,9 +1387,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz",
|
||||
"integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1401,9 +1401,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz",
|
||||
"integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1415,9 +1415,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz",
|
||||
"integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1429,9 +1429,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz",
|
||||
"integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1443,9 +1443,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz",
|
||||
"integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz",
|
||||
"integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1457,9 +1457,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openbsd-x64": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz",
|
||||
"integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz",
|
||||
"integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1471,9 +1471,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz",
|
||||
"integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz",
|
||||
"integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1485,9 +1485,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz",
|
||||
"integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz",
|
||||
"integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1499,9 +1499,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz",
|
||||
"integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz",
|
||||
"integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1513,9 +1513,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-gnu": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz",
|
||||
"integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz",
|
||||
"integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1527,9 +1527,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz",
|
||||
"integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz",
|
||||
"integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1608,9 +1608,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "25.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.8.tgz",
|
||||
"integrity": "sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg==",
|
||||
"version": "25.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz",
|
||||
"integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1618,17 +1618,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.53.0.tgz",
|
||||
"integrity": "sha512-eEXsVvLPu8Z4PkFibtuFJLJOTAV/nPdgtSjkGoPpddpFk3/ym2oy97jynY6ic2m6+nc5M8SE1e9v/mHKsulcJg==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz",
|
||||
"integrity": "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@typescript-eslint/scope-manager": "8.53.0",
|
||||
"@typescript-eslint/type-utils": "8.53.0",
|
||||
"@typescript-eslint/utils": "8.53.0",
|
||||
"@typescript-eslint/visitor-keys": "8.53.0",
|
||||
"@typescript-eslint/scope-manager": "8.54.0",
|
||||
"@typescript-eslint/type-utils": "8.54.0",
|
||||
"@typescript-eslint/utils": "8.54.0",
|
||||
"@typescript-eslint/visitor-keys": "8.54.0",
|
||||
"ignore": "^7.0.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.4.0"
|
||||
@@ -1641,22 +1641,22 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.53.0",
|
||||
"@typescript-eslint/parser": "^8.54.0",
|
||||
"eslint": "^8.57.0 || ^9.0.0",
|
||||
"typescript": ">=4.8.4 <6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.53.0.tgz",
|
||||
"integrity": "sha512-npiaib8XzbjtzS2N4HlqPvlpxpmZ14FjSJrteZpPxGUaYPlvhzlzUZ4mZyABo0EFrOWnvyd0Xxroq//hKhtAWg==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.54.0.tgz",
|
||||
"integrity": "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.53.0",
|
||||
"@typescript-eslint/types": "8.53.0",
|
||||
"@typescript-eslint/typescript-estree": "8.53.0",
|
||||
"@typescript-eslint/visitor-keys": "8.53.0",
|
||||
"@typescript-eslint/scope-manager": "8.54.0",
|
||||
"@typescript-eslint/types": "8.54.0",
|
||||
"@typescript-eslint/typescript-estree": "8.54.0",
|
||||
"@typescript-eslint/visitor-keys": "8.54.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1672,14 +1672,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.53.0.tgz",
|
||||
"integrity": "sha512-Bl6Gdr7NqkqIP5yP9z1JU///Nmes4Eose6L1HwpuVHwScgDPPuEWbUVhvlZmb8hy0vX9syLk5EGNL700WcBlbg==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.54.0.tgz",
|
||||
"integrity": "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.53.0",
|
||||
"@typescript-eslint/types": "^8.53.0",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.54.0",
|
||||
"@typescript-eslint/types": "^8.54.0",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1694,14 +1694,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.53.0.tgz",
|
||||
"integrity": "sha512-kWNj3l01eOGSdVBnfAF2K1BTh06WS0Yet6JUgb9Cmkqaz3Jlu0fdVUjj9UI8gPidBWSMqDIglmEXifSgDT/D0g==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz",
|
||||
"integrity": "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.0",
|
||||
"@typescript-eslint/visitor-keys": "8.53.0"
|
||||
"@typescript-eslint/types": "8.54.0",
|
||||
"@typescript-eslint/visitor-keys": "8.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1712,9 +1712,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.53.0.tgz",
|
||||
"integrity": "sha512-K6Sc0R5GIG6dNoPdOooQ+KtvT5KCKAvTcY8h2rIuul19vxH5OTQk7ArKkd4yTzkw66WnNY0kPPzzcmWA+XRmiA==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz",
|
||||
"integrity": "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1729,15 +1729,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.53.0.tgz",
|
||||
"integrity": "sha512-BBAUhlx7g4SmcLhn8cnbxoxtmS7hcq39xKCgiutL3oNx1TaIp+cny51s8ewnKMpVUKQUGb41RAUWZ9kxYdovuw==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz",
|
||||
"integrity": "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.0",
|
||||
"@typescript-eslint/typescript-estree": "8.53.0",
|
||||
"@typescript-eslint/utils": "8.53.0",
|
||||
"@typescript-eslint/types": "8.54.0",
|
||||
"@typescript-eslint/typescript-estree": "8.54.0",
|
||||
"@typescript-eslint/utils": "8.54.0",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.4.0"
|
||||
},
|
||||
@@ -1754,9 +1754,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.53.0.tgz",
|
||||
"integrity": "sha512-Bmh9KX31Vlxa13+PqPvt4RzKRN1XORYSLlAE+sO1i28NkisGbTtSLFVB3l7PWdHtR3E0mVMuC7JilWJ99m2HxQ==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.54.0.tgz",
|
||||
"integrity": "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1768,16 +1768,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.53.0.tgz",
|
||||
"integrity": "sha512-pw0c0Gdo7Z4xOG987u3nJ8akL9093yEEKv8QTJ+Bhkghj1xyj8cgPaavlr9rq8h7+s6plUJ4QJYw2gCZodqmGw==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz",
|
||||
"integrity": "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.53.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.53.0",
|
||||
"@typescript-eslint/types": "8.53.0",
|
||||
"@typescript-eslint/visitor-keys": "8.53.0",
|
||||
"@typescript-eslint/project-service": "8.54.0",
|
||||
"@typescript-eslint/tsconfig-utils": "8.54.0",
|
||||
"@typescript-eslint/types": "8.54.0",
|
||||
"@typescript-eslint/visitor-keys": "8.54.0",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^9.0.5",
|
||||
"semver": "^7.7.3",
|
||||
@@ -1822,16 +1822,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.53.0.tgz",
|
||||
"integrity": "sha512-XDY4mXTez3Z1iRDI5mbRhH4DFSt46oaIFsLg+Zn97+sYrXACziXSQcSelMybnVZ5pa1P6xYkPr5cMJyunM1ZDA==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.54.0.tgz",
|
||||
"integrity": "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.53.0",
|
||||
"@typescript-eslint/types": "8.53.0",
|
||||
"@typescript-eslint/typescript-estree": "8.53.0"
|
||||
"@typescript-eslint/scope-manager": "8.54.0",
|
||||
"@typescript-eslint/types": "8.54.0",
|
||||
"@typescript-eslint/typescript-estree": "8.54.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1846,13 +1846,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.53.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.53.0.tgz",
|
||||
"integrity": "sha512-LZ2NqIHFhvFwxG0qZeLL9DvdNAHPGCY5dIRwBhyYeU+LfLhcStE1ImjsuTG/WaVh3XysGaeLW8Rqq7cGkPCFvw==",
|
||||
"version": "8.54.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz",
|
||||
"integrity": "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.53.0",
|
||||
"@typescript-eslint/types": "8.54.0",
|
||||
"eslint-visitor-keys": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1877,16 +1877,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.17.tgz",
|
||||
"integrity": "sha512-mEoqP3RqhKlbmUmntNDDCJeTDavDR+fVYkSOw8qRwJFaW/0/5zA9zFeTrHqNtcmwh6j26yMmwx2PqUDPzt5ZAQ==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz",
|
||||
"integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.0.17",
|
||||
"@vitest/utils": "4.0.17",
|
||||
"@vitest/spy": "4.0.18",
|
||||
"@vitest/utils": "4.0.18",
|
||||
"chai": "^6.2.1",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
@@ -1895,13 +1895,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.17.tgz",
|
||||
"integrity": "sha512-+ZtQhLA3lDh1tI2wxe3yMsGzbp7uuJSWBM1iTIKCbppWTSBN09PUC+L+fyNlQApQoR+Ps8twt2pbSSXg2fQVEQ==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz",
|
||||
"integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.0.17",
|
||||
"@vitest/spy": "4.0.18",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
@@ -1922,9 +1922,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.17.tgz",
|
||||
"integrity": "sha512-Ah3VAYmjcEdHg6+MwFE17qyLqBHZ+ni2ScKCiW2XrlSBV4H3Z7vYfPfz7CWQ33gyu76oc0Ai36+kgLU3rfF4nw==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz",
|
||||
"integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1935,13 +1935,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.17.tgz",
|
||||
"integrity": "sha512-JmuQyf8aMWoo/LmNFppdpkfRVHJcsgzkbCA+/Bk7VfNH7RE6Ut2qxegeyx2j3ojtJtKIbIGy3h+KxGfYfk28YQ==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz",
|
||||
"integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.0.17",
|
||||
"@vitest/utils": "4.0.18",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@@ -1949,13 +1949,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.17.tgz",
|
||||
"integrity": "sha512-npPelD7oyL+YQM2gbIYvlavlMVWUfNNGZPcu0aEUQXt7FXTuqhmgiYupPnAanhKvyP6Srs2pIbWo30K0RbDtRQ==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz",
|
||||
"integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.0.17",
|
||||
"@vitest/pretty-format": "4.0.18",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
@@ -1964,9 +1964,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.17.tgz",
|
||||
"integrity": "sha512-I1bQo8QaP6tZlTomQNWKJE6ym4SHf3oLS7ceNjozxxgzavRAgZDc06T7kD8gb9bXKEgcLNt00Z+kZO6KaJ62Ew==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz",
|
||||
"integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -1974,13 +1974,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.17.tgz",
|
||||
"integrity": "sha512-RG6iy+IzQpa9SB8HAFHJ9Y+pTzI+h8553MrciN9eC6TFBErqrQaTas4vG+MVj8S4uKk8uTT2p0vgZPnTdxd96w==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz",
|
||||
"integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.0.17",
|
||||
"@vitest/pretty-format": "4.0.18",
|
||||
"tinyrainbow": "^3.0.3"
|
||||
},
|
||||
"funding": {
|
||||
@@ -2294,9 +2294,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"version": "2.8.6",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz",
|
||||
"integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
@@ -2304,6 +2304,10 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
@@ -3066,9 +3070,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "17.0.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.0.0.tgz",
|
||||
"integrity": "sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==",
|
||||
"version": "17.3.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.3.0.tgz",
|
||||
"integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -3125,9 +3129,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hono": {
|
||||
"version": "4.11.4",
|
||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.4.tgz",
|
||||
"integrity": "sha512-U7tt8JsyrxSRKspfhtLET79pU8K+tInj5QZXs1jSugO1Vq5dFj3kmZsRldo29mTBfcjDRVRXrEZ6LS63Cog9ZA==",
|
||||
"version": "4.11.7",
|
||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz",
|
||||
"integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -3724,9 +3728,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.0.tgz",
|
||||
"integrity": "sha512-yEPsovQfpxYfgWNhCfECjG5AQaO+K3dp6XERmOepyPDVqcJm+bjyCVO3pmU+nAPe0N5dDvekfGezt/EIiRe1TA==",
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
|
||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -3821,9 +3825,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.55.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.1.tgz",
|
||||
"integrity": "sha512-wDv/Ht1BNHB4upNbK74s9usvl7hObDnvVzknxqY/E/O3X6rW1U1rV1aENEfJ54eFZDTNo7zv1f5N4edCluH7+A==",
|
||||
"version": "4.57.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz",
|
||||
"integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3837,31 +3841,31 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.55.1",
|
||||
"@rollup/rollup-android-arm64": "4.55.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.55.1",
|
||||
"@rollup/rollup-darwin-x64": "4.55.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.55.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.55.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.55.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.55.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.55.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.55.1",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.55.1",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.55.1",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.55.1",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.55.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.55.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.55.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.55.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.55.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.55.1",
|
||||
"@rollup/rollup-openbsd-x64": "4.55.1",
|
||||
"@rollup/rollup-openharmony-arm64": "4.55.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.55.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.55.1",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.55.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.55.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.57.1",
|
||||
"@rollup/rollup-android-arm64": "4.57.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.57.1",
|
||||
"@rollup/rollup-darwin-x64": "4.57.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.57.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.57.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.57.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.57.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.57.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.57.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.57.1",
|
||||
"@rollup/rollup-openbsd-x64": "4.57.1",
|
||||
"@rollup/rollup-openharmony-arm64": "4.57.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.57.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.57.1",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.57.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.57.1",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -4228,9 +4232,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node/node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
|
||||
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
@@ -4396,19 +4400,19 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.0.17",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.17.tgz",
|
||||
"integrity": "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==",
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz",
|
||||
"integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.0.17",
|
||||
"@vitest/mocker": "4.0.17",
|
||||
"@vitest/pretty-format": "4.0.17",
|
||||
"@vitest/runner": "4.0.17",
|
||||
"@vitest/snapshot": "4.0.17",
|
||||
"@vitest/spy": "4.0.17",
|
||||
"@vitest/utils": "4.0.17",
|
||||
"@vitest/expect": "4.0.18",
|
||||
"@vitest/mocker": "4.0.18",
|
||||
"@vitest/pretty-format": "4.0.18",
|
||||
"@vitest/runner": "4.0.18",
|
||||
"@vitest/snapshot": "4.0.18",
|
||||
"@vitest/spy": "4.0.18",
|
||||
"@vitest/utils": "4.0.18",
|
||||
"es-module-lexer": "^1.7.0",
|
||||
"expect-type": "^1.2.2",
|
||||
"magic-string": "^0.30.21",
|
||||
@@ -4436,10 +4440,10 @@
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.0.17",
|
||||
"@vitest/browser-preview": "4.0.17",
|
||||
"@vitest/browser-webdriverio": "4.0.17",
|
||||
"@vitest/ui": "4.0.17",
|
||||
"@vitest/browser-playwright": "4.0.18",
|
||||
"@vitest/browser-preview": "4.0.18",
|
||||
"@vitest/browser-webdriverio": "4.0.18",
|
||||
"@vitest/ui": "4.0.18",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*"
|
||||
},
|
||||
@@ -4545,9 +4549,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "4.3.5",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz",
|
||||
"integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==",
|
||||
"version": "4.3.6",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz",
|
||||
"integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
|
||||
23
package.json
23
package.json
@@ -3,7 +3,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"version": "0.13.1",
|
||||
"version": "0.14.0",
|
||||
"description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
|
||||
"main": "dist/lib.js",
|
||||
"types": "dist/lib.d.ts",
|
||||
@@ -20,6 +20,7 @@
|
||||
},
|
||||
"files": [
|
||||
"dist/",
|
||||
"!dist/tests/",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"package.json"
|
||||
@@ -59,23 +60,23 @@
|
||||
"author": "Zed Industries",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "0.13.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.7",
|
||||
"@modelcontextprotocol/sdk": "1.25.2",
|
||||
"@agentclientprotocol/sdk": "0.13.1",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.2.29",
|
||||
"@modelcontextprotocol/sdk": "1.25.3",
|
||||
"diff": "8.0.3",
|
||||
"minimatch": "10.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "0.71.2",
|
||||
"@types/node": "25.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "8.53.0",
|
||||
"@typescript-eslint/parser": "8.53.0",
|
||||
"@anthropic-ai/sdk": "0.72.1",
|
||||
"@types/node": "25.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.54.0",
|
||||
"@typescript-eslint/parser": "8.54.0",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"globals": "17.0.0",
|
||||
"prettier": "3.8.0",
|
||||
"globals": "17.3.0",
|
||||
"prettier": "3.8.1",
|
||||
"ts-node": "10.9.2",
|
||||
"typescript": "5.9.3",
|
||||
"vitest": "4.0.17"
|
||||
"vitest": "4.0.18"
|
||||
}
|
||||
}
|
||||
|
||||
254
src/acp-agent.ts
254
src/acp-agent.ts
@@ -9,6 +9,8 @@ import {
|
||||
ForkSessionResponse,
|
||||
InitializeRequest,
|
||||
InitializeResponse,
|
||||
ListSessionsRequest,
|
||||
ListSessionsResponse,
|
||||
ndJsonStream,
|
||||
NewSessionRequest,
|
||||
NewSessionResponse,
|
||||
@@ -19,6 +21,7 @@ import {
|
||||
RequestError,
|
||||
ResumeSessionRequest,
|
||||
ResumeSessionResponse,
|
||||
SessionInfo,
|
||||
SessionModelState,
|
||||
SessionNotification,
|
||||
SetSessionModelRequest,
|
||||
@@ -60,8 +63,44 @@ import { ContentBlockParam } from "@anthropic-ai/sdk/resources";
|
||||
import { BetaContentBlock, BetaRawContentBlockDelta } from "@anthropic-ai/sdk/resources/beta.mjs";
|
||||
import packageJson from "../package.json" with { type: "json" };
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
export const CLAUDE_CONFIG_DIR = process.env.CLAUDE ?? path.join(os.homedir(), ".claude");
|
||||
export const CLAUDE_CONFIG_DIR =
|
||||
process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
|
||||
|
||||
/**
|
||||
* Decode a Claude project path encoding back to the original filesystem path.
|
||||
* Claude encodes paths by replacing path separators with dashes:
|
||||
* - Unix: "/Users/morse/project" -> "-Users-morse-project"
|
||||
* - Windows: "C:\Users\morse\project" -> "C-Users-morse-project"
|
||||
*/
|
||||
function decodeProjectPath(encodedPath: string): string {
|
||||
// Check if this looks like a Windows path (starts with drive letter pattern like "C-")
|
||||
const windowsDriveMatch = encodedPath.match(/^([A-Za-z])-/);
|
||||
if (windowsDriveMatch) {
|
||||
// Windows path: "C-Users-morse-project" -> "C:\Users\morse\project"
|
||||
const driveLetter = windowsDriveMatch[1];
|
||||
const rest = encodedPath.slice(2); // Skip "C-"
|
||||
return `${driveLetter}:\\${rest.replace(/-/g, "\\")}`;
|
||||
}
|
||||
|
||||
// Unix path: "-Users-morse-project" -> "/Users/morse/project"
|
||||
return encodedPath.replace(/-/g, "/");
|
||||
}
|
||||
|
||||
const MAX_TITLE_LENGTH = 128;
|
||||
|
||||
function sanitizeTitle(text: string): string {
|
||||
// Replace newlines and collapse whitespace
|
||||
const sanitized = text
|
||||
.replace(/[\r\n]+/g, " ")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
if (sanitized.length <= MAX_TITLE_LENGTH) {
|
||||
return sanitized;
|
||||
}
|
||||
return sanitized.slice(0, MAX_TITLE_LENGTH - 1) + "…";
|
||||
}
|
||||
|
||||
/**
|
||||
* Logger interface for customizing logging output
|
||||
@@ -124,17 +163,18 @@ export type ToolUpdateMeta = {
|
||||
};
|
||||
};
|
||||
|
||||
type ToolUseCache = {
|
||||
export type ToolUseCache = {
|
||||
[key: string]: {
|
||||
type: "tool_use" | "server_tool_use" | "mcp_tool_use";
|
||||
id: string;
|
||||
name: string;
|
||||
input: any;
|
||||
input: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
// Bypass Permissions doesn't work if we are a root/sudo user
|
||||
const IS_ROOT = (process.geteuid?.() ?? process.getuid?.()) === 0;
|
||||
const ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;
|
||||
|
||||
// Implement the ACP Agent interface
|
||||
export class ClaudeAcpAgent implements Agent {
|
||||
@@ -165,17 +205,17 @@ export class ClaudeAcpAgent implements Agent {
|
||||
};
|
||||
|
||||
// If client supports terminal-auth capability, use that instead.
|
||||
// if (request.clientCapabilities?._meta?.["terminal-auth"] === true) {
|
||||
// const cliPath = fileURLToPath(import.meta.resolve("@anthropic-ai/claude-agent-sdk/cli.js"));
|
||||
if (request.clientCapabilities?._meta?.["terminal-auth"] === true) {
|
||||
const cliPath = fileURLToPath(import.meta.resolve("@anthropic-ai/claude-agent-sdk/cli.js"));
|
||||
|
||||
// authMethod._meta = {
|
||||
// "terminal-auth": {
|
||||
// command: "node",
|
||||
// args: [cliPath, "/login"],
|
||||
// label: "Claude Code Login",
|
||||
// },
|
||||
// };
|
||||
// }
|
||||
authMethod._meta = {
|
||||
"terminal-auth": {
|
||||
command: "node",
|
||||
args: [cliPath, "/login"],
|
||||
label: "Claude Code Login",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
protocolVersion: 1,
|
||||
@@ -190,6 +230,7 @@ export class ClaudeAcpAgent implements Agent {
|
||||
},
|
||||
sessionCapabilities: {
|
||||
fork: {},
|
||||
list: {},
|
||||
resume: {},
|
||||
},
|
||||
},
|
||||
@@ -245,6 +286,149 @@ export class ClaudeAcpAgent implements Agent {
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* List Claude Code sessions by parsing JSONL files
|
||||
* Sessions are stored in ~/.claude/projects/<path-encoded>/
|
||||
* Implements the draft session/list RFD spec
|
||||
*/
|
||||
async unstable_listSessions(params: ListSessionsRequest): Promise<ListSessionsResponse> {
|
||||
// Note: We load all sessions into memory for sorting, so pagination here is for
|
||||
// API response size limits rather than memory efficiency. This matches the RFD spec.
|
||||
const PAGE_SIZE = 50;
|
||||
const claudeDir = path.join(CLAUDE_CONFIG_DIR, "projects");
|
||||
|
||||
try {
|
||||
await fs.promises.access(claudeDir);
|
||||
} catch {
|
||||
return { sessions: [] };
|
||||
}
|
||||
|
||||
// Collect all sessions across all project directories
|
||||
const allSessions: SessionInfo[] = [];
|
||||
|
||||
try {
|
||||
const projectDirs = await fs.promises.readdir(claudeDir);
|
||||
|
||||
for (const encodedPath of projectDirs) {
|
||||
const projectDir = path.join(claudeDir, encodedPath);
|
||||
const stat = await fs.promises.stat(projectDir);
|
||||
if (!stat.isDirectory()) continue;
|
||||
|
||||
// Decode the path based on platform:
|
||||
// - Unix: "-Users-morse-project" -> "/Users/morse/project"
|
||||
// - Windows: "C-Users-morse-project" -> "C:\Users\morse\project"
|
||||
const decodedCwd = decodeProjectPath(encodedPath);
|
||||
|
||||
// Skip if filtering by cwd and this doesn't match
|
||||
if (params.cwd && decodedCwd !== params.cwd) continue;
|
||||
|
||||
const files = await fs.promises.readdir(projectDir);
|
||||
// Filter to user session files only. Skip agent-*.jsonl files which contain
|
||||
// internal agent metadata and system logs, not user-visible conversation sessions.
|
||||
const jsonlFiles = files.filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
|
||||
|
||||
for (const file of jsonlFiles) {
|
||||
const filePath = path.join(projectDir, file);
|
||||
try {
|
||||
const content = await fs.promises.readFile(filePath, "utf-8");
|
||||
const lines = content.trim().split("\n").filter(Boolean);
|
||||
|
||||
const firstLine = lines[0];
|
||||
if (!firstLine) continue;
|
||||
|
||||
// Parse first line to get session info
|
||||
const firstEntry = JSON.parse(firstLine);
|
||||
const sessionId = firstEntry.sessionId || file.replace(".jsonl", "");
|
||||
|
||||
// Find first user message for title
|
||||
let title: string | undefined;
|
||||
for (const line of lines) {
|
||||
try {
|
||||
const entry = JSON.parse(line);
|
||||
if (entry.type === "user" && entry.message?.content) {
|
||||
const msgContent = entry.message.content;
|
||||
if (typeof msgContent === "string") {
|
||||
title = sanitizeTitle(msgContent);
|
||||
break;
|
||||
}
|
||||
if (Array.isArray(msgContent) && msgContent.length > 0) {
|
||||
const first = msgContent[0];
|
||||
const text =
|
||||
typeof first === "string"
|
||||
? first
|
||||
: first && typeof first === "object" && typeof first.text === "string"
|
||||
? first.text
|
||||
: undefined;
|
||||
if (text) {
|
||||
title = sanitizeTitle(text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Skip malformed lines
|
||||
}
|
||||
}
|
||||
|
||||
// Get file modification time as updatedAt
|
||||
const fileStat = await fs.promises.stat(filePath);
|
||||
const updatedAt = fileStat.mtime.toISOString();
|
||||
|
||||
allSessions.push({
|
||||
sessionId,
|
||||
cwd: decodedCwd,
|
||||
title: title ?? null,
|
||||
updatedAt,
|
||||
});
|
||||
} catch (err) {
|
||||
this.logger.error(
|
||||
`[unstable_listSessions] Failed to parse session file: ${filePath}`,
|
||||
err,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
this.logger.error("[unstable_listSessions] Failed to list sessions", err);
|
||||
return { sessions: [] };
|
||||
}
|
||||
|
||||
// Sort by updatedAt descending (most recent first)
|
||||
allSessions.sort((a, b) => {
|
||||
const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
|
||||
const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
||||
return timeB - timeA;
|
||||
});
|
||||
|
||||
// Handle pagination with cursor
|
||||
let startIndex = 0;
|
||||
if (params.cursor) {
|
||||
try {
|
||||
const decoded = Buffer.from(params.cursor, "base64").toString("utf-8");
|
||||
const cursorData = JSON.parse(decoded);
|
||||
startIndex = cursorData.offset ?? 0;
|
||||
} catch {
|
||||
// Invalid cursor, start from beginning
|
||||
}
|
||||
}
|
||||
|
||||
const pageOfSessions = allSessions.slice(startIndex, startIndex + PAGE_SIZE);
|
||||
const hasMore = startIndex + PAGE_SIZE < allSessions.length;
|
||||
|
||||
const response: ListSessionsResponse = {
|
||||
sessions: pageOfSessions,
|
||||
};
|
||||
|
||||
if (hasMore) {
|
||||
const nextCursor = Buffer.from(JSON.stringify({ offset: startIndex + PAGE_SIZE })).toString(
|
||||
"base64",
|
||||
);
|
||||
response.nextCursor = nextCursor;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
async authenticate(_params: AuthenticateRequest): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
@@ -274,8 +458,12 @@ export class ClaudeAcpAgent implements Agent {
|
||||
case "init":
|
||||
break;
|
||||
case "compact_boundary":
|
||||
case "hook_started":
|
||||
case "task_notification":
|
||||
case "hook_progress":
|
||||
case "hook_response":
|
||||
case "status":
|
||||
case "files_persisted":
|
||||
// Todo: process via status api: https://docs.claude.com/en/docs/claude-code/hooks#hook-output
|
||||
break;
|
||||
default:
|
||||
@@ -346,6 +534,21 @@ export class ClaudeAcpAgent implements Agent {
|
||||
typeof message.message.content === "string" &&
|
||||
message.message.content.includes("<local-command-stdout>")
|
||||
) {
|
||||
// Handle /context by sending its reply as regular agent message.
|
||||
if (message.message.content.includes("Context Usage")) {
|
||||
for (const notification of toAcpNotifications(
|
||||
message.message.content
|
||||
.replace("<local-command-stdout>", "")
|
||||
.replace("</local-command-stdout>", ""),
|
||||
"assistant",
|
||||
params.sessionId,
|
||||
this.toolUseCache,
|
||||
this.client,
|
||||
this.logger,
|
||||
)) {
|
||||
await this.client.sessionUpdate(notification);
|
||||
}
|
||||
}
|
||||
this.logger.log(message.message.content);
|
||||
break;
|
||||
}
|
||||
@@ -398,6 +601,7 @@ export class ClaudeAcpAgent implements Agent {
|
||||
break;
|
||||
}
|
||||
case "tool_progress":
|
||||
case "tool_use_summary":
|
||||
break;
|
||||
case "auth_status":
|
||||
break;
|
||||
@@ -688,7 +892,7 @@ export class ClaudeAcpAgent implements Agent {
|
||||
extraArgs,
|
||||
// If we want bypassPermissions to be an option, we have to allow it here.
|
||||
// But it doesn't work in root mode, so we only activate it if it will work.
|
||||
allowDangerouslySkipPermissions: !IS_ROOT,
|
||||
allowDangerouslySkipPermissions: ALLOW_BYPASS,
|
||||
permissionMode,
|
||||
canUseTool: this.canUseTool(sessionId),
|
||||
// note: although not documented by the types, passing an absolute path
|
||||
@@ -709,7 +913,23 @@ export class ClaudeAcpAgent implements Agent {
|
||||
PostToolUse: [
|
||||
...(userProvidedOptions?.hooks?.PostToolUse || []),
|
||||
{
|
||||
hooks: [createPostToolUseHook(this.logger)],
|
||||
hooks: [
|
||||
createPostToolUseHook(this.logger, {
|
||||
onEnterPlanMode: async () => {
|
||||
const session = this.sessions[sessionId];
|
||||
if (session) {
|
||||
session.permissionMode = "plan";
|
||||
}
|
||||
await this.client.sessionUpdate({
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "current_mode_update",
|
||||
currentModeId: "plan",
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -827,7 +1047,7 @@ export class ClaudeAcpAgent implements Agent {
|
||||
},
|
||||
];
|
||||
// Only works in non-root mode
|
||||
if (!IS_ROOT) {
|
||||
if (ALLOW_BYPASS) {
|
||||
availableModes.push({
|
||||
id: "bypassPermissions",
|
||||
name: "Bypass Permissions",
|
||||
@@ -867,7 +1087,6 @@ async function getAvailableModels(query: Query): Promise<SessionModelState> {
|
||||
|
||||
async function getAvailableSlashCommands(query: Query): Promise<AvailableCommand[]> {
|
||||
const UNSUPPORTED_COMMANDS = [
|
||||
"context",
|
||||
"cost",
|
||||
"login",
|
||||
"logout",
|
||||
@@ -1146,6 +1365,7 @@ export function toAcpNotifications(
|
||||
toolCallId: chunk.tool_use_id,
|
||||
sessionUpdate: "tool_call_update",
|
||||
status: "is_error" in chunk && chunk.is_error ? "failed" : "completed",
|
||||
rawOutput: chunk.content,
|
||||
...toolUpdateFromToolResult(chunk, toolUseCache[chunk.tool_use_id]),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
FileEditInput,
|
||||
FileReadInput,
|
||||
FileWriteInput,
|
||||
KillShellInput,
|
||||
TaskOutputInput,
|
||||
} from "@anthropic-ai/claude-agent-sdk/sdk-tools.js";
|
||||
import { z } from "zod";
|
||||
import { CLAUDE_CONFIG_DIR, ClaudeAcpAgent } from "./acp-agent.js";
|
||||
@@ -269,7 +269,12 @@ Usage:
|
||||
await writeTextFile(input);
|
||||
|
||||
return {
|
||||
content: [],
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `The file ${input.file_path} has been updated successfully.`,
|
||||
},
|
||||
],
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
@@ -552,19 +557,66 @@ Output: Create directory 'foo'`),
|
||||
|
||||
In sessions with ${acpToolNames.bashOutput} always use it for output from Bash commands instead of TaskOutput.`,
|
||||
inputSchema: {
|
||||
bash_id: z
|
||||
task_id: z
|
||||
.string()
|
||||
.describe(
|
||||
`The id of the background bash command as returned by \`${acpToolNames.bash}\``,
|
||||
),
|
||||
block: z.boolean().describe("Whether to wait for completion"),
|
||||
timeout: z.number().describe("Max wait time in ms"),
|
||||
},
|
||||
},
|
||||
async (input) => {
|
||||
async (input: TaskOutputInput) => {
|
||||
try {
|
||||
const bgTerm = agent.backgroundTerminals[input.bash_id];
|
||||
const bgTerm = agent.backgroundTerminals[input.task_id];
|
||||
|
||||
if (!bgTerm) {
|
||||
throw new Error(`Unknown shell ${input.bash_id}`);
|
||||
throw new Error(`Unknown shell ${input.task_id}`);
|
||||
}
|
||||
|
||||
if (input.block && bgTerm.status === "started") {
|
||||
const statusPromise = Promise.race([
|
||||
bgTerm.handle
|
||||
.waitForExit()
|
||||
.then((exitStatus) => ({ status: "exited" as const, exitStatus })),
|
||||
sleep(input.timeout ?? 2 * 60 * 1000).then(async () => {
|
||||
if (bgTerm.status === "started") {
|
||||
await bgTerm.handle.kill();
|
||||
}
|
||||
return { status: "timedOut" as const, exitStatus: null };
|
||||
}),
|
||||
]);
|
||||
|
||||
const { status, exitStatus } = await statusPromise;
|
||||
const currentOutput = await bgTerm.handle.currentOutput();
|
||||
const strippedOutput = stripCommonPrefix(
|
||||
bgTerm.lastOutput?.output ?? "",
|
||||
currentOutput.output,
|
||||
);
|
||||
|
||||
agent.backgroundTerminals[input.task_id] = {
|
||||
status,
|
||||
pendingOutput: {
|
||||
...currentOutput,
|
||||
output: strippedOutput,
|
||||
exitStatus: exitStatus ?? currentOutput.exitStatus,
|
||||
},
|
||||
};
|
||||
|
||||
await bgTerm.handle.release();
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: toolCommandOutput(status, {
|
||||
...currentOutput,
|
||||
output: strippedOutput,
|
||||
exitStatus: exitStatus ?? currentOutput.exitStatus,
|
||||
}),
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
if (bgTerm.status === "started") {
|
||||
@@ -628,7 +680,7 @@ In sessions with ${acpToolNames.killShell} always use it instead of KillShell.`,
|
||||
),
|
||||
},
|
||||
},
|
||||
async (input: KillShellInput) => {
|
||||
async (input) => {
|
||||
try {
|
||||
const bgTerm = agent.backgroundTerminals[input.shell_id];
|
||||
|
||||
|
||||
@@ -128,7 +128,8 @@ function normalizePath(filePath: string, cwd: string): string {
|
||||
} else if (!path.isAbsolute(filePath)) {
|
||||
filePath = path.join(cwd, filePath);
|
||||
}
|
||||
return path.normalize(filePath);
|
||||
// Convert backslashes to forward slashes for minimatch compatibility on Windows
|
||||
return path.normalize(filePath).replace(/\\/g, "/");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
description: Say hello
|
||||
argument-hint: [name]
|
||||
argument-hint: name
|
||||
---
|
||||
|
||||
Respond with "Hello $1" and nothing else.
|
||||
|
||||
@@ -21,6 +21,13 @@ import { markdownEscape, toolInfoFromToolUse, toolUpdateFromToolResult } from ".
|
||||
import { toAcpNotifications, promptToClaude } from "../acp-agent.js";
|
||||
import { query, SDKAssistantMessage } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { randomUUID } from "crypto";
|
||||
import type {
|
||||
BetaToolResultBlockParam,
|
||||
BetaToolSearchToolResultBlockParam,
|
||||
BetaWebSearchToolResultBlockParam,
|
||||
BetaWebFetchToolResultBlockParam,
|
||||
BetaCodeExecutionToolResultBlockParam,
|
||||
} from "@anthropic-ai/sdk/resources/beta.mjs";
|
||||
|
||||
describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("ACP subprocess integration", () => {
|
||||
let child: ReturnType<typeof spawn>;
|
||||
@@ -734,6 +741,200 @@ describe("tool conversions", () => {
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should transform tool_reference content to valid ACP content", () => {
|
||||
const toolUse = {
|
||||
type: "tool_use",
|
||||
id: "toolu_01MNO345",
|
||||
name: "ToolSearch",
|
||||
input: { query: "test" },
|
||||
};
|
||||
|
||||
const toolResult: BetaToolResultBlockParam = {
|
||||
content: [
|
||||
{
|
||||
type: "tool_reference",
|
||||
tool_name: "some_discovered_tool",
|
||||
},
|
||||
],
|
||||
tool_use_id: "toolu_01MNO345",
|
||||
is_error: false,
|
||||
type: "tool_result",
|
||||
};
|
||||
|
||||
const update = toolUpdateFromToolResult(toolResult, toolUse);
|
||||
|
||||
expect(update).toEqual({
|
||||
content: [
|
||||
{
|
||||
type: "content",
|
||||
content: { type: "text", text: "Tool: some_discovered_tool" },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should transform web_search_result content to valid ACP content", () => {
|
||||
const toolUse = {
|
||||
type: "tool_use",
|
||||
id: "toolu_01MNO345",
|
||||
name: "WebSearch",
|
||||
input: { query: "test" },
|
||||
};
|
||||
|
||||
const toolResult: BetaWebSearchToolResultBlockParam = {
|
||||
content: [
|
||||
{
|
||||
type: "web_search_result",
|
||||
title: "Test Result",
|
||||
url: "https://example.com",
|
||||
encrypted_content: "...",
|
||||
page_age: null,
|
||||
},
|
||||
],
|
||||
tool_use_id: "toolu_01MNO345",
|
||||
type: "web_search_tool_result",
|
||||
};
|
||||
|
||||
const update = toolUpdateFromToolResult(toolResult, toolUse);
|
||||
|
||||
expect(update).toEqual({
|
||||
content: [
|
||||
{
|
||||
type: "content",
|
||||
content: { type: "text", text: "Test Result (https://example.com)" },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should transform web_search_tool_result_error to valid ACP content", () => {
|
||||
const toolUse = {
|
||||
type: "tool_use",
|
||||
id: "toolu_01MNO345",
|
||||
name: "WebSearch",
|
||||
input: { query: "test" },
|
||||
};
|
||||
|
||||
const toolResult: BetaWebSearchToolResultBlockParam = {
|
||||
content: {
|
||||
type: "web_search_tool_result_error",
|
||||
error_code: "unavailable",
|
||||
},
|
||||
tool_use_id: "toolu_01MNO345",
|
||||
type: "web_search_tool_result",
|
||||
};
|
||||
|
||||
const update = toolUpdateFromToolResult(toolResult, toolUse);
|
||||
|
||||
expect(update).toEqual({
|
||||
content: [
|
||||
{
|
||||
type: "content",
|
||||
content: { type: "text", text: "Error: unavailable" },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should transform code_execution_result content to valid ACP content", () => {
|
||||
const toolUse = {
|
||||
type: "tool_use",
|
||||
id: "toolu_01MNO345",
|
||||
name: "CodeExecution",
|
||||
input: {},
|
||||
};
|
||||
|
||||
const toolResult: BetaCodeExecutionToolResultBlockParam = {
|
||||
content: {
|
||||
type: "code_execution_result",
|
||||
stdout: "Hello World",
|
||||
stderr: "",
|
||||
return_code: 0,
|
||||
content: [],
|
||||
},
|
||||
tool_use_id: "toolu_01MNO345",
|
||||
type: "code_execution_tool_result",
|
||||
};
|
||||
|
||||
const update = toolUpdateFromToolResult(toolResult, toolUse);
|
||||
|
||||
expect(update).toEqual({
|
||||
content: [
|
||||
{
|
||||
type: "content",
|
||||
content: { type: "text", text: "Output: Hello World" },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should transform web_fetch_result content to valid ACP content", () => {
|
||||
const toolUse = {
|
||||
type: "tool_use",
|
||||
id: "toolu_01MNO345",
|
||||
name: "WebFetch",
|
||||
input: { url: "https://example.com" },
|
||||
};
|
||||
|
||||
const toolResult: BetaWebFetchToolResultBlockParam = {
|
||||
content: {
|
||||
type: "web_fetch_result",
|
||||
url: "https://example.com",
|
||||
content: {
|
||||
type: "document",
|
||||
citations: null,
|
||||
title: null,
|
||||
source: { type: "text", media_type: "text/plain", data: "Page content here" },
|
||||
},
|
||||
},
|
||||
tool_use_id: "toolu_01MNO345",
|
||||
type: "web_fetch_tool_result",
|
||||
};
|
||||
|
||||
const update = toolUpdateFromToolResult(toolResult, toolUse);
|
||||
|
||||
expect(update).toEqual({
|
||||
content: [
|
||||
{
|
||||
type: "content",
|
||||
content: { type: "text", text: "Fetched: https://example.com" },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("should transform tool_search_tool_search_result to valid ACP content", () => {
|
||||
const toolUse = {
|
||||
type: "tool_use",
|
||||
id: "toolu_01MNO345",
|
||||
name: "ToolSearch",
|
||||
input: { query: "test" },
|
||||
};
|
||||
|
||||
const toolResult: BetaToolSearchToolResultBlockParam = {
|
||||
content: {
|
||||
type: "tool_search_tool_search_result",
|
||||
tool_references: [
|
||||
{ type: "tool_reference", tool_name: "tool_a" },
|
||||
{ type: "tool_reference", tool_name: "tool_b" },
|
||||
],
|
||||
},
|
||||
tool_use_id: "toolu_01MNO345",
|
||||
type: "tool_search_tool_result",
|
||||
};
|
||||
|
||||
const update = toolUpdateFromToolResult(toolResult, toolUse);
|
||||
|
||||
expect(update).toEqual({
|
||||
content: [
|
||||
{
|
||||
type: "content",
|
||||
content: { type: "text", text: "Tools found: tool_a, tool_b" },
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("escape markdown", () => {
|
||||
|
||||
386
src/tests/list-sessions.test.ts
Normal file
386
src/tests/list-sessions.test.ts
Normal file
@@ -0,0 +1,386 @@
|
||||
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import * as os from "node:os";
|
||||
import { AgentSideConnection } from "@agentclientprotocol/sdk";
|
||||
import type { ClaudeAcpAgent as ClaudeAcpAgentType } from "../acp-agent.js";
|
||||
|
||||
describe("unstable_listSessions", () => {
|
||||
let tempDir: string;
|
||||
let originalClaudeConfigDir: string | undefined;
|
||||
let agent: ClaudeAcpAgentType;
|
||||
let ClaudeAcpAgent: typeof ClaudeAcpAgentType;
|
||||
|
||||
// Helper to create a mock AgentSideConnection
|
||||
function createMockClient(): AgentSideConnection {
|
||||
return {
|
||||
sessionUpdate: async () => {},
|
||||
requestPermission: async () => ({ outcome: { outcome: "cancelled" } }),
|
||||
readTextFile: async () => ({ content: "" }),
|
||||
writeTextFile: async () => ({}),
|
||||
} as unknown as AgentSideConnection;
|
||||
}
|
||||
|
||||
// Helper to encode a path like Claude does:
|
||||
// - Unix: "/Users/test" -> "-Users-test"
|
||||
// - Windows: "C:\Users\test" -> "C-Users-test"
|
||||
function encodePath(cwd: string): string {
|
||||
// Handle Windows paths
|
||||
if (/^[A-Za-z]:\\/.test(cwd)) {
|
||||
return cwd.replace(/\\/g, "-").replace(":", "");
|
||||
}
|
||||
// Unix paths
|
||||
return cwd.replace(/\//g, "-");
|
||||
}
|
||||
|
||||
// Helper to write a session file
|
||||
function writeSessionFile(
|
||||
cwd: string,
|
||||
sessionId: string,
|
||||
options: {
|
||||
userMessage?: string;
|
||||
userMessageArray?: boolean;
|
||||
mtime?: Date;
|
||||
malformed?: boolean;
|
||||
isAgentFile?: boolean;
|
||||
} = {},
|
||||
): void {
|
||||
const encodedPath = encodePath(cwd);
|
||||
const projectDir = path.join(tempDir, "projects", encodedPath);
|
||||
fs.mkdirSync(projectDir, { recursive: true });
|
||||
|
||||
const filename = options.isAgentFile ? `agent-${sessionId}.jsonl` : `${sessionId}.jsonl`;
|
||||
const filePath = path.join(projectDir, filename);
|
||||
|
||||
if (options.malformed) {
|
||||
fs.writeFileSync(filePath, "not valid json\n{also bad");
|
||||
return;
|
||||
}
|
||||
|
||||
const lines: string[] = [];
|
||||
|
||||
// First line with sessionId
|
||||
lines.push(JSON.stringify({ sessionId, type: "init" }));
|
||||
|
||||
// User message if provided
|
||||
if (options.userMessage) {
|
||||
const content = options.userMessageArray
|
||||
? [{ type: "text", text: options.userMessage }]
|
||||
: options.userMessage;
|
||||
lines.push(JSON.stringify({ type: "user", message: { content } }));
|
||||
}
|
||||
|
||||
// Assistant response
|
||||
lines.push(JSON.stringify({ type: "assistant", message: { content: "Hello!" } }));
|
||||
|
||||
fs.writeFileSync(filePath, lines.join("\n"));
|
||||
|
||||
// Set modification time if specified
|
||||
if (options.mtime) {
|
||||
fs.utimesSync(filePath, options.mtime, options.mtime);
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(async () => {
|
||||
// Create temp directory to isolate tests from real filesystem.
|
||||
// We set process.env.CLAUDE_CONFIG_DIR before importing the module so that
|
||||
// CLAUDE_CONFIG_DIR is evaluated with our temp directory.
|
||||
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "claude-test-"));
|
||||
originalClaudeConfigDir = process.env.CLAUDE_CONFIG_DIR;
|
||||
process.env.CLAUDE_CONFIG_DIR = tempDir;
|
||||
|
||||
// Reset modules to pick up the new CLAUDE_CONFIG_DIR env var
|
||||
vi.resetModules();
|
||||
|
||||
// Dynamic import after setting env var
|
||||
const acpAgent = await import("../acp-agent.js");
|
||||
ClaudeAcpAgent = acpAgent.ClaudeAcpAgent;
|
||||
|
||||
// Create agent instance
|
||||
agent = new ClaudeAcpAgent(createMockClient());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Restore env and cleanup
|
||||
if (originalClaudeConfigDir !== undefined) {
|
||||
process.env.CLAUDE_CONFIG_DIR = originalClaudeConfigDir;
|
||||
} else {
|
||||
delete process.env.CLAUDE_CONFIG_DIR;
|
||||
}
|
||||
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("returns empty array when projects directory does not exist", async () => {
|
||||
const result = await agent.unstable_listSessions({});
|
||||
expect(result.sessions).toEqual([]);
|
||||
expect(result.nextCursor).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns empty array when projects directory is empty", async () => {
|
||||
fs.mkdirSync(path.join(tempDir, "projects"), { recursive: true });
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
expect(result.sessions).toEqual([]);
|
||||
});
|
||||
|
||||
it("parses session files and returns correct metadata", async () => {
|
||||
const cwd = "/Users/test/myproject";
|
||||
const sessionId = "sess-123";
|
||||
const mtime = new Date("2025-01-15T10:30:00Z");
|
||||
|
||||
writeSessionFile(cwd, sessionId, {
|
||||
userMessage: "Hello, can you help me?",
|
||||
mtime,
|
||||
});
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
expect(result.sessions[0]).toMatchObject({
|
||||
sessionId: "sess-123",
|
||||
cwd: "/Users/test/myproject",
|
||||
title: "Hello, can you help me?",
|
||||
});
|
||||
expect(result.sessions[0]!.updatedAt).toBeDefined();
|
||||
});
|
||||
|
||||
it("extracts title from array-style user message content", async () => {
|
||||
writeSessionFile("/Users/test/project", "sess-456", {
|
||||
userMessage: "Fix the bug in auth",
|
||||
userMessageArray: true,
|
||||
});
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions[0]!.title).toBe("Fix the bug in auth");
|
||||
});
|
||||
|
||||
it("truncates long titles to 128 characters with ellipsis", async () => {
|
||||
const longMessage = "A".repeat(150);
|
||||
writeSessionFile("/Users/test/project", "sess-789", {
|
||||
userMessage: longMessage,
|
||||
});
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions[0]!.title).toBe("A".repeat(127) + "…");
|
||||
});
|
||||
|
||||
it("replaces newlines with spaces in titles", async () => {
|
||||
const messageWithNewlines = "First line\nSecond line\r\nThird line";
|
||||
writeSessionFile("/Users/test/project", "sess-newlines", {
|
||||
userMessage: messageWithNewlines,
|
||||
});
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions[0]!.title).toBe("First line Second line Third line");
|
||||
});
|
||||
|
||||
it("collapses multiple whitespace characters in titles", async () => {
|
||||
const messageWithWhitespace = "Hello world \n\n test";
|
||||
writeSessionFile("/Users/test/project", "sess-whitespace", {
|
||||
userMessage: messageWithWhitespace,
|
||||
});
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions[0]!.title).toBe("Hello world test");
|
||||
});
|
||||
|
||||
it("filters sessions by cwd parameter", async () => {
|
||||
writeSessionFile("/Users/test/projectone", "sess-a", { userMessage: "Project A" });
|
||||
writeSessionFile("/Users/test/projecttwo", "sess-b", { userMessage: "Project B" });
|
||||
|
||||
const result = await agent.unstable_listSessions({ cwd: "/Users/test/projectone" });
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
expect(result.sessions[0]!.sessionId).toBe("sess-a");
|
||||
});
|
||||
|
||||
it("returns all sessions when cwd is not specified", async () => {
|
||||
writeSessionFile("/Users/test/projectone", "sess-a", { userMessage: "A" });
|
||||
writeSessionFile("/Users/test/projecttwo", "sess-b", { userMessage: "B" });
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("sorts sessions by updatedAt descending (most recent first)", async () => {
|
||||
writeSessionFile("/Users/test/project", "old-session", {
|
||||
userMessage: "Old",
|
||||
mtime: new Date("2025-01-01T00:00:00Z"),
|
||||
});
|
||||
writeSessionFile("/Users/test/project", "new-session", {
|
||||
userMessage: "New",
|
||||
mtime: new Date("2025-01-15T00:00:00Z"),
|
||||
});
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions[0]!.sessionId).toBe("new-session");
|
||||
expect(result.sessions[1]!.sessionId).toBe("old-session");
|
||||
});
|
||||
|
||||
it("skips files starting with agent-", async () => {
|
||||
writeSessionFile("/Users/test/project", "regular-session", { userMessage: "Regular" });
|
||||
writeSessionFile("/Users/test/project", "hidden-session", {
|
||||
userMessage: "Hidden",
|
||||
isAgentFile: true,
|
||||
});
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
expect(result.sessions[0]!.sessionId).toBe("regular-session");
|
||||
});
|
||||
|
||||
it("skips malformed session files gracefully", async () => {
|
||||
writeSessionFile("/Users/test/project", "good-session", { userMessage: "Good" });
|
||||
writeSessionFile("/Users/test/project", "bad-session", { malformed: true });
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
expect(result.sessions[0]!.sessionId).toBe("good-session");
|
||||
});
|
||||
|
||||
it("uses filename as sessionId when not in file content", async () => {
|
||||
const cwd = "/Users/test/project";
|
||||
const encodedPath = encodePath(cwd);
|
||||
const projectDir = path.join(tempDir, "projects", encodedPath);
|
||||
fs.mkdirSync(projectDir, { recursive: true });
|
||||
|
||||
// Write file without sessionId in content
|
||||
const filePath = path.join(projectDir, "fallback-id.jsonl");
|
||||
fs.writeFileSync(filePath, JSON.stringify({ type: "init" }) + "\n");
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions[0]!.sessionId).toBe("fallback-id");
|
||||
});
|
||||
|
||||
it("returns null title when no user message exists", async () => {
|
||||
const cwd = "/Users/test/project";
|
||||
const encodedPath = encodePath(cwd);
|
||||
const projectDir = path.join(tempDir, "projects", encodedPath);
|
||||
fs.mkdirSync(projectDir, { recursive: true });
|
||||
|
||||
// Write file with only init and assistant message
|
||||
const filePath = path.join(projectDir, "no-user.jsonl");
|
||||
fs.writeFileSync(
|
||||
filePath,
|
||||
[
|
||||
JSON.stringify({ sessionId: "no-user", type: "init" }),
|
||||
JSON.stringify({ type: "assistant", message: { content: "Hi" } }),
|
||||
].join("\n"),
|
||||
);
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions[0]!.title).toBeNull();
|
||||
});
|
||||
|
||||
describe("pagination", () => {
|
||||
it("returns nextCursor when there are more results", async () => {
|
||||
// Create 60 sessions (more than PAGE_SIZE of 50)
|
||||
for (let i = 0; i < 60; i++) {
|
||||
writeSessionFile("/Users/test/project", `sess-${i.toString().padStart(3, "0")}`, {
|
||||
userMessage: `Session ${i}`,
|
||||
mtime: new Date(Date.now() - i * 1000), // Each older by 1 second
|
||||
});
|
||||
}
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(50);
|
||||
expect(result.nextCursor).toBeDefined();
|
||||
});
|
||||
|
||||
it("does not return nextCursor when all results fit in one page", async () => {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
writeSessionFile("/Users/test/project", `sess-${i}`, { userMessage: `Session ${i}` });
|
||||
}
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(10);
|
||||
expect(result.nextCursor).toBeUndefined();
|
||||
});
|
||||
|
||||
it("returns next page when cursor is provided", async () => {
|
||||
// Create 60 sessions
|
||||
for (let i = 0; i < 60; i++) {
|
||||
writeSessionFile("/Users/test/project", `sess-${i.toString().padStart(3, "0")}`, {
|
||||
userMessage: `Session ${i}`,
|
||||
mtime: new Date(Date.now() - i * 1000),
|
||||
});
|
||||
}
|
||||
|
||||
// Get first page
|
||||
const firstPage = await agent.unstable_listSessions({});
|
||||
expect(firstPage.sessions).toHaveLength(50);
|
||||
expect(firstPage.nextCursor).toBeDefined();
|
||||
|
||||
// Get second page
|
||||
const secondPage = await agent.unstable_listSessions({ cursor: firstPage.nextCursor });
|
||||
expect(secondPage.sessions).toHaveLength(10);
|
||||
expect(secondPage.nextCursor).toBeUndefined();
|
||||
});
|
||||
|
||||
it("handles invalid cursor gracefully (starts from beginning)", async () => {
|
||||
writeSessionFile("/Users/test/project", "sess-1", { userMessage: "Test" });
|
||||
|
||||
const result = await agent.unstable_listSessions({ cursor: "invalid-base64!" });
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("handles malformed cursor JSON gracefully", async () => {
|
||||
writeSessionFile("/Users/test/project", "sess-1", { userMessage: "Test" });
|
||||
|
||||
// Valid base64 but not valid JSON
|
||||
const badCursor = Buffer.from("not json").toString("base64");
|
||||
const result = await agent.unstable_listSessions({ cursor: badCursor });
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Windows path support", () => {
|
||||
it("decodes Windows-style paths correctly", async () => {
|
||||
// Simulate a Windows path encoded as "C-Users-test-project"
|
||||
const windowsCwd = "C:\\Users\\test\\project";
|
||||
writeSessionFile(windowsCwd, "win-session", { userMessage: "Windows test" });
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
expect(result.sessions[0]!.cwd).toBe("C:\\Users\\test\\project");
|
||||
expect(result.sessions[0]!.sessionId).toBe("win-session");
|
||||
});
|
||||
|
||||
it("filters Windows paths by cwd correctly", async () => {
|
||||
writeSessionFile("C:\\Users\\test\\projectone", "win-a", { userMessage: "A" });
|
||||
writeSessionFile("C:\\Users\\test\\projecttwo", "win-b", { userMessage: "B" });
|
||||
|
||||
const result = await agent.unstable_listSessions({ cwd: "C:\\Users\\test\\projectone" });
|
||||
|
||||
expect(result.sessions).toHaveLength(1);
|
||||
expect(result.sessions[0]!.sessionId).toBe("win-a");
|
||||
});
|
||||
|
||||
it("handles mixed Unix and Windows paths", async () => {
|
||||
writeSessionFile("/Users/test/unixproject", "unix-session", { userMessage: "Unix" });
|
||||
writeSessionFile("C:\\Users\\test\\winproject", "win-session", { userMessage: "Windows" });
|
||||
|
||||
const result = await agent.unstable_listSessions({});
|
||||
|
||||
expect(result.sessions).toHaveLength(2);
|
||||
const cwds = result.sessions.map((s) => s.cwd);
|
||||
expect(cwds).toContain("/Users/test/unixproject");
|
||||
expect(cwds).toContain("C:\\Users\\test\\winproject");
|
||||
});
|
||||
});
|
||||
});
|
||||
318
src/tests/tools.test.ts
Normal file
318
src/tests/tools.test.ts
Normal file
@@ -0,0 +1,318 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { AgentSideConnection } from "@agentclientprotocol/sdk";
|
||||
import { ToolResultBlockParam } from "@anthropic-ai/sdk/resources";
|
||||
import {
|
||||
BetaMCPToolResultBlock,
|
||||
BetaTextBlock,
|
||||
BetaWebSearchResultBlock,
|
||||
BetaWebSearchToolResultBlock,
|
||||
BetaBashCodeExecutionToolResultBlock,
|
||||
BetaBashCodeExecutionResultBlock,
|
||||
} from "@anthropic-ai/sdk/resources/beta.mjs";
|
||||
import { toAcpNotifications, ToolUseCache, Logger } from "../acp-agent.js";
|
||||
|
||||
describe("rawOutput in tool call updates", () => {
|
||||
const mockClient = {} as AgentSideConnection;
|
||||
const mockLogger: Logger = { log: () => {}, error: () => {} };
|
||||
|
||||
it("should include rawOutput with string content for tool_result", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_123: {
|
||||
type: "tool_use",
|
||||
id: "toolu_123",
|
||||
name: "Bash",
|
||||
input: { command: "echo hello" },
|
||||
},
|
||||
};
|
||||
|
||||
const toolResult: ToolResultBlockParam = {
|
||||
type: "tool_result",
|
||||
tool_use_id: "toolu_123",
|
||||
content: "hello\n",
|
||||
is_error: false,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
expect(notifications).toHaveLength(1);
|
||||
expect(notifications[0].update).toMatchObject({
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: "toolu_123",
|
||||
status: "completed",
|
||||
rawOutput: "hello\n",
|
||||
});
|
||||
});
|
||||
|
||||
it("should include rawOutput with array content for tool_result", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_456: {
|
||||
type: "tool_use",
|
||||
id: "toolu_456",
|
||||
name: "Read",
|
||||
input: { file_path: "/test/file.txt" },
|
||||
},
|
||||
};
|
||||
|
||||
// ToolResultBlockParam content can be string or array of TextBlockParam
|
||||
const toolResult: ToolResultBlockParam = {
|
||||
type: "tool_result",
|
||||
tool_use_id: "toolu_456",
|
||||
content: [{ type: "text", text: "Line 1\nLine 2\nLine 3" }],
|
||||
is_error: false,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
expect(notifications).toHaveLength(1);
|
||||
expect(notifications[0].update).toMatchObject({
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: "toolu_456",
|
||||
status: "completed",
|
||||
rawOutput: [{ type: "text", text: "Line 1\nLine 2\nLine 3" }],
|
||||
});
|
||||
});
|
||||
|
||||
it("should include rawOutput for mcp_tool_result with string content", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_789: {
|
||||
type: "tool_use",
|
||||
id: "toolu_789",
|
||||
name: "mcp__server__tool",
|
||||
input: { query: "test" },
|
||||
},
|
||||
};
|
||||
|
||||
// BetaMCPToolResultBlock content can be string or Array<BetaTextBlock>
|
||||
const toolResult: BetaMCPToolResultBlock = {
|
||||
type: "mcp_tool_result",
|
||||
tool_use_id: "toolu_789",
|
||||
content: '{"result": "success", "data": [1, 2, 3]}',
|
||||
is_error: false,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
expect(notifications).toHaveLength(1);
|
||||
expect(notifications[0].update).toMatchObject({
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: "toolu_789",
|
||||
status: "completed",
|
||||
rawOutput: '{"result": "success", "data": [1, 2, 3]}',
|
||||
});
|
||||
});
|
||||
|
||||
it("should include rawOutput for mcp_tool_result with array content", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_abc: {
|
||||
type: "tool_use",
|
||||
id: "toolu_abc",
|
||||
name: "mcp__server__search",
|
||||
input: { term: "test" },
|
||||
},
|
||||
};
|
||||
|
||||
// BetaTextBlock requires citations field
|
||||
const arrayContent: BetaTextBlock[] = [
|
||||
{ type: "text", text: "Result 1", citations: null },
|
||||
{ type: "text", text: "Result 2", citations: null },
|
||||
];
|
||||
|
||||
const toolResult: BetaMCPToolResultBlock = {
|
||||
type: "mcp_tool_result",
|
||||
tool_use_id: "toolu_abc",
|
||||
content: arrayContent,
|
||||
is_error: false,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
expect(notifications).toHaveLength(1);
|
||||
expect(notifications[0].update).toMatchObject({
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: "toolu_abc",
|
||||
status: "completed",
|
||||
rawOutput: arrayContent,
|
||||
});
|
||||
});
|
||||
|
||||
it("should include rawOutput for web_search_tool_result", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_web: {
|
||||
type: "tool_use",
|
||||
id: "toolu_web",
|
||||
name: "WebSearch",
|
||||
input: { query: "test search" },
|
||||
},
|
||||
};
|
||||
|
||||
// BetaWebSearchResultBlock from SDK
|
||||
const searchResults: BetaWebSearchResultBlock[] = [
|
||||
{
|
||||
type: "web_search_result",
|
||||
url: "https://example.com",
|
||||
title: "Example",
|
||||
encrypted_content: "encrypted content here",
|
||||
page_age: "2 days ago",
|
||||
},
|
||||
];
|
||||
|
||||
const toolResult: BetaWebSearchToolResultBlock = {
|
||||
type: "web_search_tool_result",
|
||||
tool_use_id: "toolu_web",
|
||||
content: searchResults,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
expect(notifications).toHaveLength(1);
|
||||
expect(notifications[0].update).toMatchObject({
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: "toolu_web",
|
||||
status: "completed",
|
||||
rawOutput: searchResults,
|
||||
});
|
||||
});
|
||||
|
||||
it("should include rawOutput for bash_code_execution_tool_result", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_bash: {
|
||||
type: "tool_use",
|
||||
id: "toolu_bash",
|
||||
name: "Bash",
|
||||
input: { command: "ls -la" },
|
||||
},
|
||||
};
|
||||
|
||||
// BetaBashCodeExecutionResultBlock from SDK
|
||||
const bashResult: BetaBashCodeExecutionResultBlock = {
|
||||
type: "bash_code_execution_result",
|
||||
stdout: "file1.txt\nfile2.txt",
|
||||
stderr: "",
|
||||
return_code: 0,
|
||||
content: [],
|
||||
};
|
||||
|
||||
const toolResult: BetaBashCodeExecutionToolResultBlock = {
|
||||
type: "bash_code_execution_tool_result",
|
||||
tool_use_id: "toolu_bash",
|
||||
content: bashResult,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
expect(notifications).toHaveLength(1);
|
||||
expect(notifications[0].update).toMatchObject({
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: "toolu_bash",
|
||||
status: "completed",
|
||||
rawOutput: bashResult,
|
||||
});
|
||||
});
|
||||
|
||||
it("should set status to failed when is_error is true", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_err: {
|
||||
type: "tool_use",
|
||||
id: "toolu_err",
|
||||
name: "Bash",
|
||||
input: { command: "invalid_command" },
|
||||
},
|
||||
};
|
||||
|
||||
const toolResult: ToolResultBlockParam = {
|
||||
type: "tool_result",
|
||||
tool_use_id: "toolu_err",
|
||||
content: "command not found: invalid_command",
|
||||
is_error: true,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
expect(notifications).toHaveLength(1);
|
||||
expect(notifications[0].update).toMatchObject({
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: "toolu_err",
|
||||
status: "failed",
|
||||
rawOutput: "command not found: invalid_command",
|
||||
});
|
||||
});
|
||||
|
||||
it("should not emit tool_call_update for TodoWrite (emits plan instead)", () => {
|
||||
const toolUseCache: ToolUseCache = {
|
||||
toolu_todo: {
|
||||
type: "tool_use",
|
||||
id: "toolu_todo",
|
||||
name: "TodoWrite",
|
||||
input: { todos: [{ content: "Test task", status: "pending" }] },
|
||||
},
|
||||
};
|
||||
|
||||
const toolResult: ToolResultBlockParam = {
|
||||
type: "tool_result",
|
||||
tool_use_id: "toolu_todo",
|
||||
content: "Todos updated successfully",
|
||||
is_error: false,
|
||||
};
|
||||
|
||||
const notifications = toAcpNotifications(
|
||||
[toolResult],
|
||||
"assistant",
|
||||
"test-session",
|
||||
toolUseCache,
|
||||
mockClient,
|
||||
mockLogger,
|
||||
);
|
||||
|
||||
// TodoWrite should not emit tool_call_update - it emits plan updates instead
|
||||
expect(notifications).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
193
src/tools.ts
193
src/tools.ts
@@ -1,7 +1,44 @@
|
||||
import { PlanEntry, ToolCallContent, ToolCallLocation, ToolKind } from "@agentclientprotocol/sdk";
|
||||
import {
|
||||
ContentBlock,
|
||||
PlanEntry,
|
||||
ToolCallContent,
|
||||
ToolCallLocation,
|
||||
ToolKind,
|
||||
} from "@agentclientprotocol/sdk";
|
||||
import { SYSTEM_REMINDER } from "./mcp-server.js";
|
||||
import * as diff from "diff";
|
||||
import { ToolResultBlockParam, WebSearchToolResultBlockParam } from "@anthropic-ai/sdk/resources";
|
||||
import {
|
||||
ImageBlockParam,
|
||||
TextBlockParam,
|
||||
ToolResultBlockParam,
|
||||
WebSearchResultBlock,
|
||||
WebSearchToolResultBlockParam,
|
||||
WebSearchToolResultError,
|
||||
} from "@anthropic-ai/sdk/resources";
|
||||
import {
|
||||
BetaBashCodeExecutionToolResultBlockParam,
|
||||
BetaBashCodeExecutionResultBlock,
|
||||
BetaBashCodeExecutionToolResultError,
|
||||
BetaCodeExecutionToolResultBlockParam,
|
||||
BetaCodeExecutionResultBlock,
|
||||
BetaCodeExecutionToolResultError,
|
||||
BetaRequestMCPToolResultBlockParam,
|
||||
BetaTextEditorCodeExecutionToolResultBlockParam,
|
||||
BetaTextEditorCodeExecutionViewResultBlock,
|
||||
BetaTextEditorCodeExecutionCreateResultBlock,
|
||||
BetaTextEditorCodeExecutionStrReplaceResultBlock,
|
||||
BetaTextEditorCodeExecutionToolResultError,
|
||||
BetaToolResultBlockParam,
|
||||
BetaToolSearchToolResultBlockParam,
|
||||
BetaToolReferenceBlock,
|
||||
BetaToolSearchToolSearchResultBlock,
|
||||
BetaToolSearchToolResultError,
|
||||
BetaWebFetchToolResultBlockParam,
|
||||
BetaWebFetchBlock,
|
||||
BetaWebFetchToolResultErrorBlock,
|
||||
BetaWebSearchToolResultBlockParam,
|
||||
BetaImageBlockParam,
|
||||
} from "@anthropic-ai/sdk/resources/beta.mjs";
|
||||
|
||||
const acpUnqualifiedToolNames = {
|
||||
read: "Read",
|
||||
@@ -24,15 +61,29 @@ export const acpToolNames = {
|
||||
|
||||
export const EDIT_TOOL_NAMES = [acpToolNames.edit, acpToolNames.write];
|
||||
|
||||
import {
|
||||
BetaBashCodeExecutionToolResultBlockParam,
|
||||
BetaCodeExecutionToolResultBlockParam,
|
||||
BetaRequestMCPToolResultBlockParam,
|
||||
BetaTextEditorCodeExecutionToolResultBlockParam,
|
||||
BetaToolSearchToolResultBlockParam,
|
||||
BetaWebFetchToolResultBlockParam,
|
||||
BetaWebSearchToolResultBlockParam,
|
||||
} from "@anthropic-ai/sdk/resources/beta.mjs";
|
||||
/**
|
||||
* Union of all possible content types that can appear in tool results from the Anthropic SDK.
|
||||
* These are transformed to valid ACP ContentBlock types by toValidAcpContent().
|
||||
*/
|
||||
type ToolResultContent =
|
||||
| TextBlockParam
|
||||
| ImageBlockParam
|
||||
| BetaImageBlockParam
|
||||
| BetaToolReferenceBlock
|
||||
| BetaToolSearchToolSearchResultBlock
|
||||
| BetaToolSearchToolResultError
|
||||
| WebSearchResultBlock
|
||||
| WebSearchToolResultError
|
||||
| BetaWebFetchBlock
|
||||
| BetaWebFetchToolResultErrorBlock
|
||||
| BetaCodeExecutionResultBlock
|
||||
| BetaCodeExecutionToolResultError
|
||||
| BetaBashCodeExecutionResultBlock
|
||||
| BetaBashCodeExecutionToolResultError
|
||||
| BetaTextEditorCodeExecutionViewResultBlock
|
||||
| BetaTextEditorCodeExecutionCreateResultBlock
|
||||
| BetaTextEditorCodeExecutionStrReplaceResultBlock
|
||||
| BetaTextEditorCodeExecutionToolResultError;
|
||||
import { HookCallback } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { Logger } from "./acp-agent.js";
|
||||
import { SettingsManager } from "./settings.js";
|
||||
@@ -406,6 +457,7 @@ export function toolInfoFromToolUse(toolUse: any): ToolInfo {
|
||||
export function toolUpdateFromToolResult(
|
||||
toolResult:
|
||||
| ToolResultBlockParam
|
||||
| BetaToolResultBlockParam
|
||||
| BetaWebSearchToolResultBlockParam
|
||||
| BetaWebFetchToolResultBlockParam
|
||||
| WebSearchToolResultBlockParam
|
||||
@@ -547,17 +599,20 @@ function toAcpContentUpdate(
|
||||
): { content?: ToolCallContent[] } {
|
||||
if (Array.isArray(content) && content.length > 0) {
|
||||
return {
|
||||
content: content.map((content: any) => ({
|
||||
type: "content",
|
||||
content:
|
||||
isError && content.type === "text"
|
||||
? {
|
||||
...content,
|
||||
text: `\`\`\`\n${content.text}\n\`\`\``,
|
||||
}
|
||||
: content,
|
||||
content: content.map((c: any) => ({
|
||||
type: "content" as const,
|
||||
content: toAcpContentBlock(c, isError),
|
||||
})),
|
||||
};
|
||||
} else if (typeof content === "object" && content !== null && "type" in content) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "content" as const,
|
||||
content: toAcpContentBlock(content, isError),
|
||||
},
|
||||
],
|
||||
};
|
||||
} else if (typeof content === "string" && content.length > 0) {
|
||||
return {
|
||||
content: [
|
||||
@@ -574,6 +629,74 @@ function toAcpContentUpdate(
|
||||
return {};
|
||||
}
|
||||
|
||||
function toAcpContentBlock(content: ToolResultContent, isError: boolean): ContentBlock {
|
||||
const wrapText = (text: string): ContentBlock => ({
|
||||
type: "text" as const,
|
||||
text: isError ? `\`\`\`\n${text}\n\`\`\`` : text,
|
||||
});
|
||||
|
||||
switch (content.type) {
|
||||
case "text":
|
||||
return {
|
||||
type: "text" as const,
|
||||
text: isError ? `\`\`\`\n${content.text}\n\`\`\`` : content.text,
|
||||
};
|
||||
case "image":
|
||||
if (content.source.type === "base64") {
|
||||
return {
|
||||
type: "image" as const,
|
||||
data: content.source.data,
|
||||
mimeType: content.source.media_type,
|
||||
};
|
||||
}
|
||||
// URL and file-based images can't be converted to ACP format (requires data)
|
||||
return wrapText(
|
||||
content.source.type === "url"
|
||||
? `[image: ${content.source.url}]`
|
||||
: "[image: file reference]",
|
||||
);
|
||||
|
||||
case "tool_reference":
|
||||
return wrapText(`Tool: ${content.tool_name}`);
|
||||
case "tool_search_tool_search_result":
|
||||
return wrapText(
|
||||
`Tools found: ${content.tool_references.map((r) => r.tool_name).join(", ") || "none"}`,
|
||||
);
|
||||
case "tool_search_tool_result_error":
|
||||
return wrapText(
|
||||
`Error: ${content.error_code}${content.error_message ? ` - ${content.error_message}` : ""}`,
|
||||
);
|
||||
case "web_search_result":
|
||||
return wrapText(`${content.title} (${content.url})`);
|
||||
case "web_search_tool_result_error":
|
||||
return wrapText(`Error: ${content.error_code}`);
|
||||
case "web_fetch_result":
|
||||
return wrapText(`Fetched: ${content.url}`);
|
||||
case "web_fetch_tool_result_error":
|
||||
return wrapText(`Error: ${content.error_code}`);
|
||||
case "code_execution_result":
|
||||
return wrapText(`Output: ${content.stdout || content.stderr || ""}`);
|
||||
case "bash_code_execution_result":
|
||||
return wrapText(`Output: ${content.stdout || content.stderr || ""}`);
|
||||
case "code_execution_tool_result_error":
|
||||
case "bash_code_execution_tool_result_error":
|
||||
return wrapText(`Error: ${content.error_code}`);
|
||||
case "text_editor_code_execution_view_result":
|
||||
return wrapText(content.content);
|
||||
case "text_editor_code_execution_create_result":
|
||||
return wrapText(content.is_file_update ? "File updated" : "File created");
|
||||
case "text_editor_code_execution_str_replace_result":
|
||||
return wrapText(content.lines?.join("\n") || "");
|
||||
case "text_editor_code_execution_tool_result_error":
|
||||
return wrapText(
|
||||
`Error: ${content.error_code}${content.error_message ? ` - ${content.error_message}` : ""}`,
|
||||
);
|
||||
|
||||
default:
|
||||
return wrapText(JSON.stringify(content));
|
||||
}
|
||||
}
|
||||
|
||||
export type ClaudePlanEntry = {
|
||||
content: string;
|
||||
status: "pending" | "in_progress" | "completed";
|
||||
@@ -629,16 +752,28 @@ export const registerHookCallback = (
|
||||
|
||||
/* A callback for Claude Code that is called when receiving a PostToolUse hook */
|
||||
export const createPostToolUseHook =
|
||||
(logger: Logger = console): HookCallback =>
|
||||
(
|
||||
logger: Logger = console,
|
||||
options?: {
|
||||
onEnterPlanMode?: () => Promise<void>;
|
||||
},
|
||||
): HookCallback =>
|
||||
async (input: any, toolUseID: string | undefined): Promise<{ continue: boolean }> => {
|
||||
if (input.hook_event_name === "PostToolUse" && toolUseID) {
|
||||
const onPostToolUseHook = toolUseCallbacks[toolUseID]?.onPostToolUseHook;
|
||||
if (onPostToolUseHook) {
|
||||
await onPostToolUseHook(toolUseID, input.tool_input, input.tool_response);
|
||||
delete toolUseCallbacks[toolUseID]; // Cleanup after execution
|
||||
} else {
|
||||
logger.error(`No onPostToolUseHook found for tool use ID: ${toolUseID}`);
|
||||
delete toolUseCallbacks[toolUseID];
|
||||
if (input.hook_event_name === "PostToolUse") {
|
||||
// Handle EnterPlanMode tool - notify client of mode change after successful execution
|
||||
if (input.tool_name === "EnterPlanMode" && options?.onEnterPlanMode) {
|
||||
await options.onEnterPlanMode();
|
||||
}
|
||||
|
||||
if (toolUseID) {
|
||||
const onPostToolUseHook = toolUseCallbacks[toolUseID]?.onPostToolUseHook;
|
||||
if (onPostToolUseHook) {
|
||||
await onPostToolUseHook(toolUseID, input.tool_input, input.tool_response);
|
||||
delete toolUseCallbacks[toolUseID]; // Cleanup after execution
|
||||
} else {
|
||||
logger.error(`No onPostToolUseHook found for tool use ID: ${toolUseID}`);
|
||||
delete toolUseCallbacks[toolUseID];
|
||||
}
|
||||
}
|
||||
}
|
||||
return { continue: true };
|
||||
|
||||
Reference in New Issue
Block a user