Compare commits

...

7 Commits

Author SHA1 Message Date
Bennet Bo Fenner
3b4cd4b2d5 Fix duplicate tool use IDs error (#198)
<img width="595" height="107" alt="image"
src="https://github.com/user-attachments/assets/3b9ae5e9-cbc8-425a-8cb6-1d201df3a812"
/>

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2025-12-09 22:00:38 +01:00
Ben Brandt
9320e05891 Update to claude-agent-sdk 0.1.61 (#195) 2025-12-08 12:17:49 +01:00
Ben Brandt
3f44543019 Unify ACP and Claude Code session ids (#193)
There have been some issues for folks because the session id we returned
for ACP wasn't the same as the session id for Claude Code.

Now, we pass it through to the `--session-id` flag of the Claude Code
CLI, which means both ACP and Claude Code are always referring to the
same UUID. Yay!
2025-12-05 15:14:16 +00:00
Ben Brandt
4db3d855bf Update to claude-agent-sdk v0.1.59 (#192) 2025-12-05 16:06:31 +01:00
Ben Brandt
e57893f6d0 Update to claude-agent-sdk 0.1.57 (#191) 2025-12-03 11:27:01 +00:00
Ben Brandt
6a93d7e786 Update to ACP SDK v0.7.0 (#188) 2025-12-01 17:45:24 +01:00
RAIT-09
c3c0f4da36 Prevent invalid locations when Read tool call has no file_path (#186)
## Summary

Follow-up to #121. The same issue (invalid locations when `file_path` is
undefined) existed in the `Read` tool case as well.

## Problem

The ACP spec requires `path` as a required field in `ToolCallLocation`.
PR #121 fixed this for `mcp__acp__Read`, but the same issue remained for
the `Read` tool case.

When Claude generates a Read tool call without `file_path`, the current
code produces an invalid notification:

```json
{
  "locations": [
    {
      "line": 0
    }
  ]
}
```

This causes the following error in the client:

```
Error handling notification
{code: -32602, message: 'Invalid params', data: {…}}
```

## Solution

Return an empty `locations` array when `input.file_path` is undefined,
consistent with the fix in #121.
2025-12-01 13:22:06 +01:00
7 changed files with 251 additions and 294 deletions

View File

@@ -1,5 +1,30 @@
# Changelog
## 0.12.2
- Fix duplicate tool use IDs error
## 0.12.1
- Update to @anthropic-ai/claude-agent-sdk@v0.1.61
- Update to @agentclientprotocol/sdk@0.8.0
## 0.12.0
- Update to @anthropic-ai/claude-agent-sdk@v0.1.59
- Brings Opus to Claude Pro plans
- Support "Don't Ask" profile
- Unify ACP + Claude Code session ids
## 0.11.0
- Update to @anthropic-ai/claude-agent-sdk@v0.1.57
- Removed dependency on @anthropic-ai/claude-code since this is no longer needed
## 0.10.10
- Update to @agentclientprotocol/sdk@0.7.0
## 0.10.9
- Update to @anthropic-ai/claude-agent-sdk@v0.1.55

349
package-lock.json generated
View File

@@ -1,52 +1,49 @@
{
"name": "@zed-industries/claude-code-acp",
"version": "0.10.9",
"version": "0.12.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@zed-industries/claude-code-acp",
"version": "0.10.9",
"version": "0.12.2",
"license": "Apache-2.0",
"dependencies": {
"@agentclientprotocol/sdk": "0.5.1",
"@anthropic-ai/claude-agent-sdk": "0.1.55",
"@anthropic-ai/claude-code": "2.0.55",
"@modelcontextprotocol/sdk": "1.23.0",
"diff": "8.0.2",
"uuid": "13.0.0"
"@agentclientprotocol/sdk": "0.8.0",
"@anthropic-ai/claude-agent-sdk": "0.1.61",
"@modelcontextprotocol/sdk": "1.24.3",
"diff": "8.0.2"
},
"bin": {
"claude-code-acp": "dist/index.js"
},
"devDependencies": {
"@anthropic-ai/sdk": "0.71.0",
"@anthropic-ai/sdk": "0.71.2",
"@types/node": "24.10.1",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "8.48.0",
"@typescript-eslint/parser": "8.48.0",
"@typescript-eslint/eslint-plugin": "8.48.1",
"@typescript-eslint/parser": "8.48.1",
"eslint": "9.39.1",
"eslint-config-prettier": "10.1.8",
"globals": "16.5.0",
"prettier": "3.7.1",
"prettier": "3.7.4",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vitest": "4.0.14"
"vitest": "4.0.15"
}
},
"node_modules/@agentclientprotocol/sdk": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.5.1.tgz",
"integrity": "sha512-9bq2TgjhLBSUSC5jE04MEe+Hqw8YePzKghhYZ9QcjOyonY3q2oJfX6GoSO83hURpEnsqEPIrex6VZN3+61fBJg==",
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.8.0.tgz",
"integrity": "sha512-RnYsrYqrGFNpPc/cgHgMPHjgn52F1tw5PWyr7UucQ2V1O72JWy3fCCkUgbbRgn7wbNVFsrEZMuBS186Mxgkhfg==",
"license": "Apache-2.0",
"dependencies": {
"zod": "^3.0.0"
"peerDependencies": {
"zod": "^3.25.0 || ^4.0.0"
}
},
"node_modules/@anthropic-ai/claude-agent-sdk": {
"version": "0.1.55",
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.1.55.tgz",
"integrity": "sha512-nwlxPjn/gc7I+iOGYY7AGtM2xcjzJFCxF9Bnr0xH1JNaNx+QXLM3h/wmzSvuEOKeJgPymf1GMBs4DZ3jyd/Z7Q==",
"version": "0.1.61",
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.1.61.tgz",
"integrity": "sha512-V0WlOMp56OetCeNoYMtvXSh6LmRYvoA69K16iaF7mXg8XYPZcrO2tuC8k8S8LWDUjoVjgg7EJYP1v/p0Ax2UPA==",
"license": "SEE LICENSE IN README.md",
"engines": {
"node": ">=18.0.0"
@@ -65,32 +62,10 @@
"zod": "^3.24.1"
}
},
"node_modules/@anthropic-ai/claude-code": {
"version": "2.0.55",
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-2.0.55.tgz",
"integrity": "sha512-IVY6J2KgTP5BiCbLmuP3kAl8jbXfd6yGoXtvc0L0eiZwxJUMa+cubUU0U8qHRnVkNmDAis+O4P00KmeuGzSLWg==",
"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-linuxmusl-arm64": "^0.33.5",
"@img/sharp-linuxmusl-x64": "^0.33.5",
"@img/sharp-win32-x64": "^0.33.5"
}
},
"node_modules/@anthropic-ai/sdk": {
"version": "0.71.0",
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.0.tgz",
"integrity": "sha512-go1XeWXmpxuiTkosSXpb8tokLk2ZLkIRcXpbWVwJM6gH5OBtHOVsfPfGuqI1oW7RRt4qc59EmYbrXRZ0Ng06Jw==",
"version": "0.71.2",
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.71.2.tgz",
"integrity": "sha512-TGNDEUuEstk/DKu0/TflXAEt+p+p/WhTlFzEnoosvbaDU2LTjm42igSdlL0VijrKpWejtOKxX0b8A7uc+XiSAQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -668,9 +643,9 @@
}
},
"node_modules/@eslint/eslintrc": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz",
"integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
"integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -680,7 +655,7 @@
"globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"js-yaml": "^4.1.1",
"minimatch": "^3.1.2",
"strip-json-comments": "^3.1.1"
},
@@ -1165,9 +1140,9 @@
}
},
"node_modules/@modelcontextprotocol/sdk": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.23.0.tgz",
"integrity": "sha512-MCGd4K9aZKvuSqdoBkdMvZNcYXCkZRYVs/Gh92mdV5IHbctX9H9uIvd4X93+9g8tBbXv08sxc/QHXTzf8y65bA==",
"version": "1.24.3",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.24.3.tgz",
"integrity": "sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==",
"license": "MIT",
"dependencies": {
"ajv": "^8.17.1",
@@ -1179,6 +1154,7 @@
"eventsource-parser": "^3.0.0",
"express": "^5.0.1",
"express-rate-limit": "^7.5.0",
"jose": "^6.1.1",
"pkce-challenge": "^5.0.0",
"raw-body": "^3.0.0",
"zod": "^3.25 || ^4.0",
@@ -1586,25 +1562,18 @@
"undici-types": "~7.16.0"
}
},
"node_modules/@types/uuid": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
"integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz",
"integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz",
"integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "8.48.0",
"@typescript-eslint/type-utils": "8.48.0",
"@typescript-eslint/utils": "8.48.0",
"@typescript-eslint/visitor-keys": "8.48.0",
"@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/type-utils": "8.48.1",
"@typescript-eslint/utils": "8.48.1",
"@typescript-eslint/visitor-keys": "8.48.1",
"graphemer": "^1.4.0",
"ignore": "^7.0.0",
"natural-compare": "^1.4.0",
@@ -1618,23 +1587,23 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.48.0",
"@typescript-eslint/parser": "^8.48.1",
"eslint": "^8.57.0 || ^9.0.0",
"typescript": ">=4.8.4 <6.0.0"
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz",
"integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz",
"integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.48.0",
"@typescript-eslint/types": "8.48.0",
"@typescript-eslint/typescript-estree": "8.48.0",
"@typescript-eslint/visitor-keys": "8.48.0",
"@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/types": "8.48.1",
"@typescript-eslint/typescript-estree": "8.48.1",
"@typescript-eslint/visitor-keys": "8.48.1",
"debug": "^4.3.4"
},
"engines": {
@@ -1650,14 +1619,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz",
"integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz",
"integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.48.0",
"@typescript-eslint/types": "^8.48.0",
"@typescript-eslint/tsconfig-utils": "^8.48.1",
"@typescript-eslint/types": "^8.48.1",
"debug": "^4.3.4"
},
"engines": {
@@ -1672,14 +1641,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz",
"integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz",
"integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.48.0",
"@typescript-eslint/visitor-keys": "8.48.0"
"@typescript-eslint/types": "8.48.1",
"@typescript-eslint/visitor-keys": "8.48.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1690,9 +1659,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz",
"integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz",
"integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1707,15 +1676,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz",
"integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz",
"integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.48.0",
"@typescript-eslint/typescript-estree": "8.48.0",
"@typescript-eslint/utils": "8.48.0",
"@typescript-eslint/types": "8.48.1",
"@typescript-eslint/typescript-estree": "8.48.1",
"@typescript-eslint/utils": "8.48.1",
"debug": "^4.3.4",
"ts-api-utils": "^2.1.0"
},
@@ -1732,9 +1701,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz",
"integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz",
"integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1746,16 +1715,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz",
"integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz",
"integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.48.0",
"@typescript-eslint/tsconfig-utils": "8.48.0",
"@typescript-eslint/types": "8.48.0",
"@typescript-eslint/visitor-keys": "8.48.0",
"@typescript-eslint/project-service": "8.48.1",
"@typescript-eslint/tsconfig-utils": "8.48.1",
"@typescript-eslint/types": "8.48.1",
"@typescript-eslint/visitor-keys": "8.48.1",
"debug": "^4.3.4",
"minimatch": "^9.0.4",
"semver": "^7.6.0",
@@ -1774,16 +1743,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz",
"integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz",
"integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.7.0",
"@typescript-eslint/scope-manager": "8.48.0",
"@typescript-eslint/types": "8.48.0",
"@typescript-eslint/typescript-estree": "8.48.0"
"@typescript-eslint/scope-manager": "8.48.1",
"@typescript-eslint/types": "8.48.1",
"@typescript-eslint/typescript-estree": "8.48.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -1798,13 +1767,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.48.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz",
"integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==",
"version": "8.48.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz",
"integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.48.0",
"@typescript-eslint/types": "8.48.1",
"eslint-visitor-keys": "^4.2.1"
},
"engines": {
@@ -1829,16 +1798,16 @@
}
},
"node_modules/@vitest/expect": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.14.tgz",
"integrity": "sha512-RHk63V3zvRiYOWAV0rGEBRO820ce17hz7cI2kDmEdfQsBjT2luEKB5tCOc91u1oSQoUOZkSv3ZyzkdkSLD7lKw==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.15.tgz",
"integrity": "sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@standard-schema/spec": "^1.0.0",
"@types/chai": "^5.2.2",
"@vitest/spy": "4.0.14",
"@vitest/utils": "4.0.14",
"@vitest/spy": "4.0.15",
"@vitest/utils": "4.0.15",
"chai": "^6.2.1",
"tinyrainbow": "^3.0.3"
},
@@ -1847,13 +1816,13 @@
}
},
"node_modules/@vitest/mocker": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.14.tgz",
"integrity": "sha512-RzS5NujlCzeRPF1MK7MXLiEFpkIXeMdQ+rN3Kk3tDI9j0mtbr7Nmuq67tpkOJQpgyClbOltCXMjLZicJHsH5Cg==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.15.tgz",
"integrity": "sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/spy": "4.0.14",
"@vitest/spy": "4.0.15",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.21"
},
@@ -1874,9 +1843,9 @@
}
},
"node_modules/@vitest/pretty-format": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.14.tgz",
"integrity": "sha512-SOYPgujB6TITcJxgd3wmsLl+wZv+fy3av2PpiPpsWPZ6J1ySUYfScfpIt2Yv56ShJXR2MOA6q2KjKHN4EpdyRQ==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.15.tgz",
"integrity": "sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1887,13 +1856,13 @@
}
},
"node_modules/@vitest/runner": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.14.tgz",
"integrity": "sha512-BsAIk3FAqxICqREbX8SetIteT8PiaUL/tgJjmhxJhCsigmzzH8xeadtp7LRnTpCVzvf0ib9BgAfKJHuhNllKLw==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.15.tgz",
"integrity": "sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/utils": "4.0.14",
"@vitest/utils": "4.0.15",
"pathe": "^2.0.3"
},
"funding": {
@@ -1901,13 +1870,13 @@
}
},
"node_modules/@vitest/snapshot": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.14.tgz",
"integrity": "sha512-aQVBfT1PMzDSA16Y3Fp45a0q8nKexx6N5Amw3MX55BeTeZpoC08fGqEZqVmPcqN0ueZsuUQ9rriPMhZ3Mu19Ag==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.15.tgz",
"integrity": "sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/pretty-format": "4.0.14",
"@vitest/pretty-format": "4.0.15",
"magic-string": "^0.30.21",
"pathe": "^2.0.3"
},
@@ -1916,9 +1885,9 @@
}
},
"node_modules/@vitest/spy": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.14.tgz",
"integrity": "sha512-JmAZT1UtZooO0tpY3GRyiC/8W7dCs05UOq9rfsUUgEZEdq+DuHLmWhPsrTt0TiW7WYeL/hXpaE07AZ2RCk44hg==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.15.tgz",
"integrity": "sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==",
"dev": true,
"license": "MIT",
"funding": {
@@ -1926,13 +1895,13 @@
}
},
"node_modules/@vitest/utils": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.14.tgz",
"integrity": "sha512-hLqXZKAWNg8pI+SQXyXxWCTOpA3MvsqcbVeNgSi8x/CSN2wi26dSzn1wrOhmCmFjEvN9p8/kLFRHa6PI8jHazw==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.15.tgz",
"integrity": "sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/pretty-format": "4.0.14",
"@vitest/pretty-format": "4.0.15",
"tinyrainbow": "^3.0.3"
},
"funding": {
@@ -2754,19 +2723,20 @@
}
},
"node_modules/express": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"license": "MIT",
"peer": true,
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.0",
"body-parser": "^2.2.1",
"content-disposition": "^1.0.0",
"content-type": "^1.0.5",
"cookie": "^0.7.1",
"cookie-signature": "^1.2.1",
"debug": "^4.4.0",
"depd": "^2.0.0",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
@@ -2879,9 +2849,9 @@
}
},
"node_modules/finalhandler": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
@@ -2892,7 +2862,11 @@
"statuses": "^2.0.1"
},
"engines": {
"node": ">= 0.8"
"node": ">= 18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/find-up": {
@@ -3214,6 +3188,15 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
"node_modules/jose": {
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/jose/-/jose-6.1.3.tgz",
"integrity": "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/panva"
}
},
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
@@ -3668,9 +3651,9 @@
}
},
"node_modules/prettier": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.1.tgz",
"integrity": "sha512-RWKXE4qB3u5Z6yz7omJkjWwmTfLdcbv44jUVHC5NpfXwFGzvpQM798FGv/6WNK879tc+Cn0AAyherCl1KjbyZQ==",
"version": "3.7.4",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.7.4.tgz",
"integrity": "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==",
"dev": true,
"license": "MIT",
"bin": {
@@ -4051,11 +4034,14 @@
"license": "MIT"
},
"node_modules/tinyexec": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz",
"integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz",
"integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
"dev": true,
"license": "MIT"
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/tinyglobby": {
"version": "0.2.15",
@@ -4235,19 +4221,6 @@
"punycode": "^2.1.0"
}
},
"node_modules/uuid": {
"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-node/bin/uuid"
}
},
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
@@ -4265,9 +4238,9 @@
}
},
"node_modules/vite": {
"version": "7.2.4",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz",
"integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==",
"version": "7.2.7",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.2.7.tgz",
"integrity": "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -4341,19 +4314,19 @@
}
},
"node_modules/vitest": {
"version": "4.0.14",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.14.tgz",
"integrity": "sha512-d9B2J9Cm9dN9+6nxMnnNJKJCtcyKfnHj15N6YNJfaFHRLua/d3sRKU9RuKmO9mB0XdFtUizlxfz/VPbd3OxGhw==",
"version": "4.0.15",
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.15.tgz",
"integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@vitest/expect": "4.0.14",
"@vitest/mocker": "4.0.14",
"@vitest/pretty-format": "4.0.14",
"@vitest/runner": "4.0.14",
"@vitest/snapshot": "4.0.14",
"@vitest/spy": "4.0.14",
"@vitest/utils": "4.0.14",
"@vitest/expect": "4.0.15",
"@vitest/mocker": "4.0.15",
"@vitest/pretty-format": "4.0.15",
"@vitest/runner": "4.0.15",
"@vitest/snapshot": "4.0.15",
"@vitest/spy": "4.0.15",
"@vitest/utils": "4.0.15",
"es-module-lexer": "^1.7.0",
"expect-type": "^1.2.2",
"magic-string": "^0.30.21",
@@ -4362,7 +4335,7 @@
"picomatch": "^4.0.3",
"std-env": "^3.10.0",
"tinybench": "^2.9.0",
"tinyexec": "^0.3.2",
"tinyexec": "^1.0.2",
"tinyglobby": "^0.2.15",
"tinyrainbow": "^3.0.3",
"vite": "^6.0.0 || ^7.0.0",
@@ -4381,10 +4354,10 @@
"@edge-runtime/vm": "*",
"@opentelemetry/api": "^1.9.0",
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
"@vitest/browser-playwright": "4.0.14",
"@vitest/browser-preview": "4.0.14",
"@vitest/browser-webdriverio": "4.0.14",
"@vitest/ui": "4.0.14",
"@vitest/browser-playwright": "4.0.15",
"@vitest/browser-preview": "4.0.15",
"@vitest/browser-webdriverio": "4.0.15",
"@vitest/ui": "4.0.15",
"happy-dom": "*",
"jsdom": "*"
},

