mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 12:40:32 +00:00
Compare commits
10 Commits
mcp-read-l
...
v0.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa7364d49b | ||
|
|
e22d1ed52c | ||
|
|
ecfd36afa6 | ||
|
|
7bd163818b | ||
|
|
491efe32e8 | ||
|
|
ee17e45030 | ||
|
|
468c3522a0 | ||
|
|
84d64b2762 | ||
|
|
9ff7919ea4 | ||
|
|
d58c2dd45d |
9
.github/workflows/publish.yml
vendored
9
.github/workflows/publish.yml
vendored
@@ -6,6 +6,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
environment: release # Optional: for enhanced security
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
@@ -16,8 +17,8 @@ jobs:
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
- name: Update npm
|
||||
run: npm install -g npm@latest
|
||||
- run: npm ci
|
||||
# Add back provenance once repo is public
|
||||
- run: npm publish # --provenance --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- run: npm run build
|
||||
- run: npm publish
|
||||
|
||||
14
CHANGELOG.md
Normal file
14
CHANGELOG.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## v0.4.2
|
||||
|
||||
- Fix missing package.json metadata
|
||||
|
||||
## v0.4.1
|
||||
|
||||
- Add support for /compact command [ecfd36a](https://github.com/zed-industries/claude-code-acp/commit/ecfd36afa6c4e31f12e1daf9b8a2bdc12dda1794)
|
||||
- Add default limits to read tool [7bd1638](https://github.com/zed-industries/claude-code-acp/commit/7bd163818bb959b11fd2c933eff73ad83c57abb8)
|
||||
- Better rendering of Tool errors [491efe3](https://github.com/zed-industries/claude-code-acp/commit/491efe32e8547075842e448d873fc01b2ffabf3a)
|
||||
- Load managed-settings.json [f691024](https://github.com/zed-industries/claude-code-acp/commit/f691024350362858e00b97248ac68e356d2331c2)
|
||||
- Update to @anthropic-ai/claude-code@v1.0.113
|
||||
- Update to @zed-industries/agent-client-protocol@v0.3.1
|
||||
@@ -33,6 +33,7 @@ Read the docs on [External Agent](https://zed.dev/docs/ai/external-agents) suppo
|
||||
### Other clients
|
||||
|
||||
- Neovim via [CodeCompanion.nvim](https://codecompanion.olimorris.dev/configuration/adapters#setup-claude-code-via-acp)
|
||||
- [marimo notebook](https://github.com/marimo-team/marimo)
|
||||
|
||||
[Submit a PR](https://github.com/zed-industries/claude-code-acp/pulls) to add yours!
|
||||
|
||||
|
||||
236
package-lock.json
generated
236
package-lock.json
generated
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"name": "@zed-industries/claude-code-acp",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@zed-industries/claude-code-acp",
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.2",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-code": "1.0.111",
|
||||
"@modelcontextprotocol/sdk": "1.17.4",
|
||||
"@zed-industries/agent-client-protocol": "0.2.0-alpha.8",
|
||||
"@anthropic-ai/claude-code": "1.0.113",
|
||||
"@modelcontextprotocol/sdk": "1.18.0",
|
||||
"@zed-industries/agent-client-protocol": "0.3.1",
|
||||
"diff": "8.0.2",
|
||||
"express": "5.1.0",
|
||||
"minimist": "1.2.8",
|
||||
"uuid": "11.1.0"
|
||||
"uuid": "13.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"claude-code-acp": "dist/index.js"
|
||||
@@ -23,7 +23,7 @@
|
||||
"devDependencies": {
|
||||
"@types/express": "5.0.3",
|
||||
"@types/minimist": "1.2.5",
|
||||
"@types/node": "24.3.1",
|
||||
"@types/node": "24.4.0",
|
||||
"@types/uuid": "10.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.43.0",
|
||||
"@typescript-eslint/parser": "8.43.0",
|
||||
@@ -38,9 +38,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-code": {
|
||||
"version": "1.0.111",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-1.0.111.tgz",
|
||||
"integrity": "sha512-1aALYgO8JyGtRdsFskB3uZiAUKbx8u2YcGoa55ZGwsczTBBVIy/+jsuOi3bAubqlBzi5/8gfFBwYK5QuA621MA==",
|
||||
"version": "1.0.113",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-1.0.113.tgz",
|
||||
"integrity": "sha512-K/+N/rECfWa1ZauWLD6C/CnX6bxxAck5CFDuK58JjRN8v6QDuJVX7HZcNCanB0ucxEkaczAwvWnEM+UjFQsdqw==",
|
||||
"license": "SEE LICENSE IN README.md",
|
||||
"bin": {
|
||||
"claude": "cli.js"
|
||||
@@ -1001,9 +1001,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@modelcontextprotocol/sdk": {
|
||||
"version": "1.17.4",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.17.4.tgz",
|
||||
"integrity": "sha512-zq24hfuAmmlNZvik0FLI58uE5sriN0WWsQzIlYnzSuKDAHFqJtBFrl/LfB1NLgJT5Y7dEBzaX4yAKqOPrcetaw==",
|
||||
"version": "1.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.18.0.tgz",
|
||||
"integrity": "sha512-JvKyB6YwS3quM+88JPR0axeRgvdDu3Pv6mdZUy+w4qVkCzGgumb9bXG/TmtDRQv+671yaofVfXSQmFLlWU5qPQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.6",
|
||||
@@ -1069,9 +1069,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz",
|
||||
"integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz",
|
||||
"integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1083,9 +1083,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm64": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz",
|
||||
"integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz",
|
||||
"integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1097,9 +1097,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz",
|
||||
"integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz",
|
||||
"integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1111,9 +1111,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-x64": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz",
|
||||
"integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz",
|
||||
"integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1125,9 +1125,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-arm64": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz",
|
||||
"integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz",
|
||||
"integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1139,9 +1139,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-freebsd-x64": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz",
|
||||
"integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz",
|
||||
"integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1153,9 +1153,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz",
|
||||
"integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz",
|
||||
"integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1167,9 +1167,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz",
|
||||
"integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz",
|
||||
"integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -1181,9 +1181,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-gnu": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz",
|
||||
"integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz",
|
||||
"integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1195,9 +1195,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-arm64-musl": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz",
|
||||
"integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz",
|
||||
"integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1208,10 +1208,10 @@
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz",
|
||||
"integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==",
|
||||
"node_modules/@rollup/rollup-linux-loong64-gnu": {
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz",
|
||||
"integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -1223,9 +1223,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz",
|
||||
"integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz",
|
||||
"integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -1237,9 +1237,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz",
|
||||
"integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz",
|
||||
"integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1251,9 +1251,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-riscv64-musl": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz",
|
||||
"integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz",
|
||||
"integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -1265,9 +1265,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-s390x-gnu": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz",
|
||||
"integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz",
|
||||
"integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -1279,9 +1279,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz",
|
||||
"integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz",
|
||||
"integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1293,9 +1293,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-linux-x64-musl": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz",
|
||||
"integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz",
|
||||
"integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1307,9 +1307,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-openharmony-arm64": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz",
|
||||
"integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz",
|
||||
"integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1321,9 +1321,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-arm64-msvc": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz",
|
||||
"integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz",
|
||||
"integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -1335,9 +1335,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-ia32-msvc": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz",
|
||||
"integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz",
|
||||
"integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -1349,9 +1349,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@rollup/rollup-win32-x64-msvc": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz",
|
||||
"integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz",
|
||||
"integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1489,13 +1489,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.1.tgz",
|
||||
"integrity": "sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==",
|
||||
"version": "24.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.4.0.tgz",
|
||||
"integrity": "sha512-gUuVEAK4/u6F9wRLznPUU4WGUacSEBDPoC2TrBkw3GAnOLHBL45QdfHOXp1kJ4ypBGLxTOB+t7NJLpKoC3gznQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.10.0"
|
||||
"undici-types": "~7.11.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
@@ -1915,9 +1915,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@zed-industries/agent-client-protocol": {
|
||||
"version": "0.2.0-alpha.8",
|
||||
"resolved": "https://registry.npmjs.org/@zed-industries/agent-client-protocol/-/agent-client-protocol-0.2.0-alpha.8.tgz",
|
||||
"integrity": "sha512-60DDfM5ghChYkbz0Nk2nWDuWQ/BOpU+/4BcIgzHYhEQvCcJRbcs5piVjTXx7TryHNTOTyCmLmoX/WRpAZtva/Q==",
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@zed-industries/agent-client-protocol/-/agent-client-protocol-0.3.1.tgz",
|
||||
"integrity": "sha512-G3gGwNZ18vuuo6rDCo8eoGs/V/P2stIMV7srlaTNXf3u8qAoUNm91p2qhMurR/bCebq8J8yWCKuBZXdC/E162w==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"zod": "^3.0.0"
|
||||
@@ -2281,9 +2281,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
||||
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
@@ -3862,9 +3862,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.50.1",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
|
||||
"integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
|
||||
"version": "4.50.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.2.tgz",
|
||||
"integrity": "sha512-BgLRGy7tNS9H66aIMASq1qSYbAAJV6Z6WR4QYTvj5FgF15rZ/ympT1uixHXwzbZUBDbkvqUI1KR0fH1FhMaQ9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3878,27 +3878,27 @@
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.50.1",
|
||||
"@rollup/rollup-android-arm64": "4.50.1",
|
||||
"@rollup/rollup-darwin-arm64": "4.50.1",
|
||||
"@rollup/rollup-darwin-x64": "4.50.1",
|
||||
"@rollup/rollup-freebsd-arm64": "4.50.1",
|
||||
"@rollup/rollup-freebsd-x64": "4.50.1",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.50.1",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.50.1",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.50.1",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.50.1",
|
||||
"@rollup/rollup-linux-loongarch64-gnu": "4.50.1",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.50.1",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.50.1",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.50.1",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.50.1",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.50.1",
|
||||
"@rollup/rollup-linux-x64-musl": "4.50.1",
|
||||
"@rollup/rollup-openharmony-arm64": "4.50.1",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.50.1",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.50.1",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.50.1",
|
||||
"@rollup/rollup-android-arm-eabi": "4.50.2",
|
||||
"@rollup/rollup-android-arm64": "4.50.2",
|
||||
"@rollup/rollup-darwin-arm64": "4.50.2",
|
||||
"@rollup/rollup-darwin-x64": "4.50.2",
|
||||
"@rollup/rollup-freebsd-arm64": "4.50.2",
|
||||
"@rollup/rollup-freebsd-x64": "4.50.2",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.50.2",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.50.2",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.50.2",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.50.2",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.50.2",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.50.2",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.50.2",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.50.2",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.50.2",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.50.2",
|
||||
"@rollup/rollup-linux-x64-musl": "4.50.2",
|
||||
"@rollup/rollup-openharmony-arm64": "4.50.2",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.50.2",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.50.2",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.50.2",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
@@ -4444,9 +4444,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
|
||||
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
|
||||
"version": "7.11.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.11.0.tgz",
|
||||
"integrity": "sha512-kt1ZriHTi7MU+Z/r9DOdAI3ONdaR3M3csEaRc6ewa4f4dTvX4cQCbJ4NkEn0ohE4hHtq85+PhPSTY+pO/1PwgA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -4469,16 +4469,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
|
||||
"version": "13.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
|
||||
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
"uuid": "dist-node/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache-lib": {
|
||||
|
||||
20
package.json
20
package.json
@@ -6,7 +6,7 @@
|
||||
"bin": {
|
||||
"claude-code-acp": "./dist/index.js"
|
||||
},
|
||||
"version": "0.4.0",
|
||||
"version": "0.4.2",
|
||||
"description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
|
||||
"main": "dist/index.js",
|
||||
"type": "module",
|
||||
@@ -40,21 +40,29 @@
|
||||
"sdk",
|
||||
"code"
|
||||
],
|
||||
"homepage": "https://github.com/zed-industries/claude-code-acp#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/zed-industries/claude-code-acp/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zed-industries/claude-code-acp.git"
|
||||
},
|
||||
"author": "Zed Industries",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/claude-code": "1.0.111",
|
||||
"@modelcontextprotocol/sdk": "1.17.4",
|
||||
"@zed-industries/agent-client-protocol": "0.2.0-alpha.8",
|
||||
"@anthropic-ai/claude-code": "1.0.113",
|
||||
"@modelcontextprotocol/sdk": "1.18.0",
|
||||
"@zed-industries/agent-client-protocol": "0.3.1",
|
||||
"diff": "8.0.2",
|
||||
"express": "5.1.0",
|
||||
"minimist": "1.2.8",
|
||||
"uuid": "11.1.0"
|
||||
"uuid": "13.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "5.0.3",
|
||||
"@types/minimist": "1.2.5",
|
||||
"@types/node": "24.3.1",
|
||||
"@types/node": "24.4.0",
|
||||
"@types/uuid": "10.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.43.0",
|
||||
"@typescript-eslint/parser": "8.43.0",
|
||||
|
||||
@@ -284,6 +284,24 @@ export class ClaudeAcpAgent implements Agent {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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 (
|
||||
typeof message.message.content === "string" &&
|
||||
message.message.content.includes("<local-command-stdout>")
|
||||
) {
|
||||
console.log(message.message.content);
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof message.message.content === "string" &&
|
||||
message.message.content.includes("<local-command-stderr>")
|
||||
) {
|
||||
console.error(message.message.content);
|
||||
break;
|
||||
}
|
||||
|
||||
if (
|
||||
message.message.model === "<synthetic>" &&
|
||||
message.message.content.length === 1 &&
|
||||
@@ -361,7 +379,6 @@ async function getAvailableSlashCommands(query: Query): Promise<AvailableCommand
|
||||
"bashes", // Modal
|
||||
"bug", // Modal
|
||||
"clear", // Escape Codes
|
||||
"compact", // Not supported via SDK?
|
||||
"config", // Modal
|
||||
"context", // Escape Codes
|
||||
"cost", // Escape Codes
|
||||
@@ -390,14 +407,14 @@ async function getAvailableSlashCommands(query: Query): Promise<AvailableCommand
|
||||
"todos", // Escape Codes
|
||||
"vim", // Not needed
|
||||
];
|
||||
//todo: Do not use `as any` once `supportedCommands` is exposed via the typescript interface
|
||||
const commands = await (query as any).supportedCommands();
|
||||
const commands = await query.supportedCommands();
|
||||
|
||||
return commands
|
||||
.map((command: { name: string; description: string; argumentHint: string }) => {
|
||||
.map((command) => {
|
||||
const input = command.argumentHint ? { hint: command.argumentHint } : null;
|
||||
return {
|
||||
name: command.name,
|
||||
// @ts-expect-error type in the ts interface
|
||||
description: command.description || "",
|
||||
input,
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ClaudeAcpAgent } from "./acp-agent.js";
|
||||
import { ClientCapabilities, TerminalOutputResponse } from "@zed-industries/agent-client-protocol";
|
||||
import * as diff from "diff";
|
||||
|
||||
import { sleep, unreachable } from "./utils.js";
|
||||
import { sleep, unreachable, extractLinesWithByteLimit } from "./utils.js";
|
||||
import { PermissionResult } from "@anthropic-ai/claude-code";
|
||||
|
||||
export const SYSTEM_REMINDER = `
|
||||
@@ -17,6 +17,8 @@ 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 unqualifiedToolNames = {
|
||||
read: "read",
|
||||
edit: "edit",
|
||||
@@ -68,8 +70,17 @@ In sessions with ${toolNames.read} always use it instead of Read as it contains
|
||||
offset: z
|
||||
.number()
|
||||
.optional()
|
||||
.describe("Which line to start reading from. Omit to start from the beginning."),
|
||||
limit: z.number().optional().describe("How many lines to read. Omit for the whole file."),
|
||||
.default(0)
|
||||
.describe(
|
||||
"Which line to start reading from (0-based). Omit to start from the beginning.",
|
||||
),
|
||||
linesToRead: 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.)`,
|
||||
),
|
||||
},
|
||||
annotations: {
|
||||
title: "Read file",
|
||||
@@ -92,18 +103,43 @@ In sessions with ${toolNames.read} always use it instead of Read as it contains
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
const content = await agent.readTextFile({
|
||||
sessionId,
|
||||
path: input.abs_path,
|
||||
limit: input.limit,
|
||||
line: input.offset,
|
||||
});
|
||||
|
||||
// Extract lines with byte limit enforcement
|
||||
const result = extractLinesWithByteLimit(
|
||||
content.content,
|
||||
input.offset ?? 0,
|
||||
input.linesToRead,
|
||||
defaults.maxFileSize,
|
||||
);
|
||||
|
||||
// Construct informative message about what was read
|
||||
let readInfo = "";
|
||||
if (input.offset > 0 || 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.actualEndLine}. `;
|
||||
}
|
||||
|
||||
if (result.wasLimited) {
|
||||
readInfo += `Continue with offset=${result.actualEndLine}.`;
|
||||
}
|
||||
|
||||
readInfo += "</file-read-info>";
|
||||
}
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: content.content + SYSTEM_REMINDER,
|
||||
text: result.content + readInfo + SYSTEM_REMINDER,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("ACP subprocess integration"
|
||||
|
||||
async writeTextFile(params: WriteTextFileRequest): Promise<WriteTextFileResponse> {
|
||||
this.files.set(params.path, params.content);
|
||||
return null;
|
||||
return {};
|
||||
}
|
||||
|
||||
async readTextFile(params: ReadTextFileRequest): Promise<ReadTextFileResponse> {
|
||||
@@ -191,6 +191,50 @@ describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("ACP subprocess integration"
|
||||
|
||||
expect(client.takeReceivedText()).toContain("Hello GPT-5");
|
||||
}, 30000);
|
||||
|
||||
it("/compact works", async () => {
|
||||
const { client, connection, newSessionResponse } = await setupTestSession(__dirname);
|
||||
|
||||
const commands = await client.availableCommandsPromise;
|
||||
|
||||
expect(commands).toContainEqual({
|
||||
description:
|
||||
"Clear conversation history but keep a summary in context. Optional: /compact [instructions for summarization]",
|
||||
input: {
|
||||
hint: "<optional custom summarization instructions>",
|
||||
},
|
||||
name: "compact",
|
||||
});
|
||||
|
||||
// Error case (no previous message)
|
||||
await connection.prompt({
|
||||
prompt: [{ type: "text", text: "/compact" }],
|
||||
sessionId: newSessionResponse.sessionId,
|
||||
});
|
||||
|
||||
expect(client.takeReceivedText()).toBe("");
|
||||
|
||||
// Send something
|
||||
await connection.prompt({
|
||||
prompt: [{ type: "text", text: "Hi" }],
|
||||
sessionId: newSessionResponse.sessionId,
|
||||
});
|
||||
// Clear response
|
||||
client.takeReceivedText();
|
||||
|
||||
// Test with instruction
|
||||
await connection.prompt({
|
||||
prompt: [
|
||||
{
|
||||
type: "text",
|
||||
text: "/compact greeting",
|
||||
},
|
||||
],
|
||||
sessionId: newSessionResponse.sessionId,
|
||||
});
|
||||
|
||||
expect(client.takeReceivedText()).toContain("");
|
||||
}, 30000);
|
||||
});
|
||||
|
||||
describe("tool conversions", () => {
|
||||
@@ -778,7 +822,10 @@ describe("tool conversions", () => {
|
||||
// Should return empty object when parsing fails
|
||||
expect(update).toEqual({
|
||||
content: [
|
||||
{ content: { type: "text", text: "Failed to find `old_string`" }, type: "content" },
|
||||
{
|
||||
content: { type: "text", text: "```\nFailed to find `old_string`\n```" },
|
||||
type: "content",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
174
src/tests/extract-lines.test.ts
Normal file
174
src/tests/extract-lines.test.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { extractLinesWithByteLimit } from "../utils.js";
|
||||
|
||||
describe("extractLinesWithByteLimit", () => {
|
||||
const simpleContent = "Line 1\nLine 2\nLine 3\nLine 4\nLine 5";
|
||||
|
||||
it("should extract all lines when under byte limit", () => {
|
||||
const result = extractLinesWithByteLimit(simpleContent, 0, 5, 1000);
|
||||
|
||||
expect(result.content).toBe(simpleContent);
|
||||
expect(result.actualEndLine).toBe(4);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
expect(result.linesRead).toBe(5);
|
||||
});
|
||||
|
||||
it("should extract partial lines with offset", () => {
|
||||
const result = extractLinesWithByteLimit(simpleContent, 2, 2, 1000);
|
||||
|
||||
expect(result.content).toBe("Line 3\nLine 4");
|
||||
expect(result.actualEndLine).toBe(3);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
expect(result.linesRead).toBe(2);
|
||||
});
|
||||
|
||||
it("should limit output when exceeding byte limit", () => {
|
||||
// Create content that will exceed byte limit
|
||||
const longLine = "x".repeat(100);
|
||||
const manyLines = Array(10).fill(longLine).join("\n");
|
||||
|
||||
const result = extractLinesWithByteLimit(manyLines, 0, 10, 250);
|
||||
|
||||
expect(result.wasLimited).toBe(true);
|
||||
expect(result.actualEndLine).toBe(1); // Should only get 2 lines
|
||||
expect(result.linesRead).toBe(2);
|
||||
});
|
||||
|
||||
it("should handle offset beyond file length", () => {
|
||||
const result = extractLinesWithByteLimit(simpleContent, 10, 5, 1000);
|
||||
|
||||
expect(result.content).toBe("");
|
||||
expect(result.actualEndLine).toBe(10);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
expect(result.linesRead).toBe(0);
|
||||
});
|
||||
|
||||
it("should handle empty content", () => {
|
||||
const result = extractLinesWithByteLimit("", 0, 10, 1000);
|
||||
|
||||
expect(result.content).toBe("");
|
||||
expect(result.actualEndLine).toBe(0); // Empty string splits to [""] and we process that one empty line
|
||||
expect(result.wasLimited).toBe(false);
|
||||
expect(result.linesRead).toBe(1); // We read the one empty line
|
||||
});
|
||||
|
||||
it("should handle single line file", () => {
|
||||
const singleLine = "This is a single line without newline";
|
||||
const result = extractLinesWithByteLimit(singleLine, 0, 10, 1000);
|
||||
|
||||
expect(result.content).toBe(singleLine);
|
||||
expect(result.actualEndLine).toBe(0);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
expect(result.linesRead).toBe(1);
|
||||
});
|
||||
|
||||
it("should correctly count bytes with multi-byte characters", () => {
|
||||
const unicodeContent = "Hello 世界\n你好 World\nEmoji: 🌍\nNormal line";
|
||||
const result = extractLinesWithByteLimit(unicodeContent, 0, 10, 1000);
|
||||
|
||||
expect(result.content).toBe(unicodeContent);
|
||||
expect(result.linesRead).toBe(4);
|
||||
});
|
||||
|
||||
it("should stop at byte limit even with one more line available", () => {
|
||||
// Create lines where adding one more would exceed limit
|
||||
const line1 = "a".repeat(40);
|
||||
const line2 = "b".repeat(40);
|
||||
const line3 = "c".repeat(40);
|
||||
const content = `${line1}\n${line2}\n${line3}`;
|
||||
|
||||
const result = extractLinesWithByteLimit(content, 0, 3, 85);
|
||||
|
||||
expect(result.content).toBe(`${line1}\n${line2}`);
|
||||
expect(result.actualEndLine).toBe(1);
|
||||
expect(result.wasLimited).toBe(true);
|
||||
expect(result.linesRead).toBe(2);
|
||||
});
|
||||
|
||||
it("should read exactly to limit when possible", () => {
|
||||
const exactContent = "12345\n67890\n12345"; // 17 bytes total
|
||||
const result = extractLinesWithByteLimit(exactContent, 0, 3, 17);
|
||||
|
||||
expect(result.content).toBe(exactContent);
|
||||
expect(result.actualEndLine).toBe(2);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
expect(result.linesRead).toBe(3);
|
||||
});
|
||||
|
||||
it("should handle reading from middle to end", () => {
|
||||
const result = extractLinesWithByteLimit(simpleContent, 3, 100, 1000);
|
||||
|
||||
expect(result.content).toBe("Line 4\nLine 5");
|
||||
expect(result.actualEndLine).toBe(4);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
expect(result.linesRead).toBe(2);
|
||||
});
|
||||
|
||||
it("should handle large content with typical parameters", () => {
|
||||
const longContent = Array(2000).fill("Line content here").join("\n");
|
||||
const result = extractLinesWithByteLimit(longContent, 0, 1000, 50000);
|
||||
|
||||
expect(result.actualEndLine).toBeLessThanOrEqual(1000); // Should be limited by line count
|
||||
});
|
||||
|
||||
it("should provide correct data for partial read at start", () => {
|
||||
const result = extractLinesWithByteLimit(simpleContent, 0, 2, 1000);
|
||||
|
||||
expect(result.actualEndLine).toBe(1);
|
||||
expect(result.linesRead).toBe(2);
|
||||
});
|
||||
|
||||
it("should provide correct data for partial read with offset", () => {
|
||||
const result = extractLinesWithByteLimit(simpleContent, 1, 2, 1000);
|
||||
|
||||
expect(result.actualEndLine).toBe(2);
|
||||
expect(result.linesRead).toBe(2);
|
||||
});
|
||||
|
||||
it("should not add newline after last line", () => {
|
||||
const result = extractLinesWithByteLimit("Line 1\nLine 2\nLine 3", 2, 1, 1000);
|
||||
|
||||
expect(result.content).toBe("Line 3"); // No trailing newline
|
||||
});
|
||||
|
||||
it("should handle Windows-style line endings", () => {
|
||||
const windowsContent = "Line 1\r\nLine 2\r\nLine 3";
|
||||
const result = extractLinesWithByteLimit(windowsContent, 0, 3, 1000);
|
||||
|
||||
// Note: split("\n") will keep the \r characters
|
||||
expect(result.content).toBe("Line 1\r\nLine 2\r\nLine 3");
|
||||
expect(result.linesRead).toBe(3);
|
||||
});
|
||||
|
||||
it("should handle very large files efficiently", () => {
|
||||
// Create a 100KB file
|
||||
const largeLine = "x".repeat(1000);
|
||||
const largeContent = Array(110).fill(largeLine).join("\n");
|
||||
|
||||
const result = extractLinesWithByteLimit(largeContent, 0, 200, 50000);
|
||||
|
||||
expect(result.wasLimited).toBe(true);
|
||||
expect(result.actualEndLine).toBeLessThan(50); // Should stop well before 200 lines
|
||||
});
|
||||
|
||||
it("should handle line limit of 0", () => {
|
||||
const result = extractLinesWithByteLimit(simpleContent, 0, 0, 1000);
|
||||
|
||||
expect(result.content).toBe("");
|
||||
expect(result.actualEndLine).toBe(0);
|
||||
expect(result.linesRead).toBe(0);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
});
|
||||
|
||||
it("should allow at least one line even if it exceeds byte limit", () => {
|
||||
const veryLongLine = "x".repeat(100000); // 100KB line
|
||||
const result = extractLinesWithByteLimit(veryLongLine, 0, 1, 50000);
|
||||
|
||||
// Should return the line even though it exceeds the byte limit
|
||||
// because we always allow at least one line if no lines have been added yet
|
||||
expect(result.content).toBe(veryLongLine);
|
||||
expect(result.actualEndLine).toBe(0);
|
||||
expect(result.linesRead).toBe(1);
|
||||
expect(result.wasLimited).toBe(false);
|
||||
});
|
||||
});
|
||||
19
src/tools.ts
19
src/tools.ts
@@ -487,7 +487,7 @@ export function toolUpdateFromToolResult(
|
||||
case "Write": {
|
||||
if (toolResult.is_error && toolResult.content?.length > 0) {
|
||||
// Only return errors
|
||||
return toAcpContentUpdate(toolResult.content);
|
||||
return toAcpContentUpdate(toolResult.content, true);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -511,17 +511,26 @@ export function toolUpdateFromToolResult(
|
||||
case "WebSearch":
|
||||
case "Other":
|
||||
default: {
|
||||
return toAcpContentUpdate(toolResult.content);
|
||||
return toAcpContentUpdate(toolResult.content, toolResult.is_error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toAcpContentUpdate(content: any): { content?: ToolCallContent[] } {
|
||||
function toAcpContentUpdate(
|
||||
content: any,
|
||||
isError: boolean = false,
|
||||
): { content?: ToolCallContent[] } {
|
||||
if (Array.isArray(content) && content.length > 0) {
|
||||
return {
|
||||
content: content.map((content: any) => ({
|
||||
type: "content",
|
||||
content,
|
||||
content:
|
||||
isError && content.type === "text"
|
||||
? {
|
||||
...content,
|
||||
text: `\`\`\`\n${content.text}\n\`\`\``,
|
||||
}
|
||||
: content,
|
||||
})),
|
||||
};
|
||||
} else if (typeof content === "string" && content.length > 0) {
|
||||
@@ -531,7 +540,7 @@ function toAcpContentUpdate(content: any): { content?: ToolCallContent[] } {
|
||||
type: "content",
|
||||
content: {
|
||||
type: "text",
|
||||
text: content,
|
||||
text: isError ? `\`\`\`\n${content}\n\`\`\`` : content,
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
110
src/utils.ts
110
src/utils.ts
@@ -122,3 +122,113 @@ export function applyEnvironmentSettings(settings: ManagedSettings): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExtractLinesResult {
|
||||
content: string;
|
||||
actualEndLine: number;
|
||||
wasLimited: boolean;
|
||||
linesRead: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts lines from file content with byte limit enforcement.
|
||||
*
|
||||
* @param fullContent - The complete file content
|
||||
* @param linesToSkip - Starting line number (0-based)
|
||||
* @param linesToRead - Maximum number of lines to read
|
||||
* @param maxContentLength - Maximum number of UTF-16 Code Units to return
|
||||
* @returns Object containing extracted content and metadata
|
||||
*/
|
||||
export function extractLinesWithByteLimit(
|
||||
fullContent: string,
|
||||
linesToSkip: number,
|
||||
linesToRead: number,
|
||||
maxContentLength: number,
|
||||
): ExtractLinesResult {
|
||||
if (fullContent === "" || linesToRead === 0) {
|
||||
if (linesToSkip === 0 && linesToRead > 0) {
|
||||
return {
|
||||
content: "",
|
||||
actualEndLine: 0,
|
||||
wasLimited: false,
|
||||
linesRead: 1,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
content: "",
|
||||
actualEndLine: linesToSkip,
|
||||
wasLimited: false,
|
||||
linesRead: 0,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
let linesSeen = 0;
|
||||
let index = 0;
|
||||
|
||||
while (linesSeen < linesToSkip) {
|
||||
const nextIndex = fullContent.indexOf("\n", index);
|
||||
|
||||
// There were not enough lines to skip.
|
||||
if (nextIndex < 0) {
|
||||
return {
|
||||
content: "",
|
||||
actualEndLine: linesToSkip,
|
||||
wasLimited: false,
|
||||
linesRead: 0,
|
||||
};
|
||||
}
|
||||
|
||||
linesSeen += 1;
|
||||
index = nextIndex + 1;
|
||||
}
|
||||
|
||||
// We've successfully skipped over all the lines we were supposed to.
|
||||
// Now we can actually start reading!
|
||||
const startIndex = index;
|
||||
linesSeen = 0;
|
||||
|
||||
let contentLength = 0;
|
||||
let wasLimited = false;
|
||||
|
||||
while (linesSeen < linesToRead) {
|
||||
const nextIndex = fullContent.indexOf("\n", index);
|
||||
|
||||
if (nextIndex < 0) {
|
||||
// Last line in file (no trailing newline)
|
||||
const newContentLength = fullContent.length - startIndex;
|
||||
if (linesSeen > 0 && newContentLength > maxContentLength) {
|
||||
wasLimited = true;
|
||||
break;
|
||||
}
|
||||
linesSeen += 1;
|
||||
contentLength = newContentLength;
|
||||
break;
|
||||
} else {
|
||||
// Line with newline - include up to the newline
|
||||
const newContentLength = nextIndex + 1 - startIndex;
|
||||
if (linesSeen > 0 && newContentLength > maxContentLength) {
|
||||
wasLimited = true;
|
||||
break;
|
||||
}
|
||||
linesSeen += 1;
|
||||
contentLength = newContentLength;
|
||||
index = nextIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// If we ended with a newline and we stopped due to byte limit or line limit (not end of file), remove the trailing newline
|
||||
if (contentLength > 0 && fullContent[startIndex + contentLength - 1] === "\n") {
|
||||
// Check if there's more content after our current position that we didn't read
|
||||
if (startIndex + contentLength < fullContent.length) {
|
||||
contentLength -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
content: fullContent.slice(startIndex, startIndex + contentLength),
|
||||
actualEndLine: linesSeen > 0 ? linesToSkip + linesSeen - 1 : linesToSkip,
|
||||
wasLimited,
|
||||
linesRead: linesSeen,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user