Compare commits

...

5 Commits

Author SHA1 Message Date
Ben Brandt
4ee25af3f9 Update to claude-agent-sdk 0.1.8 (#83) 2025-10-06 09:01:40 +00:00
Ben Brandt
1a5a9c16c6 Add back @anthropic-ai/claude-code as runtime dependency (#79)
Some clients (i.e. Zed) still relied on this package being there at
runtime.
Adding it as a dependency for now.
2025-09-30 16:46:04 +02:00
Ben Brandt
5ca27369ef Prep v0.5.1 (#78) 2025-09-30 09:19:37 +00:00
Ben Brandt
8068d894c1 Align ACP tools with latest Claude Code tools (#77)
Signed-off-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2025-09-30 11:08:24 +02:00
Ben Brandt
71e745d5fb Use default behavior for bypassPermissions mode (#75)
They updated the types to allow us to just pass this through now. So we
shouldn't have to have the special casing here.
2025-09-29 23:13:12 +02:00
7 changed files with 361 additions and 477 deletions

View File

@@ -1,5 +1,19 @@
# Changelog
## 0.5.3
- Update to @anthropic-ai/claude-agent-sdk@v0.1.8
- Update to @zed-industries/agent-client-protocol@v0.4.5
## 0.5.2
- Add back @anthropic-ai/claude-code@2.0.1 as runtime dependency
## 0.5.1
- Update to @anthropic-ai/claude-agent-sdk@v0.1.1
- Make improvements to ACP tools provided to the model
## 0.5.0
- Migrate to @anthropic-ai/claude-agent-sdk@v0.1.0

340
package-lock.json generated
View File

@@ -1,17 +1,18 @@
{
"name": "@zed-industries/claude-code-acp",
"version": "0.5.0",
"version": "0.5.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@zed-industries/claude-code-acp",
"version": "0.5.0",
"version": "0.5.3",
"license": "Apache-2.0",
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "0.1.0",
"@modelcontextprotocol/sdk": "1.18.2",
"@zed-industries/agent-client-protocol": "0.4.3",
"@anthropic-ai/claude-agent-sdk": "0.1.8",
"@anthropic-ai/claude-code": "2.0.8",
"@modelcontextprotocol/sdk": "1.19.1",
"@zed-industries/agent-client-protocol": "0.4.5",
"diff": "8.0.2",
"express": "5.1.0",
"minimist": "1.2.8",
@@ -24,24 +25,24 @@
"@anthropic-ai/sdk": "^0.65.0",
"@types/express": "5.0.3",
"@types/minimist": "1.2.5",
"@types/node": "24.6.0",
"@types/node": "24.7.0",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "8.45.0",
"@typescript-eslint/parser": "8.45.0",
"@vitest/ui": "3.2.4",
"eslint": "9.36.0",
"eslint": "9.37.0",
"eslint-config-prettier": "10.1.8",
"globals": "16.4.0",
"prettier": "3.6.2",
"ts-node": "10.9.2",
"typescript": "5.9.2",
"typescript": "5.9.3",
"vitest": "3.2.4"
}
},
"node_modules/@anthropic-ai/claude-agent-sdk": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.1.0.tgz",
"integrity": "sha512-D2Oko7WCMQHH9TOexBVbW/31LqyAaOpVgHIjbzcTjOTmWO5Stms1SwEuWpB3SAEIrHbOtqWEqZSZz3ZZ/JmMhg==",
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.1.8.tgz",
"integrity": "sha512-QaylzHEweHI4FOKAfFd8FNzbyFd+WSA8Hb5V8+O0gOi0X1iV5xa+f6lFjBI9AlGP3frfb1ONn6LYmn0d+szV3g==",
"license": "SEE LICENSE IN README.md",
"engines": {
"node": ">=18.0.0"
@@ -55,6 +56,26 @@
"@img/sharp-win32-x64": "^0.33.5"
}
},
"node_modules/@anthropic-ai/claude-code": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-2.0.8.tgz",
"integrity": "sha512-GeNV0px4GrLnoFlC0Vv5aN0J4JlFV/xEf6KsvfMf3WdkyeaAaUR7MiMl/D6A7hb1fDF4a5nI/mCLEZZC0prpNQ==",
"license": "SEE LICENSE IN README.md",
"bin": {
"claude": "cli.js"
},
"engines": {
"node": ">=18.0.0"
},
"optionalDependencies": {
"@img/sharp-darwin-arm64": "^0.33.5",
"@img/sharp-darwin-x64": "^0.33.5",
"@img/sharp-linux-arm": "^0.33.5",
"@img/sharp-linux-arm64": "^0.33.5",
"@img/sharp-linux-x64": "^0.33.5",
"@img/sharp-win32-x64": "^0.33.5"
}
},
"node_modules/@anthropic-ai/sdk": {
"version": "0.65.0",
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.65.0.tgz",
@@ -610,19 +631,22 @@
}
},
"node_modules/@eslint/config-helpers": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz",
"integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.0.tgz",
"integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^0.16.0"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@eslint/core": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz",
"integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==",
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.16.0.tgz",
"integrity": "sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -704,9 +728,9 @@
}
},
"node_modules/@eslint/js": {
"version": "9.36.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz",
"integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==",
"version": "9.37.0",
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz",
"integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -727,13 +751,13 @@
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz",
"integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==",
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.0.tgz",
"integrity": "sha512-sB5uyeq+dwCWyPi31B2gQlVlo+j5brPlWx4yZBrEaRo/nhdDE8Xke1gsGgtiBdaBTxuTkceLVuVt/pclrasb0A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^0.15.2",
"@eslint/core": "^0.16.0",
"levn": "^0.4.1"
},
"engines": {
@@ -1030,9 +1054,9 @@
}
},
"node_modules/@modelcontextprotocol/sdk": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.18.2.tgz",
"integrity": "sha512-beedclIvFcCnPrYgHsylqiYJVJ/CI47Vyc4tY8no1/Li/O8U4BTlJfy6ZwxkYwx+Mx10nrgwSVrA7VBbhh4slg==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.19.1.tgz",
"integrity": "sha512-3Y2h3MZKjec1eAqSTBclATlX+AbC6n1LgfVzRMJLt3v6w0RCYgwLrjbxPDbhsYHt6Wdqc/aCceNJYgj448ELQQ==",
"license": "MIT",
"dependencies": {
"ajv": "^6.12.6",
@@ -1098,9 +1122,9 @@
"license": "MIT"
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.3.tgz",
"integrity": "sha512-h6cqHGZ6VdnwliFG1NXvMPTy/9PS3h8oLh7ImwR+kl+oYnQizgjxsONmmPSb2C66RksfkfIxEVtDSEcJiO0tqw==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz",
"integrity": "sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==",
"cpu": [
"arm"
],
@@ -1112,9 +1136,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.3.tgz",
"integrity": "sha512-wd+u7SLT/u6knklV/ifG7gr5Qy4GUbH2hMWcDauPFJzmCZUAJ8L2bTkVXC2niOIxp8lk3iH/QX8kSrUxVZrOVw==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz",
"integrity": "sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==",
"cpu": [
"arm64"
],
@@ -1126,9 +1150,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.3.tgz",
"integrity": "sha512-lj9ViATR1SsqycwFkJCtYfQTheBdvlWJqzqxwc9f2qrcVrQaF/gCuBRTiTolkRWS6KvNxSk4KHZWG7tDktLgjg==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz",
"integrity": "sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==",
"cpu": [
"arm64"
],
@@ -1140,9 +1164,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.3.tgz",
"integrity": "sha512-+Dyo7O1KUmIsbzx1l+4V4tvEVnVQqMOIYtrxK7ncLSknl1xnMHLgn7gddJVrYPNZfEB8CIi3hK8gq8bDhb3h5A==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz",
"integrity": "sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==",
"cpu": [
"x64"
],
@@ -1154,9 +1178,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.3.tgz",
"integrity": "sha512-u9Xg2FavYbD30g3DSfNhxgNrxhi6xVG4Y6i9Ur1C7xUuGDW3banRbXj+qgnIrwRN4KeJ396jchwy9bCIzbyBEQ==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz",
"integrity": "sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==",
"cpu": [
"arm64"
],
@@ -1168,9 +1192,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.3.tgz",
"integrity": "sha512-5M8kyi/OX96wtD5qJR89a/3x5x8x5inXBZO04JWhkQb2JWavOWfjgkdvUqibGJeNNaz1/Z1PPza5/tAPXICI6A==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz",
"integrity": "sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==",
"cpu": [
"x64"
],
@@ -1182,9 +1206,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.3.tgz",
"integrity": "sha512-IoerZJ4l1wRMopEHRKOO16e04iXRDyZFZnNZKrWeNquh5d6bucjezgd+OxG03mOMTnS1x7hilzb3uURPkJ0OfA==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz",
"integrity": "sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==",
"cpu": [
"arm"
],
@@ -1196,9 +1220,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.3.tgz",
"integrity": "sha512-ZYdtqgHTDfvrJHSh3W22TvjWxwOgc3ThK/XjgcNGP2DIwFIPeAPNsQxrJO5XqleSlgDux2VAoWQ5iJrtaC1TbA==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz",
"integrity": "sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==",
"cpu": [
"arm"
],
@@ -1210,9 +1234,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.3.tgz",
"integrity": "sha512-NcViG7A0YtuFDA6xWSgmFb6iPFzHlf5vcqb2p0lGEbT+gjrEEz8nC/EeDHvx6mnGXnGCC1SeVV+8u+smj0CeGQ==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz",
"integrity": "sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==",
"cpu": [
"arm64"
],
@@ -1224,9 +1248,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.3.tgz",
"integrity": "sha512-d3pY7LWno6SYNXRm6Ebsq0DJGoiLXTb83AIPCXl9fmtIQs/rXoS8SJxxUNtFbJ5MiOvs+7y34np77+9l4nfFMw==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz",
"integrity": "sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==",
"cpu": [
"arm64"
],
@@ -1238,9 +1262,9 @@
]
},
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.3.tgz",
"integrity": "sha512-3y5GA0JkBuirLqmjwAKwB0keDlI6JfGYduMlJD/Rl7fvb4Ni8iKdQs1eiunMZJhwDWdCvrcqXRY++VEBbvk6Eg==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz",
"integrity": "sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==",
"cpu": [
"loong64"
],
@@ -1252,9 +1276,9 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.3.tgz",
"integrity": "sha512-AUUH65a0p3Q0Yfm5oD2KVgzTKgwPyp9DSXc3UA7DtxhEb/WSPfbG4wqXeSN62OG5gSo18em4xv6dbfcUGXcagw==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz",
"integrity": "sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==",
"cpu": [
"ppc64"
],
@@ -1266,9 +1290,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.3.tgz",
"integrity": "sha512-1makPhFFVBqZE+XFg3Dkq+IkQ7JvmUrwwqaYBL2CE+ZpxPaqkGaiWFEWVGyvTwZace6WLJHwjVh/+CXbKDGPmg==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz",
"integrity": "sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==",
"cpu": [
"riscv64"
],
@@ -1280,9 +1304,9 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.3.tgz",
"integrity": "sha512-OOFJa28dxfl8kLOPMUOQBCO6z3X2SAfzIE276fwT52uXDWUS178KWq0pL7d6p1kz7pkzA0yQwtqL0dEPoVcRWg==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz",
"integrity": "sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==",
"cpu": [
"riscv64"
],
@@ -1294,9 +1318,9 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.3.tgz",
"integrity": "sha512-jMdsML2VI5l+V7cKfZx3ak+SLlJ8fKvLJ0Eoa4b9/vCUrzXKgoKxvHqvJ/mkWhFiyp88nCkM5S2v6nIwRtPcgg==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz",
"integrity": "sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==",
"cpu": [
"s390x"
],
@@ -1308,9 +1332,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.3.tgz",
"integrity": "sha512-tPgGd6bY2M2LJTA1uGq8fkSPK8ZLYjDjY+ZLK9WHncCnfIz29LIXIqUgzCR0hIefzy6Hpbe8Th5WOSwTM8E7LA==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz",
"integrity": "sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==",
"cpu": [
"x64"
],
@@ -1322,9 +1346,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.3.tgz",
"integrity": "sha512-BCFkJjgk+WFzP+tcSMXq77ymAPIxsX9lFJWs+2JzuZTLtksJ2o5hvgTdIcZ5+oKzUDMwI0PfWzRBYAydAHF2Mw==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz",
"integrity": "sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==",
"cpu": [
"x64"
],
@@ -1336,9 +1360,9 @@
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.3.tgz",
"integrity": "sha512-KTD/EqjZF3yvRaWUJdD1cW+IQBk4fbQaHYJUmP8N4XoKFZilVL8cobFSTDnjTtxWJQ3JYaMgF4nObY/+nYkumA==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz",
"integrity": "sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==",
"cpu": [
"arm64"
],
@@ -1350,9 +1374,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.3.tgz",
"integrity": "sha512-+zteHZdoUYLkyYKObGHieibUFLbttX2r+58l27XZauq0tcWYYuKUwY2wjeCN9oK1Um2YgH2ibd6cnX/wFD7DuA==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz",
"integrity": "sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==",
"cpu": [
"arm64"
],
@@ -1364,9 +1388,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.3.tgz",
"integrity": "sha512-of1iHkTQSo3kr6dTIRX6t81uj/c/b15HXVsPcEElN5sS859qHrOepM5p9G41Hah+CTqSh2r8Bm56dL2z9UQQ7g==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz",
"integrity": "sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==",
"cpu": [
"ia32"
],
@@ -1378,9 +1402,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.3.tgz",
"integrity": "sha512-s0hybmlHb56mWVZQj8ra9048/WZTPLILKxcvcq+8awSZmyiSUZjjem1AhU3Tf4ZKpYhK4mg36HtHDOe8QJS5PQ==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz",
"integrity": "sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==",
"cpu": [
"x64"
],
@@ -1392,9 +1416,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.3.tgz",
"integrity": "sha512-zGIbEVVXVtauFgl3MRwGWEN36P5ZGenHRMgNw88X5wEhEBpq0XrMEZwOn07+ICrwM17XO5xfMZqh0OldCH5VTA==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz",
"integrity": "sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==",
"cpu": [
"x64"
],
@@ -1532,13 +1556,13 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.6.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.6.0.tgz",
"integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==",
"version": "24.7.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.7.0.tgz",
"integrity": "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.13.0"
"undici-types": "~7.14.0"
}
},
"node_modules/@types/qs": {
@@ -1556,6 +1580,28 @@
"license": "MIT"
},
"node_modules/@types/send": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz",
"integrity": "sha512-zBF6vZJn1IaMpg3xUF25VK3gd3l8zwE0ZLRX7dsQyQi+jp4E8mMDJNGDYnYse+bQhYwWERTxVwHpi3dMOq7RKQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/serve-static": {
"version": "1.15.9",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.9.tgz",
"integrity": "sha512-dOTIuqpWLyl3BBXU3maNQsS4A3zuuoYRNIvYSxxhebPfXg2mzWQEPne/nlJ37yOse6uGgR386uTpdsx4D0QZWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/http-errors": "*",
"@types/node": "*",
"@types/send": "<1"
}
},
"node_modules/@types/serve-static/node_modules/@types/send": {
"version": "0.17.5",
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
"integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
@@ -1566,18 +1612,6 @@
"@types/node": "*"
}
},
"node_modules/@types/serve-static": {
"version": "1.15.8",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz",
"integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/http-errors": "*",
"@types/node": "*",
"@types/send": "*"
}
},
"node_modules/@types/uuid": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
@@ -1958,9 +1992,9 @@
}
},
"node_modules/@zed-industries/agent-client-protocol": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@zed-industries/agent-client-protocol/-/agent-client-protocol-0.4.3.tgz",
"integrity": "sha512-6lcxHVdkm0YMvqBNJyddXA4T8qhVMeOVscXwioA8hRMLhroLigsspH8oQEbuL35r3g+b2LcmhVzu8EijUo4DYw==",
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/@zed-industries/agent-client-protocol/-/agent-client-protocol-0.4.5.tgz",
"integrity": "sha512-OwHKfu5AiKul/GSJilHg36+kOSV9eOl2eYnjR6tenAQDdraSnt22WFk0SDFTeuAANz1Gxkv+DTf7Hq32rvX7FQ==",
"license": "Apache-2.0",
"dependencies": {
"zod": "^3.0.0"
@@ -2503,20 +2537,20 @@
}
},
"node_modules/eslint": {
"version": "9.36.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz",
"integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==",
"version": "9.37.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz",
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
"@eslint/config-array": "^0.21.0",
"@eslint/config-helpers": "^0.3.1",
"@eslint/core": "^0.15.2",
"@eslint/config-helpers": "^0.4.0",
"@eslint/core": "^0.16.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "9.36.0",
"@eslint/plugin-kit": "^0.3.5",
"@eslint/js": "9.37.0",
"@eslint/plugin-kit": "^0.4.0",
"@humanfs/node": "^0.16.6",
"@humanwhocodes/module-importer": "^1.0.1",
"@humanwhocodes/retry": "^0.4.2",
@@ -3919,9 +3953,9 @@
}
},
"node_modules/rollup": {
"version": "4.52.3",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.3.tgz",
"integrity": "sha512-RIDh866U8agLgiIcdpB+COKnlCreHJLfIhWC3LVflku5YHfpnsIKigRZeFfMfCc4dVcqNVfQQ5gO/afOck064A==",
"version": "4.52.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz",
"integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3935,28 +3969,28 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.52.3",
"@rollup/rollup-android-arm64": "4.52.3",
"@rollup/rollup-darwin-arm64": "4.52.3",
"@rollup/rollup-darwin-x64": "4.52.3",
"@rollup/rollup-freebsd-arm64": "4.52.3",
"@rollup/rollup-freebsd-x64": "4.52.3",
"@rollup/rollup-linux-arm-gnueabihf": "4.52.3",
"@rollup/rollup-linux-arm-musleabihf": "4.52.3",
"@rollup/rollup-linux-arm64-gnu": "4.52.3",
"@rollup/rollup-linux-arm64-musl": "4.52.3",
"@rollup/rollup-linux-loong64-gnu": "4.52.3",
"@rollup/rollup-linux-ppc64-gnu": "4.52.3",
"@rollup/rollup-linux-riscv64-gnu": "4.52.3",
"@rollup/rollup-linux-riscv64-musl": "4.52.3",
"@rollup/rollup-linux-s390x-gnu": "4.52.3",
"@rollup/rollup-linux-x64-gnu": "4.52.3",
"@rollup/rollup-linux-x64-musl": "4.52.3",
"@rollup/rollup-openharmony-arm64": "4.52.3",
"@rollup/rollup-win32-arm64-msvc": "4.52.3",
"@rollup/rollup-win32-ia32-msvc": "4.52.3",
"@rollup/rollup-win32-x64-gnu": "4.52.3",
"@rollup/rollup-win32-x64-msvc": "4.52.3",
"@rollup/rollup-android-arm-eabi": "4.52.4",
"@rollup/rollup-android-arm64": "4.52.4",
"@rollup/rollup-darwin-arm64": "4.52.4",
"@rollup/rollup-darwin-x64": "4.52.4",
"@rollup/rollup-freebsd-arm64": "4.52.4",
"@rollup/rollup-freebsd-x64": "4.52.4",
"@rollup/rollup-linux-arm-gnueabihf": "4.52.4",
"@rollup/rollup-linux-arm-musleabihf": "4.52.4",
"@rollup/rollup-linux-arm64-gnu": "4.52.4",
"@rollup/rollup-linux-arm64-musl": "4.52.4",
"@rollup/rollup-linux-loong64-gnu": "4.52.4",
"@rollup/rollup-linux-ppc64-gnu": "4.52.4",
"@rollup/rollup-linux-riscv64-gnu": "4.52.4",
"@rollup/rollup-linux-riscv64-musl": "4.52.4",
"@rollup/rollup-linux-s390x-gnu": "4.52.4",
"@rollup/rollup-linux-x64-gnu": "4.52.4",
"@rollup/rollup-linux-x64-musl": "4.52.4",
"@rollup/rollup-openharmony-arm64": "4.52.4",
"@rollup/rollup-win32-arm64-msvc": "4.52.4",
"@rollup/rollup-win32-ia32-msvc": "4.52.4",
"@rollup/rollup-win32-x64-gnu": "4.52.4",
"@rollup/rollup-win32-x64-msvc": "4.52.4",
"fsevents": "~2.3.2"
}
},
@@ -4495,9 +4529,9 @@
}
},
"node_modules/typescript": {
"version": "5.9.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
"dev": true,
"license": "Apache-2.0",
"bin": {
@@ -4509,9 +4543,9 @@
}
},
"node_modules/undici-types": {
"version": "7.13.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.13.0.tgz",
"integrity": "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==",
"version": "7.14.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.14.0.tgz",
"integrity": "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA==",
"dev": true,
"license": "MIT"
},
@@ -4563,9 +4597,9 @@
}
},
"node_modules/vite": {
"version": "7.1.7",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz",
"integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==",
"version": "7.1.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz",
"integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==",
"dev": true,
"license": "MIT",
"dependencies": {

View File

@@ -6,7 +6,7 @@
"bin": {
"claude-code-acp": "./dist/index.js"
},
"version": "0.5.0",
"version": "0.5.3",
"description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
"main": "dist/index.js",
"type": "module",
@@ -51,9 +51,10 @@
"author": "Zed Industries",
"license": "Apache-2.0",
"dependencies": {
"@anthropic-ai/claude-agent-sdk": "0.1.0",
"@modelcontextprotocol/sdk": "1.18.2",
"@zed-industries/agent-client-protocol": "0.4.3",
"@anthropic-ai/claude-agent-sdk": "0.1.8",
"@anthropic-ai/claude-code": "2.0.8",
"@modelcontextprotocol/sdk": "1.19.1",
"@zed-industries/agent-client-protocol": "0.4.5",
"diff": "8.0.2",
"express": "5.1.0",
"minimist": "1.2.8",
@@ -63,17 +64,17 @@
"@anthropic-ai/sdk": "^0.65.0",
"@types/express": "5.0.3",
"@types/minimist": "1.2.5",
"@types/node": "24.6.0",
"@types/node": "24.7.0",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "8.45.0",
"@typescript-eslint/parser": "8.45.0",
"@vitest/ui": "3.2.4",
"eslint": "9.36.0",
"eslint": "9.37.0",
"eslint-config-prettier": "10.1.8",
"globals": "16.4.0",
"prettier": "3.6.2",
"ts-node": "10.9.2",
"typescript": "5.9.2",
"typescript": "5.9.3",
"vitest": "3.2.4"
}
}

View File

@@ -189,11 +189,11 @@ export class ClaudeAcpAgent implements Agent {
}
if (this.clientCapabilities?.fs?.writeTextFile) {
allowedTools.push(toolNames.write);
disallowedTools.push("Write", "Edit", "MultiEdit");
disallowedTools.push("Write", "Edit");
}
if (this.clientCapabilities?.terminal) {
allowedTools.push(toolNames.bashOutput, toolNames.killBash);
disallowedTools.push("Bash", "BashOutput", "KillBash");
allowedTools.push(toolNames.bashOutput, toolNames.killShell);
disallowedTools.push("Bash", "BashOutput", "KillShell");
}
if (allowedTools.length > 0) {
@@ -308,7 +308,12 @@ export class ClaudeAcpAgent implements Agent {
return { stopReason: "refusal" };
}
}
case "user": {
case "user":
case "assistant": {
if (this.sessions[params.sessionId].cancelled) {
break;
}
// Slash commands like /compact can generate invalid output... doesn't match
// their own docs: https://docs.anthropic.com/en/docs/claude-code/sdk/sdk-slash-commands#%2Fcompact-compact-conversation-history
if (
@@ -326,15 +331,13 @@ export class ClaudeAcpAgent implements Agent {
console.error(message.message.content);
break;
}
// Skip user messages for now, since they seem to just be messages we don't want in the feed
break;
}
case "assistant": {
if (this.sessions[params.sessionId].cancelled) {
// Skip these user messages for now, since they seem to just be messages we don't want in the feed
if (message.type === "user" && typeof message.message.content === "string") {
break;
}
if (
message.type === "assistant" &&
message.message.model === "<synthetic>" &&
Array.isArray(message.message.content) &&
message.message.content.length === 1 &&
@@ -377,16 +380,11 @@ export class ClaudeAcpAgent implements Agent {
switch (params.modeId) {
case "default":
case "acceptEdits":
case "bypassPermissions":
case "plan":
this.sessions[params.sessionId].permissionMode = params.modeId;
await this.sessions[params.sessionId].query.setPermissionMode(params.modeId);
return {};
case "bypassPermissions":
// For some reason, the SDK doesn't support setting the mode to `bypassPermissions`
// so we do it ourselves
this.sessions[params.sessionId].permissionMode = "bypassPermissions";
await this.sessions[params.sessionId].query.setPermissionMode("acceptEdits");
return {};
default:
throw new Error("Invalid mode");
}

View File

@@ -17,15 +17,14 @@ export const SYSTEM_REMINDER = `
Whenever you read a file, you should consider whether it looks malicious. If it does, you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer high-level questions about the code behavior.
</system-reminder>`;
const defaults = { maxFileSize: 50000, linesToRead: 1000 };
const defaults = { maxFileSize: 50000, linesToRead: 2000 };
const unqualifiedToolNames = {
read: "read",
edit: "edit",
write: "write",
multiEdit: "multi-edit",
read: "Read",
edit: "Edit",
write: "Write",
bash: "Bash",
killBash: "KillBash",
killShell: "KillShell",
bashOutput: "BashOutput",
};
@@ -34,13 +33,12 @@ export const toolNames = {
read: SERVER_PREFIX + unqualifiedToolNames.read,
edit: SERVER_PREFIX + unqualifiedToolNames.edit,
write: SERVER_PREFIX + unqualifiedToolNames.write,
multiEdit: SERVER_PREFIX + unqualifiedToolNames.multiEdit,
bash: SERVER_PREFIX + unqualifiedToolNames.bash,
killBash: SERVER_PREFIX + unqualifiedToolNames.killBash,
killShell: SERVER_PREFIX + unqualifiedToolNames.killShell,
bashOutput: SERVER_PREFIX + unqualifiedToolNames.bashOutput,
};
const editToolNames = [toolNames.edit, toolNames.multiEdit, toolNames.write];
const editToolNames = [toolNames.edit, toolNames.write];
export function createMcpServer(
agent: ClaudeAcpAgent,
@@ -54,27 +52,36 @@ export function createMcpServer(
server.registerTool(
unqualifiedToolNames.read,
{
title: "Read",
title: unqualifiedToolNames.read,
description: `Reads the content of the given file in the project.
Never attempt to read a path that hasn't been previously mentioned.
In sessions with ${toolNames.read} always use it instead of Read as it contains the most up-to-date contents.
In sessions with ${toolNames.read} always use it instead of Read as it contains the most up-to-date contents.`,
Reads a file from the local filesystem. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned.
Usage:
- The file_path parameter must be an absolute path, not a relative path
- By default, it reads up to ${defaults.linesToRead} lines starting from the beginning of the file
- You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters
- Any files larger than ${defaults.maxFileSize} bytes will be truncated
- This tool allows Claude Code to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Claude Code is a multimodal LLM.
- This tool can only read files, not directories. To read a directory, use an ls command via the ${toolNames.bash} tool.
- You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.`,
inputSchema: {
abs_path: z.string().describe("The absolute path to the file to read."),
file_path: z.string().describe("The absolute path to the file to read"),
offset: z
.number()
.optional()
.default(0)
.default(1)
.describe(
"Which line to start reading from (0-based). Omit to start from the beginning.",
"The line number to start reading from. Only provide if the file is too large to read at once",
),
linesToRead: z
limit: z
.number()
.optional()
.default(defaults.linesToRead)
.describe(
`How many lines to read. Omit for ${defaults.linesToRead}. (Reading files that are too large can fill up the context window unnecessarily, so be thoughtful about how much you read at a time.)`,
`The number of lines to read. Only provide if the file is too large to read at once.`,
),
},
annotations: {
@@ -101,9 +108,9 @@ In sessions with ${toolNames.read} always use it instead of Read as it contains
const content = await agent.readTextFile({
sessionId,
path: input.abs_path,
line: input.offset + 1,
limit: input.linesToRead,
path: input.file_path,
line: input.offset,
limit: input.limit,
});
// Extract lines with byte limit enforcement
@@ -111,13 +118,13 @@ In sessions with ${toolNames.read} always use it instead of Read as it contains
// Construct informative message about what was read
let readInfo = "";
if (input.offset > 0 || result.wasLimited) {
if (input.offset > 1 || result.wasLimited) {
readInfo = "\n\n<file-read-info>";
if (result.wasLimited) {
readInfo += `Read ${result.linesRead} lines (hit 50KB limit). `;
} else {
readInfo += `Read lines ${(input.offset ?? 0) + 1}-${result.linesRead}. `;
readInfo += `Read lines ${input.offset}-${result.linesRead}. `;
}
if (result.wasLimited) {
@@ -153,14 +160,23 @@ In sessions with ${toolNames.read} always use it instead of Read as it contains
server.registerTool(
unqualifiedToolNames.write,
{
title: "Write",
description: `Writes content to the specified file in the project.
title: unqualifiedToolNames.write,
description: `Writes a file to the local filesystem..
In sessions with ${toolNames.write} always use it instead of Write as it will
allow the user to conveniently review changes.`,
allow the user to conveniently review changes.
Usage:
- This tool will overwrite the existing file if there is one at the provided path.
- If this is an existing file, you MUST use the ${toolNames.read} tool first to read the file's contents. This tool will fail if you did not read the file first.
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.
- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.`,
inputSchema: {
abs_path: z.string().describe("The absolute path to the file to write"),
content: z.string().describe("The full content to write"),
file_path: z
.string()
.describe("The absolute path to the file to write (must be absolute, not relative)"),
content: z.string().describe("The content to write to the file"),
},
annotations: {
title: "Write file",
@@ -185,7 +201,7 @@ allow the user to conveniently review changes.`,
}
await agent.writeTextFile({
sessionId,
path: input.abs_path,
path: input.file_path,
content: input.content,
});
@@ -208,26 +224,30 @@ allow the user to conveniently review changes.`,
server.registerTool(
unqualifiedToolNames.edit,
{
title: "Edit",
description: `Edit a file.
title: unqualifiedToolNames.edit,
description: `Performs exact string replacements in files.
In sessions with ${toolNames.edit} always use it instead of Edit as it will
allow the user to conveniently review changes.
File editing instructions:
- The \`old_string\` param must match existing file content, including indentation.
- The \`old_string\` param must come from the actual file, not an outline.
- The \`old_string\` section must not be empty.
- Be minimal with replacements:
- For unique lines, include only those lines.
- For non-unique lines, include enough context to identify them.
- Do not escape quotes, newlines, or other characters.
- Only edit the specified file.
- If the \`old_string\` value isn't found in the file, the edit won't be applied. The tool will fail and must be retried.`,
Usage:
- You must use your \`${toolNames.read}\` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.
- When editing text from Read tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears.
- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.
- The edit will FAIL if \`old_string\` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use \`replace_all\` to change every instance of \`old_string\`.
- Use \`replace_all\` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.`,
inputSchema: {
abs_path: z.string().describe("The absolute path to the file to read."),
old_string: z.string().describe("The old text to replace (must be unique in the file)"),
new_string: z.string().describe("The new text."),
file_path: z.string().describe("The absolute path to the file to modify"),
old_string: z.string().describe("The text to replace"),
new_string: z
.string()
.describe("The text to replace it with (must be different from old_string)"),
replace_all: z
.boolean()
.default(false)
.optional()
.describe("Replace all occurences of old_string (default false)"),
},
annotations: {
title: "Edit file",
@@ -252,105 +272,17 @@ File editing instructions:
const { content } = await agent.readTextFile({
sessionId,
path: input.abs_path,
path: input.file_path,
});
const { newContent } = replaceAndCalculateLocation(content, [
{
oldText: input.old_string,
newText: input.new_string,
replaceAll: false,
replaceAll: input.replace_all,
},
]);
const patch = diff.createPatch(input.abs_path, content, newContent);
await agent.writeTextFile({
sessionId,
path: input.abs_path,
content: newContent,
});
return {
content: [
{
type: "text",
text: patch,
},
],
};
},
);
server.registerTool(
unqualifiedToolNames.multiEdit,
{
title: "Multi Edit",
description: `Edit a file with multiple sequential edits.
In sessions with ${toolNames.multiEdit} always use it instead of MultiEdit as it will
allow the user to conveniently review changes.
File editing instructions:
- The \`old_string\` param must match existing file content, including indentation.
- The \`old_string\` param must come from the actual file, not an outline.
- The \`old_string\` section must not be empty.
- Be minimal with replacements:
- For unique lines, include only those lines.
- For non-unique lines, include enough context to identify them, unless you're using \`replace_all\`
- Do not escape quotes, newlines, or other characters.
- If any of the provided \`old_string\` values aren't found in the file, no edits will be applied. The tool will fail and must be retried.`,
inputSchema: {
file_path: z.string().describe("The absolute path to the file to modify"),
edits: z
.array(
z.object({
old_string: z.string().describe("The text to replace"),
new_string: z.string().describe("The text to replace it with"),
replace_all: z
.boolean()
.optional()
.describe("Replace all occurrences of old_string (default false)"),
}),
)
.min(1)
.describe("Array of edit operations to perform sequentially on the file"),
},
annotations: {
title: "Multi Edit file",
readOnlyHint: false,
destructiveHint: false,
openWorldHint: false,
idempotentHint: false,
},
},
async (input) => {
const session = agent.sessions[sessionId];
if (!session) {
return {
content: [
{
type: "text",
text: "The user has left the building",
},
],
};
}
const { content } = await agent.readTextFile({
sessionId,
path: input.file_path,
});
const { newContent } = replaceAndCalculateLocation(
content,
input.edits.map((edit) => ({
oldText: edit.old_string,
newText: edit.new_string,
replaceAll: edit.replace_all ?? false,
})),
);
const patch = diff.createPatch(input.file_path, content, newContent);
await agent.writeTextFile({
@@ -375,19 +307,34 @@ File editing instructions:
server.registerTool(
unqualifiedToolNames.bash,
{
title: "Bash",
description: "Executes a bash command",
title: unqualifiedToolNames.bash,
description: `Executes a bash command
In sessions with ${toolNames.bash} always use it instead of Bash`,
inputSchema: {
command: z.string().describe("The bash command to execute as a one-liner"),
timeout_ms: z
command: z.string().describe("The command to execute"),
timeout: z
.number()
.default(2 * 60 * 1000)
.describe("Optional timeout in milliseconds"),
.describe(`Optional timeout in milliseconds (max ${2 * 60 * 1000})`),
description: z.string().optional()
.describe(`Clear, concise description of what this command does in 5-10 words, in active voice. Examples:
Input: ls
Output: List files in current directory
Input: git status
Output: Show working tree status
Input: npm install
Output: Install package dependencies
Input: mkdir foo
Output: Create directory 'foo'`),
run_in_background: z
.boolean()
.default(false)
.describe(
`When set to true, the command is started in the background. The tool returns an \`id\` that can be used with the \`${toolNames.bashOutput}\` tool to retrieve the current output, or the \`${toolNames.killBash}\` tool to stop it early.`,
`Set to true to run this command in the background. The tool returns an \`id\` that can be used with the \`${toolNames.bashOutput}\` tool to retrieve the current output, or the \`${toolNames.killShell}\` tool to stop it early.`,
),
},
},
@@ -426,6 +373,7 @@ File editing instructions:
sessionUpdate: "tool_call_update",
toolCallId,
status: "in_progress",
title: input.description,
content: [{ type: "terminal", terminalId: handle.id }],
},
});
@@ -443,7 +391,7 @@ File editing instructions:
const statusPromise = Promise.race([
handle.waitForExit().then((exitStatus) => ({ status: "exited" as const, exitStatus })),
abortPromise.then(() => ({ status: "aborted" as const, exitStatus: null })),
sleep(input.timeout_ms).then(async () => {
sleep(input.timeout).then(async () => {
if (agent.backgroundTerminals[handle.id]?.status === "started") {
await handle.kill();
}
@@ -510,20 +458,25 @@ File editing instructions:
server.registerTool(
unqualifiedToolNames.bashOutput,
{
title: "BashOutput",
description:
"Returns the current output and exit status of a background bash command by its id. Includes only new output since last invocation.",
title: unqualifiedToolNames.bashOutput,
description: `- Retrieves output from a running or completed background bash shell
- Takes a shell_id parameter identifying the shell
- Always returns only new output since the last check
- Returns stdout and stderr output along with shell status
- Use this tool when you need to monitor or check the output of a long-running shell
In sessions with ${toolNames.bashOutput} always use it instead of BashOutput.`,
inputSchema: {
id: z
shell_id: z
.string()
.describe(`The id of the background bash command as returned by \`${toolNames.bash}\``),
},
},
async (input) => {
const bgTerm = agent.backgroundTerminals[input.id];
const bgTerm = agent.backgroundTerminals[input.shell_id];
if (!bgTerm) {
throw new Error(`Unknown shell ${input.id}`);
throw new Error(`Unknown shell ${input.shell_id}`);
}
if (bgTerm.status === "started") {
@@ -559,21 +512,26 @@ File editing instructions:
);
server.registerTool(
unqualifiedToolNames.killBash,
unqualifiedToolNames.killShell,
{
title: "KillBash",
description: "Stops a background command by its id",
title: unqualifiedToolNames.killShell,
description: `- Kills a running background bash shell by its ID
- Takes a shell_id parameter identifying the shell to kill
- Returns a success or failure status
- Use this tool when you need to terminate a long-running shell
In sessions with ${toolNames.killShell} always use it instead of KillShell.`,
inputSchema: {
id: z
shell_id: z
.string()
.describe(`The id of the background bash command as returned by \`${toolNames.bash}\``),
},
},
async (input) => {
const bgTerm = agent.backgroundTerminals[input.id];
const bgTerm = agent.backgroundTerminals[input.shell_id];
if (!bgTerm) {
throw new Error(`Unknown shell ${input.id}`);
throw new Error(`Unknown shell ${input.shell_id}`);
}
switch (bgTerm.status) {

View File

@@ -371,13 +371,13 @@ describe("tool conversions", () => {
});
});
it("should handle mcp__acp__write tool calls", () => {
it("should handle mcp__acp__Write tool calls", () => {
const tool_use = {
type: "tool_use",
id: "toolu_01GHI789JKL456",
name: "mcp__acp__write",
name: "mcp__acp__Write",
input: {
abs_path: "/Users/test/project/config.json",
file_path: "/Users/test/project/config.json",
content: '{"version": "1.0.0"}',
},
};
@@ -415,13 +415,13 @@ describe("tool conversions", () => {
});
});
it("should handle mcp__acp__read tool calls", () => {
it("should handle mcp__acp__Read tool calls", () => {
const tool_use = {
type: "tool_use",
id: "toolu_01YZA789BCD123",
name: "mcp__acp__read",
name: "mcp__acp__Read",
input: {
abs_path: "/Users/test/project/data.json",
file_path: "/Users/test/project/data.json",
},
};
@@ -433,13 +433,13 @@ describe("tool conversions", () => {
});
});
it("should handle mcp__acp__read with limit", () => {
it("should handle mcp__acp__Read with limit", () => {
const tool_use = {
type: "tool_use",
id: "toolu_01EFG456HIJ789",
name: "mcp__acp__read",
name: "mcp__acp__Read",
input: {
abs_path: "/Users/test/project/large.txt",
file_path: "/Users/test/project/large.txt",
limit: 100,
},
};
@@ -452,13 +452,13 @@ describe("tool conversions", () => {
});
});
it("should handle mcp__acp__read with offset and limit", () => {
it("should handle mcp__acp__Read with offset and limit", () => {
const tool_use = {
type: "tool_use",
id: "toolu_01KLM789NOP456",
name: "mcp__acp__read",
name: "mcp__acp__Read",
input: {
abs_path: "/Users/test/project/large.txt",
file_path: "/Users/test/project/large.txt",
offset: 50,
limit: 100,
},
@@ -472,13 +472,13 @@ describe("tool conversions", () => {
});
});
it("should handle mcp__acp__read with only offset", () => {
it("should handle mcp__acp__Read with only offset", () => {
const tool_use = {
type: "tool_use",
id: "toolu_01QRS123TUV789",
name: "mcp__acp__read",
name: "mcp__acp__Read",
input: {
abs_path: "/Users/test/project/large.txt",
file_path: "/Users/test/project/large.txt",
offset: 200,
},
};
@@ -539,7 +539,7 @@ describe("tool conversions", () => {
const tool_use = {
type: "tool_use",
id: "toolu_01PhLms5fuvmdjy2bb6dfUKT",
name: "KillBash",
name: "KillShell",
input: {
shell_id: "bash_1",
},
@@ -701,78 +701,13 @@ describe("tool conversions", () => {
]);
});
it("should show full diff for multi edit tool", () => {
const toolUse = {
type: "tool_use",
id: "toolu_01DEF456",
name: "mcp__acp__multi-edit",
input: {
file_path: "/Users/test/project/config.json",
edits: [
{
old_string: 'version": 1',
new_string: 'version": 2',
replace_all: false,
},
{
old_string: 'enabled": false',
new_string: 'enabled": true',
replace_all: true,
},
],
},
};
const fileCache: { [key: string]: string } = {
"/Users/test/project/config.json": JSON.stringify(
{
version: 1,
filler: "filler",
enabled: false,
},
null,
4,
),
};
expect(toolInfoFromToolUse(toolUse, fileCache)).toEqual({
content: [
{
newText: `{
"version": 2,
"filler": "filler",
"enabled": true
}`,
oldText: `{
"version": 1,
"filler": "filler",
"enabled": false
}`,
path: "/Users/test/project/config.json",
type: "diff",
},
],
kind: "edit",
locations: [
{
path: "/Users/test/project/config.json",
line: 1,
},
{
path: "/Users/test/project/config.json",
line: 3,
},
],
title: "Edit /Users/test/project/config.json",
});
});
it("should return empty update for successful edit result", () => {
const toolUse = {
type: "tool_use",
id: "toolu_01MNO345",
name: "mcp__acp__edit",
name: "mcp__acp__Edit",
input: {
abs_path: "/Users/test/project/test.txt",
file_path: "/Users/test/project/test.txt",
old_string: "old",
new_string: "new",
},
@@ -800,9 +735,9 @@ describe("tool conversions", () => {
const toolUse = {
type: "tool_use",
id: "toolu_01MNO345",
name: "mcp__acp__edit",
name: "mcp__acp__Edit",
input: {
abs_path: "/Users/test/project/test.txt",
file_path: "/Users/test/project/test.txt",
old_string: "old",
new_string: "new",
},

View File

@@ -91,8 +91,8 @@ export function toolInfoFromToolUse(
content: [],
};
case "KillBash":
case toolNames.killBash:
case "KillShell":
case toolNames.killShell:
return {
title: "Kill Process",
kind: "execute",
@@ -108,11 +108,11 @@ export function toolInfoFromToolUse(
limit = " (from line " + (input.offset + 1) + ")";
}
return {
title: "Read " + (input.abs_path ?? "File") + limit,
title: "Read " + (input.file_path ?? "File") + limit,
kind: "read",
locations: [
{
path: input.abs_path,
path: input.file_path,
line: input.offset ?? 0,
},
],
@@ -138,7 +138,7 @@ export function toolInfoFromToolUse(
case toolNames.edit:
case "Edit": {
const path = input?.abs_path ?? input?.file_path;
const path = input?.file_path ?? input?.file_path;
let oldText = input.old_string ?? null;
let newText = input.new_string ?? "";
let affectedLines: number[] = [];
@@ -182,66 +182,13 @@ export function toolInfoFromToolUse(
};
}
case toolNames.multiEdit:
case "MultiEdit": {
const multiInput = input as {
file_path: string;
edits: {
old_string: string;
new_string: string;
replace_all?: boolean;
}[];
};
let oldTextMulti = multiInput.edits.map((edit: any) => edit.old_string).join("\n");
let newTextMulti = multiInput.edits.map((edit: any) => edit.new_string).join("\n");
let affectedLines: number[] = [];
try {
if (multiInput.edits && multiInput.file_path) {
const oldContent =
cachedFileContent[multiInput.file_path] ||
multiInput.edits.map((edit: any) => edit.oldText).join("\n");
const newContent = replaceAndCalculateLocation(
oldContent,
multiInput.edits.map((edit) => ({
oldText: edit.old_string,
newText: edit.new_string,
replaceAll: edit.replace_all,
})),
);
oldTextMulti = oldContent;
newTextMulti = newContent.newContent;
affectedLines = newContent.lineNumbers;
}
} catch (e) {
console.error(e);
}
// Display it as a normal edit, because end users don't care about
// the distinction between edits and multi-edits.
return {
title: input?.file_path ? `Edit ${input.file_path}` : "Edit",
kind: "edit",
content: [
{
type: "diff" as const,
path: input.file_path,
oldText: oldTextMulti,
newText: newTextMulti,
},
],
locations: input?.file_path
? affectedLines.length > 0
? affectedLines.map((line) => ({ line, path: input.file_path }))
: [{ path: input.file_path }]
: [],
};
}
case toolNames.write: {
let content: ToolCallContent[] = [];
if (input && input.abs_path) {
if (input && input.file_path) {
content = [
{
type: "diff",
path: input.abs_path,
path: input.file_path,
oldText: null,
newText: input.content,
},
@@ -255,10 +202,10 @@ export function toolInfoFromToolUse(
];
}
return {
title: input?.abs_path ? `Write ${input.abs_path}` : "Write",
title: input?.file_path ? `Write ${input.file_path}` : "Write",
kind: "edit",
content,
locations: input?.abs_path ? [{ path: input.abs_path }] : [],
locations: input?.file_path ? [{ path: input.file_path }] : [],
};
}
@@ -481,9 +428,6 @@ export function toolUpdateFromToolResult(
case "edit":
case "Edit":
case toolNames.edit:
case toolNames.multiEdit:
case "multi-edit":
case "MultiEdit":
case toolNames.write:
case "Write": {
if (toolResult.is_error && toolResult.content && toolResult.content.length > 0) {