View File

@@ -3,7 +3,7 @@
"publishConfig": {
"access": "public"
},
"version": "0.10.9",
"version": "0.12.2",
"description": "An ACP-compatible coding agent powered by the Claude Code SDK (TypeScript)",
"main": "dist/lib.js",
"bin": {
@@ -51,25 +51,22 @@
"author": "Zed Industries",
"license": "Apache-2.0",
"dependencies": {
"@agentclientprotocol/sdk": "0.5.1",
"@anthropic-ai/claude-agent-sdk": "0.1.55",
"@anthropic-ai/claude-code": "2.0.55",
"@modelcontextprotocol/sdk": "1.23.0",
"diff": "8.0.2",
"uuid": "13.0.0"
"@agentclientprotocol/sdk": "0.8.0",
"@anthropic-ai/claude-agent-sdk": "0.1.61",
"@modelcontextprotocol/sdk": "1.24.3",
"diff": "8.0.2"
},
"devDependencies": {
"@anthropic-ai/sdk": "0.71.0",
"@anthropic-ai/sdk": "0.71.2",
"@types/node": "24.10.1",
"@types/uuid": "10.0.0",
"@typescript-eslint/eslint-plugin": "8.48.0",
"@typescript-eslint/parser": "8.48.0",
"@typescript-eslint/eslint-plugin": "8.48.1",
"@typescript-eslint/parser": "8.48.1",
"eslint": "9.39.1",
"eslint-config-prettier": "10.1.8",
"globals": "16.5.0",
"prettier": "3.7.1",
"prettier": "3.7.4",
"ts-node": "10.9.2",
"typescript": "5.9.3",
"vitest": "4.0.14"
"vitest": "4.0.15"
}
}

View File

@@ -16,6 +16,7 @@ import {
ReadTextFileResponse,
RequestError,
SessionModelState,
SessionNotification,
SetSessionModelRequest,
SetSessionModelResponse,
SetSessionModeRequest,
@@ -38,9 +39,7 @@ import {
import * as fs from "node:fs";
import * as path from "node:path";
import * as os from "node:os";
import { v7 as uuidv7 } from "uuid";
import { nodeToWebReadable, nodeToWebWritable, Pushable, unreachable } from "./utils.js";
import { SessionNotification } from "@agentclientprotocol/sdk";
import { createMcpServer, EDIT_TOOL_NAMES, toolNames } from "./mcp-server.js";
import {
toolInfoFromToolUse,
@@ -53,6 +52,7 @@ import {
import { ContentBlockParam } from "@anthropic-ai/sdk/resources";
import { BetaContentBlock, BetaRawContentBlockDelta } from "@anthropic-ai/sdk/resources/beta.mjs";
import packageJson from "../package.json" with { type: "json" };
import { randomUUID } from "node:crypto";
/**
* Logger interface for customizing logging output
@@ -197,7 +197,7 @@ export class ClaudeAcpAgent implements Agent {
throw RequestError.authRequired();
}
const sessionId = uuidv7();
const sessionId = randomUUID();
const input = new Pushable<SDKUserMessage>();
const mcpServers: Record<string, McpServerConfig> = {};
@@ -262,6 +262,8 @@ export class ClaudeAcpAgent implements Agent {
cwd: params.cwd,
includePartialMessages: true,
mcpServers: { ...(userProvidedOptions?.mcpServers || {}), ...mcpServers },
// Set our own session id
extraArgs: { ...userProvidedOptions?.extraArgs, "session-id": sessionId },
// If we want bypassPermissions to be an option, we have to allow it here.
// But it doesn't work in root mode, so we only activate it if it will work.
allowDangerouslySkipPermissions: !IS_ROOT,
@@ -373,18 +375,23 @@ export class ClaudeAcpAgent implements Agent {
const availableModes = [
{
id: "default",
name: "Always Ask",
description: "Prompts for permission on first use of each tool",
name: "Default",
description: "Standard behavior, prompts for dangerous operations",
},
{
id: "acceptEdits",
name: "Accept Edits",
description: "Automatically accepts file edit permissions for the session",
description: "Auto-accept file edit operations",
},
{
id: "plan",
name: "Plan Mode",
description: "Claude can analyze but not modify files or execute commands",
description: "Planning mode, no actual tool execution",
},
{
id: "dontAsk",
name: "Don't Ask",
description: "Don't prompt for permissions, deny if not pre-approved",
},
];
// Only works in non-root mode
@@ -392,7 +399,7 @@ export class ClaudeAcpAgent implements Agent {
availableModes.push({
id: "bypassPermissions",
name: "Bypass Permissions",
description: "Skips all permission prompts",
description: "Bypass all permission checks",
});
}
@@ -595,6 +602,7 @@ export class ClaudeAcpAgent implements Agent {
case "default":
case "acceptEdits":
case "bypassPermissions":
case "dontAsk":
case "plan":
this.sessions[params.sessionId].permissionMode = params.modeId;
try {
@@ -626,7 +634,7 @@ export class ClaudeAcpAgent implements Agent {
}
canUseTool(sessionId: string): CanUseTool {
return async (toolName, toolInput, { suggestions, toolUseID }) => {
return async (toolName, toolInput, { signal, suggestions, toolUseID }) => {
const session = this.sessions[sessionId];
if (!session) {
return {
@@ -659,6 +667,9 @@ export class ClaudeAcpAgent implements Agent {
},
});
if (signal.aborted || response.outcome?.outcome === "cancelled") {
throw new Error("Tool use aborted");
}
if (
response.outcome?.outcome === "selected" &&
(response.outcome.optionId === "default" || response.outcome.optionId === "acceptEdits")
@@ -722,6 +733,9 @@ export class ClaudeAcpAgent implements Agent {
).title,
},
});
if (signal.aborted || response.outcome?.outcome === "cancelled") {
throw new Error("Tool use aborted");
}
if (
response.outcome?.outcome === "selected" &&
(response.outcome.optionId === "allow" || response.outcome.optionId === "allow_always")

View File

@@ -20,6 +20,7 @@ import { nodeToWebWritable, nodeToWebReadable } from "../utils.js";
import { markdownEscape, toolInfoFromToolUse, toolUpdateFromToolResult } from "../tools.js";
import { toAcpNotifications, promptToClaude } from "../acp-agent.js";
import { query, SDKAssistantMessage } from "@anthropic-ai/claude-agent-sdk";
import { randomUUID } from "crypto";
describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("ACP subprocess integration", () => {
let child: ReturnType<typeof spawn>;
@@ -830,17 +831,29 @@ describe("prompt conversion", () => {
});
});
describe("SDK behavior", () => {
it.skipIf(!process.env.RUN_INTEGRATION_TESTS)(
"query has a 'default' model",
async () => {
const q = query({ prompt: "hi" });
const models = await q.supportedModels();
const defaultModel = models.find((m) => m.value === "default");
expect(defaultModel).toBeDefined();
},
10000,
);
describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("SDK behavior", () => {
it("query has a 'default' model", async () => {
const q = query({ prompt: "hi" });
const models = await q.supportedModels();
const defaultModel = models.find((m) => m.value === "default");
expect(defaultModel).toBeDefined();
}, 10000);
it("custom session id", async () => {
const sessionId = randomUUID();
const q = query({
prompt: "hi",
options: {
systemPrompt: { type: "preset", preset: "claude_code" },
extraArgs: { "session-id": sessionId },
settingSources: ["user", "project", "local"],
includePartialMessages: true,
},
});
const { value } = await q.next();
expect(value).toMatchObject({ type: "system", subtype: "init", session_id: sessionId });
}, 10000);
});
describe("permission requests", () => {

View File

@@ -1,72 +0,0 @@
import { describe, expect, it, vi } from "vitest";
import { createMcpServer } from "../mcp-server.js";
const SESSION_ID = "session-id";
function getTool(server: any, name: string) {
const tools = server?._registeredTools;
if (!tools || !tools[name]) {
throw new Error(`Tool ${name} not registered`);
}
return tools[name];
}
function createAgent(overrides: Record<string, unknown> = {}) {
return {
sessions: {
[SESSION_ID]: {},
},
readTextFile: vi.fn(),
writeTextFile: vi.fn(),
backgroundTerminals: {},
clientCapabilities: {},
client: {
sessionUpdate: vi.fn(),
createTerminal: vi.fn(),
requestPermission: vi.fn(),
},
...overrides,
};
}
describe("MCP server read-related tools", () => {
it("reports missing file contents instead of crashing the read tool", async () => {
const agent = createAgent();
agent.readTextFile.mockResolvedValue({});
const server = createMcpServer(agent as any, SESSION_ID, {
fs: { readTextFile: true },
});
const readTool = getTool(server, "Read");
const result = await readTool.callback({
file_path: "/tmp/file.txt",
offset: 1,
limit: 2000,
});
expect(result.content[0].text).toBe("Reading file failed: No file contents for /tmp/file.txt.");
});
it("reports missing contents inside the edit tool and skips writes", async () => {
const agent = createAgent();
agent.readTextFile.mockResolvedValue({});
const server = createMcpServer(agent as any, SESSION_ID, {
fs: { readTextFile: true, writeTextFile: true },
});
const editTool = getTool(server, "Edit");
const result = await editTool.callback({
file_path: "/tmp/file.txt",
old_string: "foo",
new_string: "bar",
replace_all: false,
});
expect(result.content[0].text).toBe("Editing file failed: No file contents for /tmp/file.txt.");
expect(agent.writeTextFile).not.toHaveBeenCalled();
});
});

View File

@@ -134,7 +134,14 @@ export function toolInfoFromToolUse(
title: "Read File",
kind: "read",
content: [],
locations: [{ path: input.file_path, line: input.offset ?? 0 }],
locations: input.file_path
? [
{
path: input.file_path,
line: input.offset ?? 0,
},
]
: [],
};
case "LS":