mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-11-06 17:31:36 +00:00
Compare commits
27 Commits
v0.99.1
...
fix/subage
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
198a189e27 | ||
|
|
ba162346c9 | ||
|
|
85aec26ef9 | ||
|
|
7ea9eec839 | ||
|
|
a79d07324d | ||
|
|
1d4418f80d | ||
|
|
21d24f9e8b | ||
|
|
e3f0b6c89c | ||
|
|
8bbdea6cc6 | ||
|
|
1e986b526d | ||
|
|
53e3eec013 | ||
|
|
981bf9a28a | ||
|
|
4d79b9ffbc | ||
|
|
5565259771 | ||
|
|
720bbb3e4c | ||
|
|
38cf656fc9 | ||
|
|
1d0306468b | ||
|
|
c6de68797b | ||
|
|
eb78afa855 | ||
|
|
d2ef490a31 | ||
|
|
f50598a39c | ||
|
|
3bc671193c | ||
|
|
c3428de1bf | ||
|
|
1d2b92feae | ||
|
|
99a6e76158 | ||
|
|
e01a288384 | ||
|
|
2fd46c866d |
125
.github/workflows/binaries.yml
vendored
Normal file
125
.github/workflows/binaries.yml
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
# Builds the standalone executables (scripts/build-binary.mjs) and smoke-tests
|
||||
# each one on a runner of its own platform. Each archive holds
|
||||
# `claude-agent-acp` and the Claude CLI (`claude`) it runs from its directory.
|
||||
# CI calls this to check that every target still builds and starts; the
|
||||
# release calls it with `upload: true` and attaches the archives to the GitHub
|
||||
# release.
|
||||
name: Binaries
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
upload:
|
||||
description: Upload each archive as a workflow artifact for the release job.
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Binary (${{ matrix.target }})
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 20
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- target: bun-linux-x64
|
||||
runner: ubuntu-latest
|
||||
archive: claude-agent-acp-linux-x64.tar.gz
|
||||
- target: bun-linux-arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
archive: claude-agent-acp-linux-arm64.tar.gz
|
||||
# npm skips the musl package on a glibc host, so these are
|
||||
# cross-built and smoke-tested in an Alpine container.
|
||||
- target: bun-linux-x64-musl
|
||||
runner: ubuntu-latest
|
||||
archive: claude-agent-acp-linux-x64-musl.tar.gz
|
||||
musl: true
|
||||
- target: bun-linux-arm64-musl
|
||||
runner: ubuntu-24.04-arm
|
||||
archive: claude-agent-acp-linux-arm64-musl.tar.gz
|
||||
musl: true
|
||||
- target: bun-darwin-x64
|
||||
runner: macos-15-intel
|
||||
archive: claude-agent-acp-darwin-x64.zip
|
||||
- target: bun-darwin-arm64
|
||||
runner: macos-latest
|
||||
archive: claude-agent-acp-darwin-arm64.zip
|
||||
- target: bun-windows-x64
|
||||
runner: windows-latest
|
||||
archive: claude-agent-acp-windows-x64.zip
|
||||
- target: bun-windows-arm64
|
||||
runner: windows-11-arm
|
||||
archive: claude-agent-acp-windows-arm64.zip
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||
|
||||
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1
|
||||
with:
|
||||
node-version: "lts/*"
|
||||
check-latest: true
|
||||
cache: "npm"
|
||||
|
||||
# Unpinned: each build is smoke-tested on its platform before it uploads,
|
||||
# so a Bun release that breaks the executable fails here instead of
|
||||
# shipping. Pin a version if one ever regresses past the smoke test.
|
||||
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
||||
with:
|
||||
bun-version: latest
|
||||
|
||||
- run: npm ci
|
||||
|
||||
- name: Install the musl Claude CLI package
|
||||
if: ${{ matrix.musl }}
|
||||
run: |
|
||||
version="$(node -p "require('./node_modules/@anthropic-ai/claude-agent-sdk/package.json').version")"
|
||||
npm install --no-save --force "@anthropic-ai/claude-agent-sdk-linux-${RUNNER_ARCH,,}-musl@$version"
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
echo "Built \`${{ matrix.target }}\` with Bun $(bun --version)" >> "$GITHUB_STEP_SUMMARY"
|
||||
node scripts/build-binary.mjs --target ${{ matrix.target }}
|
||||
|
||||
- name: Smoke test
|
||||
if: ${{ !matrix.musl }}
|
||||
run: node scripts/smoke-binary.mjs
|
||||
|
||||
# Claude Code's Alpine requirements: libgcc and libstdc++.
|
||||
- name: Smoke test (Alpine)
|
||||
if: ${{ matrix.musl }}
|
||||
run: |
|
||||
docker run --rm -v "$PWD:/work" -w /work node:lts-alpine \
|
||||
sh -c 'apk add --no-cache libgcc libstdc++ >/dev/null && node scripts/smoke-binary.mjs'
|
||||
|
||||
- name: Archive
|
||||
if: ${{ inputs.upload }}
|
||||
env:
|
||||
ARCHIVE: ${{ matrix.archive }}
|
||||
run: |
|
||||
cd dist-bin
|
||||
if [[ "$ARCHIVE" == *.zip ]]; then
|
||||
if [[ "$RUNNER_OS" == "Windows" ]]; then
|
||||
pwsh -Command "Compress-Archive -Path claude-agent-acp.exe,claude.exe -DestinationPath ../$ARCHIVE"
|
||||
else
|
||||
zip "../$ARCHIVE" claude-agent-acp claude
|
||||
fi
|
||||
else
|
||||
tar czf "../$ARCHIVE" claude-agent-acp claude
|
||||
fi
|
||||
|
||||
- name: Upload
|
||||
if: ${{ inputs.upload }}
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
name: ${{ matrix.archive }}
|
||||
path: ${{ matrix.archive }}
|
||||
retention-days: 7
|
||||
if-no-files-found: error
|
||||
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -44,3 +44,7 @@ jobs:
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test:run
|
||||
|
||||
binaries:
|
||||
name: Binaries
|
||||
uses: ./.github/workflows/binaries.yml
|
||||
|
||||
38
.github/workflows/publish.yml
vendored
38
.github/workflows/publish.yml
vendored
@@ -88,6 +88,38 @@ jobs:
|
||||
npm publish
|
||||
echo "version=$version" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# Standalone executables for the GitHub release, stable releases only. They
|
||||
# don't gate the npm publish: a failed build leaves the release without
|
||||
# binaries, and re-running the failed jobs attaches them.
|
||||
build-binaries:
|
||||
name: Build binaries
|
||||
needs: [release-please]
|
||||
if: ${{ needs.release-please.outputs.release_created == 'true' }}
|
||||
# The called workflow only reads the repository; upload-binaries does the write.
|
||||
permissions:
|
||||
contents: read
|
||||
uses: ./.github/workflows/binaries.yml
|
||||
with:
|
||||
upload: true
|
||||
|
||||
upload-binaries:
|
||||
name: Attach binaries to the release
|
||||
runs-on: ubuntu-latest
|
||||
needs: [release-please, build-binaries]
|
||||
permissions:
|
||||
contents: write
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
|
||||
with:
|
||||
path: artifacts
|
||||
merge-multiple: true
|
||||
- name: Upload to the release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG: ${{ needs.release-please.outputs.tag_name }}
|
||||
run: gh release upload "$TAG" artifacts/* --clobber --repo "$GITHUB_REPOSITORY"
|
||||
|
||||
# Same shape as publish-npm. Tagging is a separate job, so nothing here needs
|
||||
# write access to the repository.
|
||||
publish-npm-preview:
|
||||
@@ -199,7 +231,11 @@ jobs:
|
||||
echo "Tagged \`v$VERSION\` at \`$SHA\`" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
trigger-registry-update:
|
||||
needs: [publish-npm, publish-npm-preview]
|
||||
# upload-binaries too, so a stable release's archives are attached before the
|
||||
# registry reads the release: it takes each archive's sha256 from the release
|
||||
# assets when it bumps the version. It only waits; a failed or skipped upload
|
||||
# (every preview) doesn't stop the dispatch.
|
||||
needs: [publish-npm, publish-npm-preview, upload-binaries]
|
||||
# Both channels dispatch this: the registry has its own handling for preview
|
||||
# versions. The two never fire together — a release merge publishes stable and
|
||||
# skips the preview, and every other push does the reverse — so the registry sees
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -3,4 +3,5 @@ dist
|
||||
.DS_Store
|
||||
.claude/*.local.*
|
||||
CLAUDE.local.md
|
||||
.idea/
|
||||
.idea/
|
||||
dist-bin
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
".": "0.99.1"
|
||||
".": "0.101.0"
|
||||
}
|
||||
|
||||
84
AGENTS.md
84
AGENTS.md
@@ -16,13 +16,85 @@ npm run format # prettier --write
|
||||
CI runs `format:check`, `lint`, `build` and `test:run`. Run `npm run check` before
|
||||
opening a PR.
|
||||
|
||||
## Code comments
|
||||
## Coding guidelines
|
||||
|
||||
Keep comments straightforward, concise, and concrete. Say what the code does and
|
||||
why, in plain terms: name the actual state, call, or failure involved instead of
|
||||
alluding to it. Prefer a short concrete example over an abstract description.
|
||||
Don't use vague phrases like "keeps it honest" or "the residual case" that make
|
||||
the reader reconstruct the meaning.
|
||||
- Keep edits consistent with the surrounding code's formatting, naming and idioms.
|
||||
- Keep comments concise and concrete. Name the actual state, call or failure
|
||||
instead of alluding to it, prefer a short example over an abstract
|
||||
description, and avoid vague phrases like "keeps it honest". A comment or doc
|
||||
must be true on every code path it describes, and a doc that lists what a
|
||||
result omits or rejects must name the actual cases.
|
||||
- When a request can't be served, throw a `RequestError` whose message says what
|
||||
happened and what to do (e.g. "Try again when the turn ends"). Don't drop the
|
||||
request silently.
|
||||
- Don't report success for work you start without awaiting it. If the detached
|
||||
call can still refuse and its `.catch` only logs, check the refusal condition
|
||||
first or report the failure to the client.
|
||||
- A result must not depend on what an earlier call happened to cache. A request
|
||||
right after a restart, with cold caches, must return the same thing as one
|
||||
after a warm-up.
|
||||
- If code relies on an ordering or call sequence that nothing enforces (e.g. an
|
||||
echo arriving before the result), say so in a short comment.
|
||||
|
||||
## Architecture and design fit
|
||||
|
||||
- Before coding, read the code the change plugs into and find the module that
|
||||
owns the state or concept. Build on that module, not beside it.
|
||||
- Don't add new features or components to `acp-agent.ts`. If no existing module fits the new
|
||||
code cleanly, create a dedicated one that owns the feature's state and logic,
|
||||
and keep the change in `acp-agent.ts` to the calls that wire it in.
|
||||
- Prefer extending an existing mechanism over adding a new one, even if it takes
|
||||
a small refactor (moving a helper, generalizing a function). Add a parallel
|
||||
path, special case or flag only when the existing structure can't support the
|
||||
change.
|
||||
- Before writing new logic, check whether it already exists in a sibling handler
|
||||
of the same flow or in a helper that works with the same data, and reuse it.
|
||||
Paths that handle the same input must apply the same rules through the same
|
||||
code: the live stream and the `session/load` replay, the command list and
|
||||
command dispatch, `prompt` and `steer`. Two copies of one check drift apart.
|
||||
- Put guards, filters and cleanup in the module that owns the state, so every
|
||||
caller gets them. If guards, flags or fallbacks pile up in one place,
|
||||
restructure instead of adding another.
|
||||
- If a result is meant to match another request's output, reuse that request's
|
||||
logic.
|
||||
- The adapter serves ACP v1 and v2. A change that is not meant for one protocol
|
||||
version only must work correctly in both. `src/v2/` converts v2 requests to v1
|
||||
and reuses the v1 logic; keep v2-only differences in the conversion.
|
||||
- A session runs one turn at a time. "Claude is working" means `startTurn`'s
|
||||
check (an unsettled turn in `turnQueue`, or `foregroundWork` for the session);
|
||||
don't write a narrower one. Anything that sends `session/update` must go
|
||||
through the turn queue or be refused while the session is busy, or its output
|
||||
lands inside another turn. Keep the session marked busy across awaited network
|
||||
calls.
|
||||
- Don't branch on a local copy of state that Claude Code or a remote service
|
||||
owns: it goes stale when the other side changes. Have a command set the state
|
||||
the user asks for instead of toggling it.
|
||||
- A command or name the adapter adds must not shadow one that Claude Code or the
|
||||
user's own commands and skills already provide.
|
||||
- New optional request fields and `_meta` keys must not reject requests that
|
||||
were valid before.
|
||||
- If a workaround or new path is unavoidable (e.g. a Claude Code or SDK
|
||||
limitation), say why in a short code comment and in the PR description.
|
||||
|
||||
## Testing guidelines
|
||||
|
||||
- Before adding a test, search `src/tests/` for existing tests of the same API
|
||||
and scenario, and add to their file and `describe` block. Use the helpers in
|
||||
`helpers.ts` and `session-doubles.ts` instead of copying setup.
|
||||
- Don't add cases that take the same code path. Tests that differ only in input
|
||||
and expected output belong in one `it.each`. Don't repeat another test's
|
||||
assertions; assert only what this test is about.
|
||||
- Reach a state the shortest way (e.g. set `session.tornDown = true`) instead of
|
||||
driving a full flow with extra mocks, unless the flow is what you test.
|
||||
- Build test doubles from what the bundled Claude Code CLI really sends,
|
||||
including fields like `origin` it echoes back and fields it omits. A double
|
||||
simpler than the real message hides bugs. If unsure, check against the real
|
||||
CLI (`npm run test:integration`).
|
||||
- Cover both ACP v1 and v2 when a change affects what a client receives
|
||||
(updates, responses, replay). A change to internal logic only does not need
|
||||
its tests duplicated per version.
|
||||
- For each behavior the docs or comments promise, including what is omitted or
|
||||
rejected, have a test that would fail if it broke.
|
||||
|
||||
## Pull requests
|
||||
|
||||
|
||||
40
CHANGELOG.md
40
CHANGELOG.md
@@ -1,5 +1,45 @@
|
||||
# Changelog
|
||||
|
||||
## [0.101.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.100.0...v0.101.0) (2026-11-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* compact idle sessions before the prompt cache expires ([#1522](https://github.com/agentclientprotocol/claude-agent-acp/issues/1522)) ([a79d073](https://github.com/agentclientprotocol/claude-agent-acp/commit/a79d07324dc15808c94a889a3b60615cca5a9fbd)), closes [#1454](https://github.com/agentclientprotocol/claude-agent-acp/issues/1454) [#1518](https://github.com/agentclientprotocol/claude-agent-acp/issues/1518)
|
||||
* ship single-file executables built with bun ([#1524](https://github.com/agentclientprotocol/claude-agent-acp/issues/1524)) ([e3f0b6c](https://github.com/agentclientprotocol/claude-agent-acp/commit/e3f0b6c89c783939e6ca8c19c220c21b58263f46))
|
||||
* start sessions in Auto mode by default ([#1533](https://github.com/agentclientprotocol/claude-agent-acp/issues/1533)) ([7ea9eec](https://github.com/agentclientprotocol/claude-agent-acp/commit/7ea9eec8392a43191b25a5c3636c181cc7eb42f3))
|
||||
* stream the output of v2 background commands ([#1512](https://github.com/agentclientprotocol/claude-agent-acp/issues/1512)) ([53e3eec](https://github.com/agentclientprotocol/claude-agent-acp/commit/53e3eec0134209654f53c46f319aaac851b8fff0))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* honor configured fallback for unavailable restored modes ([#1520](https://github.com/agentclientprotocol/claude-agent-acp/issues/1520)) ([8bbdea6](https://github.com/agentclientprotocol/claude-agent-acp/commit/8bbdea6cc62a7ae080cb73ff476ed28ad7574018))
|
||||
* update to @anthropic-ai/claude-agent-sdk 0.3.318 ([#1525](https://github.com/agentclientprotocol/claude-agent-acp/issues/1525)) ([1d4418f](https://github.com/agentclientprotocol/claude-agent-acp/commit/1d4418f80daf14c29cecc5b23286f52c7f0402ec))
|
||||
|
||||
## [0.100.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.99.1...v0.100.0) (2026-11-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* list v2 background tool calls ([#1511](https://github.com/agentclientprotocol/claude-agent-acp/issues/1511)) ([4d79b9f](https://github.com/agentclientprotocol/claude-agent-acp/commit/4d79b9ffbce95c23928a5dd771d6c87476d37160))
|
||||
* report subagent working directories ([#1496](https://github.com/agentclientprotocol/claude-agent-acp/issues/1496)) ([eb78afa](https://github.com/agentclientprotocol/claude-agent-acp/commit/eb78afa8556b8fc4082495e48e3fd1762fb6a50f))
|
||||
* report v2 background work ([#1510](https://github.com/agentclientprotocol/claude-agent-acp/issues/1510)) ([5565259](https://github.com/agentclientprotocol/claude-agent-acp/commit/5565259771cb74e3a9bdbacfcbce43e061d81422))
|
||||
* report why Claude Code could not start a session ([#1508](https://github.com/agentclientprotocol/claude-agent-acp/issues/1508)) ([38cf656](https://github.com/agentclientprotocol/claude-agent-acp/commit/38cf656fc9d80fec2d1a16c472779803e2c802d2))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* align session/cancel, session/close, and v2 setup with the ACP v2 spec ([#1494](https://github.com/agentclientprotocol/claude-agent-acp/issues/1494)) ([f50598a](https://github.com/agentclientprotocol/claude-agent-acp/commit/f50598a39c5dc3908d4b98a7213e01d63ea867d5))
|
||||
* forward v2 elicitation values and read dismissed v2 permission prompts as a refusal ([#1493](https://github.com/agentclientprotocol/claude-agent-acp/issues/1493)) ([3bc6711](https://github.com/agentclientprotocol/claude-agent-acp/commit/3bc671193c6456516fe05a0eaa53c17bdfb6a190))
|
||||
* keep native Windows paths in v2 git patches ([#1492](https://github.com/agentclientprotocol/claude-agent-acp/issues/1492)) ([c3428de](https://github.com/agentclientprotocol/claude-agent-acp/commit/c3428de1bf411c513b0703ddd56bb6c5fdff583c))
|
||||
* preserve live session settings across provider refreshes ([#1474](https://github.com/agentclientprotocol/claude-agent-acp/issues/1474)) ([e01a288](https://github.com/agentclientprotocol/claude-agent-acp/commit/e01a28838499dd6dd7c31e35708090b938e852c6))
|
||||
* reject unreadable skill manifests ([#1482](https://github.com/agentclientprotocol/claude-agent-acp/issues/1482)) ([99a6e76](https://github.com/agentclientprotocol/claude-agent-acp/commit/99a6e76158b9164e51bd62e3b89113beadea5ce2))
|
||||
* report the fresh context's usage when ExitPlanMode clears context ([#1484](https://github.com/agentclientprotocol/claude-agent-acp/issues/1484)) ([2fd46c8](https://github.com/agentclientprotocol/claude-agent-acp/commit/2fd46c866d4ff2939fe1b1245b15a536d6de7c0b))
|
||||
* update to @agentclientprotocol/sdk 2.2.0 ([#1491](https://github.com/agentclientprotocol/claude-agent-acp/issues/1491)) ([1d2b92f](https://github.com/agentclientprotocol/claude-agent-acp/commit/1d2b92feae5eeccde3ac738edca1f1d71250762e))
|
||||
* update to @agentclientprotocol/sdk 2.4.0 ([#1509](https://github.com/agentclientprotocol/claude-agent-acp/issues/1509)) ([720bbb3](https://github.com/agentclientprotocol/claude-agent-acp/commit/720bbb3e4c65874775a0bb9418799baf4b6e3680))
|
||||
* update to Claude Agent SDK 0.3.316 (Claude Code 2.1.316) ([#1507](https://github.com/agentclientprotocol/claude-agent-acp/issues/1507)) ([1d03064](https://github.com/agentclientprotocol/claude-agent-acp/commit/1d0306468b632c6a56b4fb076ad7a19f23d9e7b5))
|
||||
* validate session, prompt, config, and auth requests per the latest ACP spec ([#1495](https://github.com/agentclientprotocol/claude-agent-acp/issues/1495)) ([d2ef490](https://github.com/agentclientprotocol/claude-agent-acp/commit/d2ef490a318033049af00cb9164a39ac2dd1eb95))
|
||||
|
||||
## [0.99.1](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.99.0...v0.99.1) (2026-10-29)
|
||||
|
||||
|
||||
|
||||
25
README.md
25
README.md
@@ -36,6 +36,23 @@ To try changes that have landed on `main` but are not released yet, install from
|
||||
npm install @agentclientprotocol/claude-agent-acp@preview
|
||||
```
|
||||
|
||||
### Standalone executables
|
||||
|
||||
Each release attaches archives for Linux (glibc and musl), macOS and Windows, on
|
||||
x64 and arm64, to its [GitHub release](https://github.com/agentclientprotocol/claude-agent-acp/releases).
|
||||
They need no Node.js install. Each holds two files: `claude-agent-acp`, and the
|
||||
Claude CLI (`claude`) it runs. Keep them in the same directory; a symlink to
|
||||
`claude-agent-acp` elsewhere works. To use a Claude CLI you already have
|
||||
instead, set `CLAUDE_CODE_EXECUTABLE`. On Alpine, install `libgcc` and
|
||||
`libstdc++` first.
|
||||
|
||||
To build one for your machine (needs [Bun](https://bun.sh)) and check it:
|
||||
|
||||
```sh
|
||||
npm run build:binary
|
||||
npm run smoke:binary # add `-- --full` to drive a real session; needs a Claude login
|
||||
```
|
||||
|
||||
### Subagent sessions
|
||||
|
||||
A client that declares `clientCapabilities.subagents`, other than JetBrains AIR, gets each Agent or
|
||||
@@ -48,6 +65,14 @@ Task subagent as its own child session, following the [subagents RFD](https://gi
|
||||
`end_turn` or `cancelled` when the SDK gives the reason. A failure is `idle` with the `error`
|
||||
stop reason and the SDK's error text as its `error`. The child keeps its session for every
|
||||
delegation to it.
|
||||
- A child that runs outside its parent's working directory, such as an Agent call with
|
||||
`isolation: "worktree"`, gets its `cwd` on `subagent_update` before its first tool call. The
|
||||
adapter takes it from the `cwd` of the child's own hooks: its SubagentStart hook runs before its
|
||||
first model request. It sends `cwd: null` when the child is back in its parent's directory. A
|
||||
child in its parent's directory gets no `cwd`, and no child gets `additionalDirectories`: Claude
|
||||
Code gives a subagent the session's additional directories, so it inherits them. A replay
|
||||
announces a child with the `cwd` that its transcript recorded, and clears it after the response
|
||||
when that directory no longer exists.
|
||||
- Session messages replace the Agent or Task call that launches the child, which its parent is
|
||||
not shown:
|
||||
- The launch's prompt is a `session_message` in both transcripts: the parent's outgoing view and
|
||||
|
||||
@@ -7,7 +7,9 @@ keeps a single release PR open, titled `chore(main): release X.Y.Z` and labelled
|
||||
`autorelease: pending`.
|
||||
|
||||
Merging that PR is what releases. It tags `vX.Y.Z`, creates the GitHub release,
|
||||
publishes to npm, and dispatches a version update to the agent registry.
|
||||
publishes to npm, dispatches a version update to the agent registry, and
|
||||
attaches the [standalone executables](../README.md#standalone-executables) to
|
||||
the GitHub release. Previews get no executables.
|
||||
|
||||
There is no manual release button, and versions are never typed in by hand: the
|
||||
version is an output of the commit history, not an input.
|
||||
@@ -45,6 +47,9 @@ gh release view "v<version>"
|
||||
npm view "@agentclientprotocol/claude-agent-acp@<version>"
|
||||
```
|
||||
|
||||
The release should list 8 `claude-agent-acp-*` archives. They are attached a
|
||||
few minutes after the release is created, once every platform has built.
|
||||
|
||||
## Preview releases
|
||||
|
||||
Every push to `main` that is not a release merge publishes a preview from the
|
||||
@@ -203,6 +208,13 @@ npm versions are immutable. If the package already published and only the
|
||||
registry update failed, pass `-f publish_npm=false` so the run skips publishing
|
||||
and only re-dispatches the registry update.
|
||||
|
||||
### The release has no executables
|
||||
|
||||
`build-binaries` and `upload-binaries` don't gate npm, so a failed build only
|
||||
leaves the release without archives. Re-run the failed jobs of that publish run
|
||||
(`gh run rerun <run-id> --failed`); the upload uses `--clobber`, so archives
|
||||
already attached are replaced rather than duplicated.
|
||||
|
||||
### A preview published but the commit was not tagged
|
||||
|
||||
Only the publish is irreversible, so re-run just the tag job:
|
||||
|
||||
@@ -1569,7 +1569,7 @@ It is idempotent, and an unknown id also returns `{}`.
|
||||
`session/delete`:
|
||||
|
||||
- a `sessionIndex` client: deletes every transcript of the session (empty ones too) and every `<sessionId>/` directory, also one left without a transcript by an earlier failed delete. Anything left behind fails the request. A session that runs here is closed first. As with the CLI, the session is deleted also when another Claude Code process has it open. An unknown session is `-32002`.
|
||||
- an AIR client without `sessionIndex`: archives the session instead of deleting it (the title records of [Archive](#archive)), because AIR uses delete for "Done" and can reopen the session. A session that runs here is closed first. The list hides archived sessions from such a client too: those whose custom title, as the SDK list reports it, is archived. A session without a transcript fails with the error of the SDK delete, as before.
|
||||
- an AIR client without `sessionIndex`: archives the session instead of deleting it (the title records of [Archive](#archive)), because AIR uses delete for "Done" and can reopen the session. A session that runs here is closed first. The list hides archived sessions from such a client too: those whose custom title, as the SDK list reports it, is archived. A session without a transcript has nothing to archive, so the delete succeeds, as ACP asks of a session that does not exist.
|
||||
A `sessionIndex` client sees such a session as archived (`archived: true`), as AIR's native Claude path does.
|
||||
- any other client: the SDK delete. A session without a transcript (unknown, deleted before, or
|
||||
never prompted) succeeds, as ACP asks.
|
||||
@@ -1679,14 +1679,14 @@ For AIR, both forms carry `_meta.jetbrains.air.contextCompaction`:
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Meaning |
|
||||
| ------------ | --------------------------------------------------------------------- |
|
||||
| `version` | Must equal `1`. |
|
||||
| `trigger` | `manual` or `automatic`. |
|
||||
| `preTokens` | The context size before the compaction. |
|
||||
| `postTokens` | The context size after the compaction. |
|
||||
| `durationMs` | The duration of the compaction. |
|
||||
| `error` | The error of a failed compaction. Only the tool call form carries it. |
|
||||
| Field | Meaning |
|
||||
| ------------ | -------------------------------------------------------------------------------------------------------- |
|
||||
| `version` | Must equal `1`. |
|
||||
| `trigger` | `manual`, `automatic`, or `idle`: the adapter compacted an idle session before its prompt cache expired. |
|
||||
| `preTokens` | The context size before the compaction. |
|
||||
| `postTokens` | The context size after the compaction. |
|
||||
| `durationMs` | The duration of the compaction. |
|
||||
| `error` | The error of a failed compaction. Only the tool call form carries it. |
|
||||
|
||||
The standard `toolCallId` or `compactionId` and the `status` own the identity and the phase.
|
||||
The `compaction_update` form puts the error in the standard `error` field.
|
||||
|
||||
352
package-lock.json
generated
352
package-lock.json
generated
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"name": "@agentclientprotocol/claude-agent-acp",
|
||||
"version": "0.99.1",
|
||||
"version": "0.101.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@agentclientprotocol/claude-agent-acp",
|
||||
"version": "0.99.1",
|
||||
"version": "0.101.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "2.1.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.312",
|
||||
"@agentclientprotocol/sdk": "2.4.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.318",
|
||||
"diff": "9.0.0",
|
||||
"zod": "4.6.7"
|
||||
},
|
||||
@@ -18,29 +18,29 @@
|
||||
"claude-agent-acp": "dist/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "1.3.0",
|
||||
"@anthropic-ai/sdk": "1.4.0",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@tsconfig/node22": "22.0.6",
|
||||
"@types/node": "26.6.5",
|
||||
"@types/node": "26.6.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.72.1",
|
||||
"@typescript-eslint/parser": "8.72.1",
|
||||
"ajv": "8.20.0",
|
||||
"ajv-formats": "3.0.1",
|
||||
"eslint": "10.13.0",
|
||||
"eslint": "10.14.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"globals": "17.13.0",
|
||||
"globals": "17.14.0",
|
||||
"prettier": "3.9.10",
|
||||
"typescript": "6.0.3",
|
||||
"vitest": "5.0.5"
|
||||
"vitest": "5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@agentclientprotocol/sdk": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-2.1.0.tgz",
|
||||
"integrity": "sha512-IuKjJmHLPzbmbg26eK9Jopd8AVxgLuu8fX114YzYAU6tLYclCo2DUzLL4vbCpYGr9mzvs2T0kigE3ZCueL06tg==",
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-2.4.0.tgz",
|
||||
"integrity": "sha512-7qJ8nnyj7WesC5ve185ioTpB2/svQoeGV4HA4nLEhgDUrcmBe54/08VcXc/oL4p14tDbxxECZzdYmUYQ+4l+Wg==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"@modelcontextprotocol/server": "^2.4.0",
|
||||
@@ -53,22 +53,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.312.tgz",
|
||||
"integrity": "sha512-Ilj5Agx3ak/Z0UPZNLS7+CTnYMa+Ijf8+FKelh9MKGRwHVYyfvmJgL0fsmooI78SdkZwqjI5a4CwOAsJurdjJA==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.318.tgz",
|
||||
"integrity": "sha512-z5WHCUeW52SKQ3rnvI3zt8X5h2QQ5o3Cgg5xarO5Rimfe67f3pOJt2aOh00S8t/nRzqfs+8nCb9o1EoXe+yccA==",
|
||||
"license": "SEE LICENSE IN README.md",
|
||||
"engines": {
|
||||
"node": ">=18.14.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.312",
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.312",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.312",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.312",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.312",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.312",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.312",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.312"
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.318",
|
||||
"@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.318",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.318",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.318",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.318",
|
||||
"@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.318",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.318",
|
||||
"@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.318"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@anthropic-ai/sdk": ">=0.93.0",
|
||||
@@ -77,9 +77,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.312.tgz",
|
||||
"integrity": "sha512-AVmdMOuoeE3Y9f4wAIPcEAAS0OFaZw1L6l11YuyqfS0B/+DYxkWxS/ZYZ1NbUy57eaIW/vdEgz9Q5M99Pl6ZJw==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.318.tgz",
|
||||
"integrity": "sha512-AWoXeDXzAMD3RaA21lWuHvCrKd8xmbTTmKjovninn4j07jheoVSMzFbCFjpp4kk5TdhT36JtWPkAxvjNMbcO8w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -90,9 +90,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.312.tgz",
|
||||
"integrity": "sha512-Dmxyil+GPzF1WENoFOi1Cx0roSdJA6HewGAfAFvsH5vYrzb6G0REGuoQQ0n3u8i8qFgtl1m/WSl4u5t+MdiHWA==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.318.tgz",
|
||||
"integrity": "sha512-6CkZ5PCdebSY/LePp16sf/HYRtM6zVuxtn8qYICFS5KUZFsjccJJ9swVsOdHXNHi4SWZcSmIFTwoUbfFCzisRw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -103,9 +103,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.312.tgz",
|
||||
"integrity": "sha512-jebsXksKh7g7u1x+RxjYQXM50TCN0e7GthebXa+n5IebF3pPqtmyWGVIiEEjvpajn3P6Zh8BWUVuufUpXn8ccA==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.318.tgz",
|
||||
"integrity": "sha512-mBm4su17aMitLBBCQj3bHdejyUDY6z/ormGih+HG24N689RSbdKECjGjkT87tDBIR/4jyoqmuSeHqM1DI8TJlg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -119,9 +119,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.312.tgz",
|
||||
"integrity": "sha512-9GT0JzbfhODwsCO3MCg79wPH47qARCuKECcryeAJnVczplAlXSIiBw1+6UcqL5+0wSYFu6D/tvw/AiVy+PkHsg==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.318.tgz",
|
||||
"integrity": "sha512-l4LSYFOrvlYCrUImGfxMTQ0wg+T3s9CBhrBvPF/0oJGKZg+QnxHHU8jUVm9e9/xYmDRTtqFIrr4id/5AfH4XGw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -135,9 +135,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.312.tgz",
|
||||
"integrity": "sha512-UOsqza2uo5gqlX2OU72LhkQvIaNJKUQMJIi1poX2NtYqaWACqNo/TZPWfOBzxhyWmX8BLWaOlcuZGPLgcCJOTg==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.318.tgz",
|
||||
"integrity": "sha512-+mE+ueBD3oRFdaG16rd0h+LMjdeivGxL0pr/+FZK7JeLWVu+yPSw/f/X02b9oK36/DWykiFTu2G6HnJ9/+YO6w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -151,9 +151,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.312.tgz",
|
||||
"integrity": "sha512-zM+PB6qVybdwtlqElXQ4+wCwk2v/jjT3Xau4foydzy/g5pGRTuGT3PTcfDLeG0j9zF8IxLaCQ/+Bl9MABPQD8g==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.318.tgz",
|
||||
"integrity": "sha512-SAF3lj/2OzTU84p+OOA13QEKA9+5fYAw0M9E7AJjdnRmVFGqQfbV7Do1i1f9Sj0mIubB3rLTRphGRw8O4HZjgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -167,9 +167,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.312.tgz",
|
||||
"integrity": "sha512-Li9CyzsC2mzGmF1wtt/R59ChBLww6nc2dLn6tb+bgTDcd6kqvW44x5rIH+lRmBcpTNHR/8VO/k+GlmnkxqeaQQ==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.318.tgz",
|
||||
"integrity": "sha512-19iVSZ4379QbZU1XnGUtfFvhKS1WzS8H1sbU/DbrzqbJ5Kq1eB1drj+obB1fCxTh6m26tRPj0zMJmdeu/jk3Gw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -180,9 +180,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": {
|
||||
"version": "0.3.312",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.312.tgz",
|
||||
"integrity": "sha512-9GgGHHFEQnXx6EPhkPplOw1ndqmys8+Z+uOR68EIQlXGZm+wE+BmfypyHAoZhjs4151iWdQgNzjDT7wet3crdw==",
|
||||
"version": "0.3.318",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.318.tgz",
|
||||
"integrity": "sha512-ZdKVWpyVNVt0cXrOf8sUBaxcxLEAP+oGMdQDLBWr/BqOxTWLy7TBWOj1kzw+wVg/9WIkjkgQWeJzGXPWulR1sA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -193,9 +193,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/@anthropic-ai/sdk": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-1.3.0.tgz",
|
||||
"integrity": "sha512-k7z9BlLLPxfZH+ov7dS6EnaN/wiZeV8YNT1LZfrpAHIy7oY7pHr4UzirF9f2OlHtFEnRBOX+AZQ91Y5fK+TPTw==",
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-1.4.0.tgz",
|
||||
"integrity": "sha512-tyuibnhQL57kLOx5oomY4Ld7jOVOPNC5v3IiyRtR3l+Friv66tI4VbuZYF2NMel/T0WMuQMBFOMKDBUbUh8gPA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@opentelemetry/api": "^1.4.1",
|
||||
@@ -363,9 +363,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@hono/node-server": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.5.tgz",
|
||||
"integrity": "sha512-MgP/I06GdvsilDspMk/qmRzpk8LOUStP6jFAbSRi40W09DhoyUn+Mj7eyKICPqeYKybOjVFLVIAQzvu1bfIa7Q==",
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.6.tgz",
|
||||
"integrity": "sha512-p/KH9MnfNcsm3sR6x4lNgm5j+QN4Et8srKredl9DZfXiyZ1UQ3aQ2YVpFLbqktYN5JI+DB+VZFKM2PqE5hLKjQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -544,9 +544,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.155.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.155.0.tgz",
|
||||
"integrity": "sha512-SeE8JPwW1xs1tHeNycjUtUBdhorRa8o4jlvjwk49R7/Z291i+4DQa7JJIgOm/TaYQZx+QrPQbVJ/9c8dMIZN8Q==",
|
||||
"version": "0.156.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.156.0.tgz",
|
||||
"integrity": "sha512-1Duyg48TdJNdyhEB8Xn1L36bT9Pv6GUtlKjHxOys8xkaF/rQq3XJE+bAurSK/AgIz5mGFsb77cn9Pb20+WCScw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
@@ -555,9 +555,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm-eabi": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.15.tgz",
|
||||
"integrity": "sha512-aLcgK9gIJ3YRvrrtfSBbRa27F5WrpiTaPulnFpsHPxpUHgFlSgnU4854MHwoRGEBhfRJDWCS2WQ7lIjskE9Olw==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.16.tgz",
|
||||
"integrity": "sha512-ia3DwAs0OsMGS7+IConptSiyk9pEXkOx/AbJ2n/lAGxH3QkWQus1t8d7gnAT38FCU2sQu8lUbeR6AiZFv4JxaA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -573,9 +573,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.15.tgz",
|
||||
"integrity": "sha512-xD7DdZCrbThKuxNg7ooQmvp07ys4J/pnSEMTG3/OdOWl6daC67m/Q4fL78sRHMxTH/N4fGUbYhcPM0MF5WFHkg==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.16.tgz",
|
||||
"integrity": "sha512-kx5wBiMB6E7TEvpl2B9gjLU004BkvEm2Dr941BFjx/SontPwSzNuQUIoVKxHHoSjpFIfHMmcguyLOtyn0hObRg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -591,9 +591,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.15.tgz",
|
||||
"integrity": "sha512-m2WuQ6r0B4OTYxyPpNLtXaMRbRDUbG8YQV2Q3KTdSSK8Th6KHCnC8jVCJt8bvYeSB5WivkkNbc85mKadaSdOxA==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.16.tgz",
|
||||
"integrity": "sha512-qslZrXnKJU4cUpjoAmtAo/KQM9e2IRMlmpig6Zpwj+8KWxW8v+nkAf9216Bsek9lOC1jvg2yCjygCFo2f83msQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -609,9 +609,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.15.tgz",
|
||||
"integrity": "sha512-5RtnsHM36nodM9WbMy+zip0LGS/G+y5wro5RHrpOlr4ac24+1zSi9kiV2MP1myZeZ/ifEHfulQcWjnAXzc2C2A==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.16.tgz",
|
||||
"integrity": "sha512-FdF+y48ND13eAyM2mQn+85kvAqNlvRWROy2rhgA463X/0Gv4vGtazZtfaF1mRBLscYvtOlh4QnLjOWiFzX69OQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -627,9 +627,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.15.tgz",
|
||||
"integrity": "sha512-g3l09pyFqhu+135JKkbkwiKGQmwU5hUMUPJ4VdBADvuqR8d33L6H578rh8m7rtxbdp+VmX/+nzI7nvhSZlzpUQ==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.16.tgz",
|
||||
"integrity": "sha512-ddjqFM5e95AgLbUPtKIS7V1KTVlA0RUgCVr5mn+/IEhsdy3pr+Vuj/HZ7nlMN2FyxIwUktOH1LEPIQXO1v9y1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -645,9 +645,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.15.tgz",
|
||||
"integrity": "sha512-nIe3VugI97nGQtspPxDqA4sXMUpeiocKIP/CqpY/u/vgbT+alX+cVxu1C/oVBPKg4feNTmYovE91v4DgXvXNwQ==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.16.tgz",
|
||||
"integrity": "sha512-tHdKWbFkFBI687iim3LIyIvyL7j66VvQYkDPss5Stn/qyE2tWkR1YD0dXmXPFKKqT/o5ZEJVsaRsWS2meQwGOA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -663,9 +663,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.15.tgz",
|
||||
"integrity": "sha512-iTBjXx+B5QSvgI89lJfmqh4wTh8NabR1YZIIN3hNx4zSG0EVfVqkOvLulNpG4251pbd6/IAmZ/LefVk1Y4rPhw==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.16.tgz",
|
||||
"integrity": "sha512-FJiLGAblPBMlBEdbOqw6kW6QcXDWAf/oJu7gYs9ZJZwmg+K+/zjFLxPTIY9izJUzxzc24FHvmseyA0IvJSl17w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -684,9 +684,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.15.tgz",
|
||||
"integrity": "sha512-uN26XOnVR7rqQupG3V9oAG2EGGatWjcJHOeDOHUFCh4TBWmP2tHTFoVN13aYbwfm0aHqJAEmcwhAu6sooIjfqQ==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.16.tgz",
|
||||
"integrity": "sha512-hrJpblMsrQ58U9veWpbXzkhV5zStunds6HWLprqq1qauvgBr1E6P+24kLj6lSLI9vjRn/RYpjprhkHQPKGWpNg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -705,9 +705,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.15.tgz",
|
||||
"integrity": "sha512-9nWkcdd+H+XhaA3fQIwpHnKIrfx/PQ6rO0pivr78Og07tXlUlctBBJoEYLPfhTmCR/QxEVdn6uPjHV5SymPhdw==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.16.tgz",
|
||||
"integrity": "sha512-qJd/dC6j6CwLG9/s/RP2nb1RZ0GIgj7Ioj7x/SYa3RzjVrlzrmH0fhIOpfvqQDeIsdP0loi+kHaMhJzY1PBIaA==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -726,9 +726,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.15.tgz",
|
||||
"integrity": "sha512-Ggh0ciFjLwIusLSLz7LZYEaGdxOAUJXI+Qu5JCbhPJJHEt8vP+IjRATTJheiJsdzzTYgUiHUiw3X1Ea3ZpMBdA==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.16.tgz",
|
||||
"integrity": "sha512-Vx7Xg5uUJuNcujJjI70OICaH0EYj80BtOLZTSN7uOYg8QOLlyKnaG0IW7Fn/J0IpJsaKzmDKMhOQv1JBM9m9vg==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -747,9 +747,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.15.tgz",
|
||||
"integrity": "sha512-FHg60rS6DBePAYZ9X9F67x+JObFdmgn6tupA1C/a3B+CufFmTD4mX+e8M75tCiAO3foR/6xwVBI0KQiI7sn/rw==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.16.tgz",
|
||||
"integrity": "sha512-TNKhgE3uJTsTzatUSSYt0Kgo+Oa2uSlSjz4r1aEIea7HX6ULBym4fAlYUhG1i6pjNf2njfCUAfKwr6C3E9Xg1w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -768,9 +768,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.15.tgz",
|
||||
"integrity": "sha512-/cvV/7v5VGz/moiz0XKRj2dE8DzsKyhIu1KpOvJGPjRywg3yscON889UGvAe8zfiJLHup7VLjBduoGWi3HusWQ==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.16.tgz",
|
||||
"integrity": "sha512-7chXdpjXZ8qG0+mIxECN3cT9kvhZ3/oZhMX6Pp876P7CDrIy8nJswva6Mq357JR7eYXfuskwZxMeV1SzoZdHrA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -789,9 +789,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.15.tgz",
|
||||
"integrity": "sha512-MyzC5Hrv/sm+Z7TSGKP/j8001RO2xQm1zOpCNVL4j0cY/VhBZviludA2YFQ7i4lH6ZAXxQm0lcMdBzM+99mE7w==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.16.tgz",
|
||||
"integrity": "sha512-Kwjt+7uNTJK5/MDkGWGVO2KQPnj8yAV75dMpfwyHZrJSXWHrniOB0aUEWlVYf3H1hOqFLIStLdM5QXq6bnKmOQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -807,9 +807,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.15.tgz",
|
||||
"integrity": "sha512-+PgYiS+AH5omy6L45ZLxybasauJaj3M8buoT83D+nzPmCayXlxUV9hydhciCKVyIg0B/v0BtXPDE1uGqNwCPpg==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.16.tgz",
|
||||
"integrity": "sha512-/LH6WfjDRXXJz/p5xl4TmU+jpcnwcxbKEQBW/GZE0JHfN0lGIyTtsUEGaQ/q/GikkGJ2yLKe6pwm7AnEWO8pdw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -825,9 +825,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.15.tgz",
|
||||
"integrity": "sha512-HFZd2QNQYn1JbIi+Hpd7H+r/lkWxcfIu28nirZ6eCn2LafuvmExMlb/P96Sfx5tf7pPArw39IdhmCF8vmV+NhQ==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.16.tgz",
|
||||
"integrity": "sha512-1lv1KvX0Z871zfk7vw+dnXMMnHNyDwMzWG8Kv3HxDXMOhzCX4SHc7HK319fInP0i+0p9D8brkfzL7pJOaGl+tw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -889,9 +889,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
|
||||
"integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.10.tgz",
|
||||
"integrity": "sha512-lTyOMnOcmRBzdCv6/4zUZCrEhV0xrqQiUZBZtVcbmLHBXKLnN8q89v/wKRF/Q0HbwVsqbIG3o5HDoFl9sduM+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -903,9 +903,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "26.6.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.5.tgz",
|
||||
"integrity": "sha512-uMzsv9stDdofIZBx4UGh4Z9ZgXnGC9seRDscilBcTHAeOFk67MZg/k9bWVfO+bk4qZmG+l52hRnLwUiH2LnJTg==",
|
||||
"version": "26.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.6.6.tgz",
|
||||
"integrity": "sha512-MzQj+8Kx3XI40OmUAE6Qoh58ZMNstNNMwn2nfd3qWsfe7nDNSqJNzes4njhz6AHwrSHOffSLwXU6yb474Q4aog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1146,14 +1146,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.0.5.tgz",
|
||||
"integrity": "sha512-xLL3lkDegJZw+MGoGaCCsFayDZthGgpAtr3Vziyfc4p7xH89K7KRPcRBBh/kEYm0Aqkt5DtTmkYpBtRV/FrHZg==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-5.1.0.tgz",
|
||||
"integrity": "sha512-5umB9/jlWcqVS6fsrFmv5Gdnpu6wAUio/lEOwAmvB7v+lFo/IW2B9FhAD0p19GCULTgMzLCdUmuCDCnAzWgppQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "0.3.31",
|
||||
"@vitest/spy": "5.0.5",
|
||||
"@vitest/spy": "5.1.0",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^1.4.3"
|
||||
},
|
||||
@@ -1174,9 +1174,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.0.5.tgz",
|
||||
"integrity": "sha512-lwJRExuH417257Q5wv9QYugN9IMJkoxcrKrYxGPQkBzl7wlNpTUxD/5yNX4ESKVUIShKPgkGchYPFMWOOk0wzw==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-5.1.0.tgz",
|
||||
"integrity": "sha512-2DPO5OMHWKrBngC+fCmTQqemNF0gidRhp3lxbBmRhW+M1XJrfgPpqNqWVevXtn2f2ufD5ZaR1B6B641aAlcX5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
@@ -1543,13 +1543,17 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.1.tgz",
|
||||
"integrity": "sha512-Ev/hIyePLZtpL98x562lvPtenrUfGr0lfaf44HFZ+hDEwso7ccV9QAZrEVLg0hxNAzygaAFxy2dYaAKKM0G06A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
@@ -1613,9 +1617,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "10.13.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.13.0.tgz",
|
||||
"integrity": "sha512-UohDjD4zSzEwhf58M3O7vc/ycc8O1I7dNlhtD0WxE8Px8EHNJKtUwzBqrzeGhisRuv2ag4sAYswszCJRgKXYUg==",
|
||||
"version": "10.14.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-10.14.0.tgz",
|
||||
"integrity": "sha512-T0pNsxkb9IKmtQjhpK3d7nWOpFv+YHuMbTJnSVMoQblF0onvXfErrtp4V1jHtsQPan7dKaGVD0q1WCXnzMF31A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
@@ -1628,7 +1632,7 @@
|
||||
"@eslint/config-helpers": "^0.7.0",
|
||||
"@eslint/core": "^1.2.1",
|
||||
"@eslint/plugin-kit": "^0.7.3",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanfs/node": "^0.16.8",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@humanwhocodes/retry": "^0.4.2",
|
||||
"@types/estree": "^1.0.6",
|
||||
@@ -1649,7 +1653,7 @@
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-glob": "^4.0.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"minimatch": "^10.2.5",
|
||||
"minimatch": "^10.2.6",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.3"
|
||||
},
|
||||
@@ -1941,9 +1945,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express-rate-limit": {
|
||||
"version": "8.7.1",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.1.tgz",
|
||||
"integrity": "sha512-2FXbqkygil3mZiXzEtM0IjE/UBmBNot0J1GEVrJT4JbrvwOSoEtqtO+wHbiMQELWe1eNvHoYRg2dkjOid+6JkA==",
|
||||
"version": "8.7.3",
|
||||
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.3.tgz",
|
||||
"integrity": "sha512-zPLqDI2f0gV2WmGnacLf9XSSqn4VldRyP5LCzOwx0BKH40mO6+2PCFkoSsRO2jePx87/Kf6NUF6P2QOTKXHbQA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
@@ -2201,9 +2205,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "17.13.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz",
|
||||
"integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==",
|
||||
"version": "17.14.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.14.0.tgz",
|
||||
"integrity": "sha512-UtdkTVyAJePQv0J2M9Xe4L0ruNSDV314XiIJsADI2Zf40bcdAonE/D/OhAU8AT99oij9mhLByb+NvA3QWZYgCg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2266,9 +2270,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hono": {
|
||||
"version": "4.13.14",
|
||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.13.14.tgz",
|
||||
"integrity": "sha512-yhRLQ21U6qa9Hsu2N7Qcbh8tE+WKEcoErjIo56LeSGiGXGp9sA7UpE86Ui9uexb61KakiGwuHMn2QdV7w6i6kQ==",
|
||||
"version": "4.13.16",
|
||||
"resolved": "https://registry.npmjs.org/hono/-/hono-4.13.16.tgz",
|
||||
"integrity": "sha512-AOLOEhvrV+iH92xXCnFr/5+3KjPKcI3xP63XJtX5spAnkznPdHijlIsUTpi7/9EhWqrTCekw5c5zh1K+YsVw7A==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -2348,9 +2352,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "10.7.5",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.5.tgz",
|
||||
"integrity": "sha512-t2v0rkILYv9WXmSL7TpAaU3HXgaFYOPUcH3QHgwQ++gpJuH3bqyMy4Fvt/DJCTKwzH3Cf+bAp5W/mFL39KPLzA==",
|
||||
"version": "10.7.6",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.6.tgz",
|
||||
"integrity": "sha512-00LYkM6byILa9eQIx6qoaXCM40xTLd56AZ4vyaPW3YTyb49VZYPo5xsiAq4tuQ54GH4R7gVdYScJ1B7B77PuTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
@@ -2404,9 +2408,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/jose": {
|
||||
"version": "6.2.13",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.2.13.tgz",
|
||||
"integrity": "sha512-7TIg10ZE1x82YediN+lcrPNvGMKge9yFHQD+Qho/b8y2adfugU3AsvvHfxV0fzyFllT6l9xCjf4RWY9g/Z9PJQ==",
|
||||
"version": "6.2.15",
|
||||
"resolved": "https://registry.npmjs.org/jose/-/jose-6.2.15.tgz",
|
||||
"integrity": "sha512-qdF6ewcZARtef63fJ9AKKZPgxw+t7USH6HLXYcD4CrdmSvDp79rpJSPFEKc90QBeGS63u1KQtN2MZQHC0yDIzA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
@@ -3215,9 +3219,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.17.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.17.0.tgz",
|
||||
"integrity": "sha512-5LK5BZ2XDHMvcUJaf0CQ5HL3aVgKbpklvByC7qLSxYkfE8COEEbJg5xCHWCTqzqi0Gs4Jn5Mv5v3R38W6edscA==",
|
||||
"version": "6.17.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.17.1.tgz",
|
||||
"integrity": "sha512-jd3COkaKVgGUW+ZHyEHCG9bH7RoaaiWuMgzsIBjUMVjLAaWGWpoUAVwljVvBHxRu/2qEHnadLGZrkutYUBPQJA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
@@ -3271,14 +3275,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.2.15",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.15.tgz",
|
||||
"integrity": "sha512-6odND+fel5zVw3I4Yc2e69gvguDnX0CAAGiNDZSq4ik5WUcaLrkD2GLuog0XcODbor31hZ5ayEMgVDno+KPV5g==",
|
||||
"version": "1.2.16",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.16.tgz",
|
||||
"integrity": "sha512-bWvlMpFKiTfDKfnK7FC2MPgPeWCf/Kpwsq49ApdW+FQaBZb6O6dZ4MAPbPUjp7hYQrw/RobqCzn64BRrQecGHw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.155.0",
|
||||
"@oxc-project/types": "=0.156.0",
|
||||
"@rolldown/pluginutils": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
@@ -3288,21 +3292,21 @@
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm-eabi": "1.2.15",
|
||||
"@rolldown/binding-android-arm64": "1.2.15",
|
||||
"@rolldown/binding-darwin-arm64": "1.2.15",
|
||||
"@rolldown/binding-darwin-x64": "1.2.15",
|
||||
"@rolldown/binding-freebsd-x64": "1.2.15",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.2.15",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.2.15",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.2.15",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.2.15",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.2.15",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.2.15",
|
||||
"@rolldown/binding-linux-x64-musl": "1.2.15",
|
||||
"@rolldown/binding-openharmony-arm64": "1.2.15",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.2.15",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.2.15"
|
||||
"@rolldown/binding-android-arm-eabi": "1.2.16",
|
||||
"@rolldown/binding-android-arm64": "1.2.16",
|
||||
"@rolldown/binding-darwin-arm64": "1.2.16",
|
||||
"@rolldown/binding-darwin-x64": "1.2.16",
|
||||
"@rolldown/binding-freebsd-x64": "1.2.16",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.2.16",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.2.16",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.2.16",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.2.16",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.2.16",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.2.16",
|
||||
"@rolldown/binding-linux-x64-musl": "1.2.16",
|
||||
"@rolldown/binding-openharmony-arm64": "1.2.16",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.2.16",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.2.16"
|
||||
}
|
||||
},
|
||||
"node_modules/router": {
|
||||
@@ -3330,9 +3334,9 @@
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.8.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
||||
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
||||
"version": "7.8.6",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.6.tgz",
|
||||
"integrity": "sha512-9lpSSU4Mly3mrtruwLs1eLK6+gzbzqeBFwRNjIjE+9LuDpWdYctrQlQ3ej1Ilgi7gknpsTRnPoLP8DpCHqHIJw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
@@ -3532,9 +3536,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tinybench": {
|
||||
"version": "6.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.2.2.tgz",
|
||||
"integrity": "sha512-nIZ2N2dFpjBsg2hgitKu7mA+FvsIJuGJOwysRngmVRRmWgR/UyPjwJj8c/fT/dhm8EkHnF5EOogRf+0Z2qrimA==",
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-6.2.3.tgz",
|
||||
"integrity": "sha512-Al01C2JIBnO2CXCAPbpAl6sUiOZHeThGtHYNTa51JRw9PyWOCdr+9Ong05R4qg/Sk3+H645E8ov1h2c58ityNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -3774,14 +3778,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-5.0.5.tgz",
|
||||
"integrity": "sha512-cPODOMF8YnkiiYtDdHo6n4wWmBrOBBbOIYH2d33M4l3CdNn72h+qMmO6uXffUN6A5AZFXNND/d+krS9mgkXRfg==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-5.1.0.tgz",
|
||||
"integrity": "sha512-MzmNFnrwa8v8lF1bLxw3UJ4EREwVOVb75VqJZmUDRjJ6EluK/x9th7qTbaeDk41WxE1GxWqmTXcdsfobfH5sOA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/mocker": "5.0.5",
|
||||
"@vitest/mocker": "5.1.0",
|
||||
"chai": "^6.3.0",
|
||||
"es-module-lexer": "^2.3.2",
|
||||
"expect-type": "^1.4.0",
|
||||
@@ -3807,12 +3811,12 @@
|
||||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "5.0.5",
|
||||
"@vitest/browser-preview": "5.0.5",
|
||||
"@vitest/browser-playwright": "5.1.0",
|
||||
"@vitest/browser-preview": "5.1.0",
|
||||
"@vitest/browser-webdriverio": "^5.0.0-beta.5 || >=5.0.0",
|
||||
"@vitest/coverage-istanbul": "5.0.5",
|
||||
"@vitest/coverage-v8": "5.0.5",
|
||||
"@vitest/ui": "5.0.5",
|
||||
"@vitest/coverage-istanbul": "5.1.0",
|
||||
"@vitest/coverage-v8": "5.1.0",
|
||||
"@vitest/ui": "5.1.0",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.4.0 || ^7.0.0 || ^8.0.0"
|
||||
|
||||
19
package.json
19
package.json
@@ -3,7 +3,7 @@
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"version": "0.99.1",
|
||||
"version": "0.101.0",
|
||||
"description": "An ACP-compatible coding agent powered by the Claude Agent SDK (TypeScript)",
|
||||
"main": "dist/lib.js",
|
||||
"types": "dist/lib.d.ts",
|
||||
@@ -21,12 +21,15 @@
|
||||
"files": [
|
||||
"dist/",
|
||||
"!dist/tests/",
|
||||
"!dist/binary-entry.*",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"package.json"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"build:binary": "node scripts/build-binary.mjs",
|
||||
"smoke:binary": "node scripts/smoke-binary.mjs",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "npm run build && npm run start",
|
||||
"example:simple-client": "node --experimental-strip-types --disable-warning=ExperimentalWarning examples/simple-client.ts",
|
||||
@@ -65,25 +68,25 @@
|
||||
"node": ">=22"
|
||||
},
|
||||
"dependencies": {
|
||||
"@agentclientprotocol/sdk": "2.1.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.312",
|
||||
"@agentclientprotocol/sdk": "2.4.0",
|
||||
"@anthropic-ai/claude-agent-sdk": "0.3.318",
|
||||
"diff": "9.0.0",
|
||||
"zod": "4.6.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@anthropic-ai/sdk": "1.3.0",
|
||||
"@anthropic-ai/sdk": "1.4.0",
|
||||
"@eslint/js": "10.0.1",
|
||||
"@tsconfig/node22": "22.0.6",
|
||||
"@types/node": "26.6.5",
|
||||
"@types/node": "26.6.6",
|
||||
"@typescript-eslint/eslint-plugin": "8.72.1",
|
||||
"@typescript-eslint/parser": "8.72.1",
|
||||
"ajv": "8.20.0",
|
||||
"ajv-formats": "3.0.1",
|
||||
"eslint": "10.13.0",
|
||||
"eslint": "10.14.0",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
"globals": "17.13.0",
|
||||
"globals": "17.14.0",
|
||||
"prettier": "3.9.10",
|
||||
"typescript": "6.0.3",
|
||||
"vitest": "5.0.5"
|
||||
"vitest": "5.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
92
scripts/build-binary.mjs
Normal file
92
scripts/build-binary.mjs
Normal file
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env node
|
||||
// Builds an executable of the agent with `bun build --compile` and copies the
|
||||
// target platform's Claude CLI next to it. Both files go in the release
|
||||
// archive: the executable runs the CLI from its own directory.
|
||||
//
|
||||
// node scripts/build-binary.mjs [--target bun-linux-x64-musl] [--outfile path]
|
||||
//
|
||||
// --target defaults to the host. Cross-compiling needs the target's SDK
|
||||
// platform package installed; the script prints the install command when it
|
||||
// is missing.
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { chmodSync, copyFileSync, readFileSync } from "node:fs";
|
||||
import { createRequire } from "node:module";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { parseArgs } from "node:util";
|
||||
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
|
||||
function hostTarget() {
|
||||
const os = process.platform === "win32" ? "windows" : process.platform;
|
||||
// Node linked against glibc reports its version; musl builds don't.
|
||||
const musl =
|
||||
process.platform === "linux" && !process.report.getReport().header.glibcVersionRuntime;
|
||||
return `bun-${os}-${process.arch}${musl ? "-musl" : ""}`;
|
||||
}
|
||||
|
||||
const { values } = parseArgs({
|
||||
options: {
|
||||
target: { type: "string", default: hostTarget() },
|
||||
outfile: { type: "string" },
|
||||
},
|
||||
});
|
||||
const target = values.target;
|
||||
|
||||
// Bun targets look like `bun-<os>-<arch>` with optional `-musl`, `-baseline` or
|
||||
// `-modern` suffixes; the SDK names its packages `<platform>-<arch>[-musl]`.
|
||||
const match = /^bun-(linux|darwin|windows)-(x64|arm64|aarch64)(?:-.+)?$/.exec(target);
|
||||
if (!match) {
|
||||
console.error(
|
||||
`Unsupported target "${target}". Expected e.g. bun-linux-x64, bun-darwin-arm64, bun-windows-x64.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
const [, os, rawArch] = match;
|
||||
const platform = os === "windows" ? "win32" : os;
|
||||
const arch = rawArch === "aarch64" ? "arm64" : rawArch;
|
||||
const musl = target.split("-").includes("musl");
|
||||
const exe = os === "windows" ? ".exe" : "";
|
||||
const cliPackage = `@anthropic-ai/claude-agent-sdk-${platform}-${arch}${musl ? "-musl" : ""}`;
|
||||
const cliSpecifier = `${cliPackage}/claude${exe}`;
|
||||
const outfile = resolve(values.outfile ?? join(repoRoot, "dist-bin", `claude-agent-acp${exe}`));
|
||||
|
||||
// Resolve from the SDK, the way claudeCliPath() does at runtime, so a nested
|
||||
// install is checked rather than only a hoisted one.
|
||||
const sdkRequire = createRequire(
|
||||
createRequire(join(repoRoot, "package.json")).resolve("@anthropic-ai/claude-agent-sdk"),
|
||||
);
|
||||
let cliPath;
|
||||
try {
|
||||
cliPath = sdkRequire.resolve(cliSpecifier);
|
||||
} catch {
|
||||
const sdkVersion = JSON.parse(
|
||||
readFileSync(
|
||||
join(dirname(sdkRequire.resolve("@anthropic-ai/claude-agent-sdk")), "package.json"),
|
||||
"utf8",
|
||||
),
|
||||
).version;
|
||||
console.error(
|
||||
`${cliSpecifier} is not installed. npm only installs the host's platform package; for ${target} run:\n\n` +
|
||||
` npm install --no-save --force ${cliPackage}@${sdkVersion}\n`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const bun = spawnSync(
|
||||
"bun",
|
||||
["build", "src/binary-entry.ts", "--compile", "--target", target, "--outfile", outfile],
|
||||
{ cwd: repoRoot, stdio: "inherit", shell: process.platform === "win32" },
|
||||
);
|
||||
if (bun.error) {
|
||||
console.error(`Could not run bun: ${bun.error.message}. Install it from https://bun.sh.`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (bun.status !== 0) process.exit(bun.status ?? 1);
|
||||
|
||||
// The executable runs the CLI from its own directory (src/binary-entry.ts).
|
||||
const cliOutfile = join(dirname(outfile), `claude${exe}`);
|
||||
copyFileSync(cliPath, cliOutfile);
|
||||
chmodSync(cliOutfile, 0o755);
|
||||
console.log(`Copied ${cliSpecifier} to ${cliOutfile}`);
|
||||
470
scripts/smoke-binary.mjs
Normal file
470
scripts/smoke-binary.mjs
Normal file
@@ -0,0 +1,470 @@
|
||||
#!/usr/bin/env node
|
||||
// Smoke-tests a built agent over ACP. Defaults to the executable from
|
||||
// scripts/build-binary.mjs, with `claude` next to it. Pass another command
|
||||
// after `--` to compare, e.g.
|
||||
// `node scripts/smoke-binary.mjs --full -- node "$PWD/dist/index.js"` (the full
|
||||
// run starts the agent in a scratch directory, so paths must be absolute).
|
||||
//
|
||||
// node scripts/smoke-binary.mjs # no login needed
|
||||
// node scripts/smoke-binary.mjs --full # talks to the model; needs a logged-in Claude
|
||||
//
|
||||
// SMOKE_DEBUG=1 prints every tool call the full run saw.
|
||||
//
|
||||
// The basic run checks `--version`, `--cli --version`, `initialize` (v1 and
|
||||
// v2) and the `terminal-auth` login command. The
|
||||
// full run also has Claude use Bash, Read (text and image), Edit and a
|
||||
// subagent in a scratch directory, then cancels a turn, lists the session,
|
||||
// loads it in a fresh agent process, and forks and deletes it.
|
||||
//
|
||||
// Claude Code's native builds have no Grep or Glob tool: its Bash shell wraps
|
||||
// `grep` and `find` in functions that run the ugrep and bfs built into the
|
||||
// Claude binary at `$CLAUDE_CODE_EXECPATH`. The full run checks that those
|
||||
// run, since they are the helpers a packaged build could fail to reach.
|
||||
|
||||
import { spawn, spawnSync } from "node:child_process";
|
||||
import {
|
||||
copyFileSync,
|
||||
mkdirSync,
|
||||
mkdtempSync,
|
||||
readFileSync,
|
||||
rmSync,
|
||||
symlinkSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import readline from "node:readline";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { parseArgs } from "node:util";
|
||||
import { deflateSync } from "node:zlib";
|
||||
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const { values, positionals } = parseArgs({
|
||||
options: { full: { type: "boolean", default: false } },
|
||||
allowPositionals: true,
|
||||
});
|
||||
const exe = process.platform === "win32" ? ".exe" : "";
|
||||
const [command, ...commandArgs] =
|
||||
positionals.length > 0 ? positionals : [join(repoRoot, "dist-bin", `claude-agent-acp${exe}`)];
|
||||
|
||||
let failures = 0;
|
||||
function check(ok, label, detail) {
|
||||
console.log(
|
||||
`${ok ? "ok " : "FAIL"} ${label}${!ok && detail !== undefined ? `: ${detail}` : ""}`,
|
||||
);
|
||||
if (!ok) failures++;
|
||||
return ok;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- basic
|
||||
|
||||
function runSync(args, [cmd, ...cmdArgs] = [command, ...commandArgs]) {
|
||||
const result = spawnSync(cmd, [...cmdArgs, ...args], {
|
||||
encoding: "utf8",
|
||||
timeout: 60_000,
|
||||
});
|
||||
return { stdout: (result.stdout ?? "").trim(), error: result.error ?? result.stderr };
|
||||
}
|
||||
|
||||
const version = JSON.parse(readFileSync(join(repoRoot, "package.json"), "utf8")).version;
|
||||
const own = runSync(["--version"]);
|
||||
check(own.stdout === version, `--version prints ${version}`, own.stdout || own.error);
|
||||
const cli = runSync(["--cli", "--version"]);
|
||||
check(
|
||||
/\(Claude Code\)$/.test(cli.stdout),
|
||||
"--cli --version runs the bundled Claude CLI",
|
||||
cli.stdout || cli.error,
|
||||
);
|
||||
|
||||
// The release archive's layout: the executable finds `claude` in the directory
|
||||
// of its real path. Only for the default executable; a `--` command has no
|
||||
// such layout.
|
||||
if (positionals.length === 0) {
|
||||
const scratch = mkdtempSync(join(tmpdir(), "acp-layout-"));
|
||||
try {
|
||||
if (process.platform !== "win32") {
|
||||
const link = join(scratch, "claude-agent-acp");
|
||||
symlinkSync(command, link);
|
||||
const linked = runSync(["--cli", "--version"], [link]);
|
||||
check(
|
||||
/\(Claude Code\)$/.test(linked.stdout),
|
||||
"a symlink to the executable finds the bundled CLI",
|
||||
linked.stdout || linked.error,
|
||||
);
|
||||
rmSync(link);
|
||||
}
|
||||
const alone = join(scratch, `claude-agent-acp${exe}`);
|
||||
copyFileSync(command, alone);
|
||||
const missing = runSync(["--cli", "--version"], [alone]);
|
||||
check(
|
||||
String(missing.error).includes("The Claude CLI is missing"),
|
||||
"without claude next to it, says the CLI is missing",
|
||||
missing.stdout || missing.error,
|
||||
);
|
||||
} finally {
|
||||
rmSync(scratch, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
/** Starts the agent and speaks newline-delimited JSON-RPC to it. */
|
||||
function startAgent(cwd, onNotification) {
|
||||
const child = spawn(command, commandArgs, { cwd, stdio: ["pipe", "pipe", "pipe"] });
|
||||
const stderr = [];
|
||||
child.stderr.on("data", (chunk) => stderr.push(chunk));
|
||||
let nextId = 0;
|
||||
const pending = new Map();
|
||||
const write = (message) =>
|
||||
child.stdin.write(JSON.stringify({ jsonrpc: "2.0", ...message }) + "\n");
|
||||
readline.createInterface({ input: child.stdout }).on("line", (line) => {
|
||||
let message;
|
||||
try {
|
||||
message = JSON.parse(line);
|
||||
} catch {
|
||||
check(false, "stdout carries only JSON-RPC", line.slice(0, 200));
|
||||
return;
|
||||
}
|
||||
if (message.method === undefined && pending.has(message.id)) {
|
||||
pending.get(message.id)(message);
|
||||
pending.delete(message.id);
|
||||
} else if (message.method === "session/request_permission") {
|
||||
const allow =
|
||||
message.params.options.find((o) => o.kind === "allow_once") ?? message.params.options[0];
|
||||
write({
|
||||
id: message.id,
|
||||
result: { outcome: { outcome: "selected", optionId: allow.optionId } },
|
||||
});
|
||||
} else if (message.id !== undefined && message.method !== undefined) {
|
||||
write({
|
||||
id: message.id,
|
||||
error: { code: -32601, message: `smoke client does not handle ${message.method}` },
|
||||
});
|
||||
} else {
|
||||
onNotification?.(message);
|
||||
}
|
||||
});
|
||||
const exited = new Promise((resolve) => child.on("exit", resolve));
|
||||
// Answer anything still pending if the agent dies, instead of hanging.
|
||||
let exitError;
|
||||
exited.then((code) => {
|
||||
exitError = { message: `agent exited with ${code}: ${Buffer.concat(stderr)}` };
|
||||
for (const resolve of pending.values()) resolve({ error: exitError });
|
||||
pending.clear();
|
||||
});
|
||||
return {
|
||||
request(method, params) {
|
||||
const id = ++nextId;
|
||||
return new Promise((resolve) => {
|
||||
if (exitError) return resolve({ error: exitError });
|
||||
pending.set(id, resolve);
|
||||
write({ id, method, params });
|
||||
});
|
||||
},
|
||||
notify: (method, params) => write({ method, params }),
|
||||
async stop() {
|
||||
child.stdin.end();
|
||||
const code = await Promise.race([
|
||||
exited,
|
||||
new Promise((r) => setTimeout(() => r("timeout"), 10_000)),
|
||||
]);
|
||||
if (code === "timeout") child.kill();
|
||||
return { code, stderr: Buffer.concat(stderr).toString() };
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const initializeParams = { protocolVersion: 1, clientCapabilities: {} };
|
||||
{
|
||||
const agent = startAgent(process.cwd());
|
||||
const init = await agent.request("initialize", initializeParams);
|
||||
check(
|
||||
init.result?.agentInfo?.version === version,
|
||||
"initialize answers",
|
||||
JSON.stringify(init.error),
|
||||
);
|
||||
const { code } = await agent.stop();
|
||||
check(code === 0, "exits 0 when stdin closes", code);
|
||||
}
|
||||
{
|
||||
// The `terminal-auth` login command reruns the agent; run it with
|
||||
// `--version` in place of `auth login --console` instead of logging in.
|
||||
// `--version` wins over a stray argument, so also check that no path inside
|
||||
// a compiled executable leaked into the arguments.
|
||||
const agent = startAgent(process.cwd());
|
||||
const init = await agent.request("initialize", {
|
||||
protocolVersion: 1,
|
||||
clientCapabilities: { _meta: { "terminal-auth": true } },
|
||||
});
|
||||
await agent.stop();
|
||||
const login = init.result?.authMethods?.find((m) => m.id === "console-login")?._meta?.[
|
||||
"terminal-auth"
|
||||
];
|
||||
const cliArgs = login?.args?.slice(0, login.args.indexOf("--cli") + 1);
|
||||
const rerun = login
|
||||
? runSync([...cliArgs, "--version"], [login.command])
|
||||
: { stdout: "", error: "no terminal-auth console-login method" };
|
||||
check(
|
||||
/\(Claude Code\)$/.test(rerun.stdout) &&
|
||||
!login.args.some((arg) => arg.includes("$bunfs") || arg.includes("~BUN")),
|
||||
"the terminal-auth login command reruns the agent",
|
||||
`${JSON.stringify(login)} -> ${rerun.stdout || rerun.error}`,
|
||||
);
|
||||
}
|
||||
{
|
||||
const agent = startAgent(process.cwd());
|
||||
const init = await agent.request("initialize", {
|
||||
protocolVersion: 2,
|
||||
info: { name: "smoke-binary", version },
|
||||
capabilities: {},
|
||||
});
|
||||
check(
|
||||
init.result?.protocolVersion === 2,
|
||||
"initialize answers ACP v2",
|
||||
JSON.stringify(init.error),
|
||||
);
|
||||
await agent.stop();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- full
|
||||
|
||||
if (values.full) {
|
||||
const work = mkdtempSync(join(tmpdir(), "acp-smoke-"));
|
||||
try {
|
||||
await fullSmoke(work);
|
||||
} finally {
|
||||
rmSync(work, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
/** A solid red 16x16 PNG, so the model has something to name. */
|
||||
function redPng() {
|
||||
const crcTable = Array.from({ length: 256 }, (_, n) => {
|
||||
let c = n;
|
||||
for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
||||
return c >>> 0;
|
||||
});
|
||||
const crc = (buf) => {
|
||||
let c = 0xffffffff;
|
||||
for (const byte of buf) c = crcTable[(c ^ byte) & 0xff] ^ (c >>> 8);
|
||||
return (c ^ 0xffffffff) >>> 0;
|
||||
};
|
||||
const chunk = (type, data) => {
|
||||
const body = Buffer.concat([Buffer.from(type), data]);
|
||||
const out = Buffer.alloc(body.length + 8);
|
||||
out.writeUInt32BE(data.length, 0);
|
||||
body.copy(out, 4);
|
||||
out.writeUInt32BE(crc(body), body.length + 4);
|
||||
return out;
|
||||
};
|
||||
const size = 16;
|
||||
const header = Buffer.alloc(13);
|
||||
header.writeUInt32BE(size, 0);
|
||||
header.writeUInt32BE(size, 4);
|
||||
header[8] = 8; // bit depth
|
||||
header[9] = 2; // RGB
|
||||
const row = Buffer.concat([Buffer.from([0]), Buffer.alloc(size * 3, Buffer.from([255, 0, 0]))]);
|
||||
return Buffer.concat([
|
||||
Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]),
|
||||
chunk("IHDR", header),
|
||||
chunk("IDAT", deflateSync(Buffer.concat(Array(size).fill(row)))),
|
||||
chunk("IEND", Buffer.alloc(0)),
|
||||
]);
|
||||
}
|
||||
|
||||
/** Writes its results to files so the checks don't depend on the model's reply. */
|
||||
function searchCommand(token) {
|
||||
return [
|
||||
`grep -rl "${token}" . > grep.out`,
|
||||
'find . -name "*.md" > find.out',
|
||||
'{ echo "$CLAUDE_CODE_EXECPATH"; grep --version | head -1; find --version | head -1; } > tools.out',
|
||||
].join("; ");
|
||||
}
|
||||
|
||||
function searchResults(work) {
|
||||
const read = (name) => {
|
||||
try {
|
||||
return readFileSync(join(work, name), "utf8");
|
||||
} catch (error) {
|
||||
return String(error);
|
||||
}
|
||||
};
|
||||
const [execPath = "", grepVersion = "", findVersion = ""] = read("tools.out").split("\n");
|
||||
return { grep: read("grep.out"), find: read("find.out"), execPath, grepVersion, findVersion };
|
||||
}
|
||||
|
||||
async function fullSmoke(work) {
|
||||
const token = `SMOKE_TOKEN_${process.pid}`;
|
||||
mkdirSync(join(work, "notes"));
|
||||
mkdirSync(join(work, "src"));
|
||||
writeFileSync(join(work, "notes", "alpha.md"), `# Alpha\n\nThe token is ${token}.\n`);
|
||||
writeFileSync(join(work, "notes", "beta.md"), "# Beta\n\nNothing here.\n");
|
||||
writeFileSync(join(work, "src", "gamma.ts"), `export const value = "${token}";\n`);
|
||||
writeFileSync(join(work, "pixel.png"), redPng());
|
||||
|
||||
const toolCalls = new Map();
|
||||
let text = "";
|
||||
const onNotification = (message) => {
|
||||
if (message.method !== "session/update") return;
|
||||
const update = message.params.update;
|
||||
if (update.sessionUpdate === "agent_message_chunk" && update.content.type === "text") {
|
||||
text += update.content.text;
|
||||
} else if (
|
||||
update.sessionUpdate === "tool_call" ||
|
||||
update.sessionUpdate === "tool_call_update"
|
||||
) {
|
||||
const call = toolCalls.get(update.toolCallId) ?? {};
|
||||
toolCalls.set(update.toolCallId, {
|
||||
...call,
|
||||
name: update._meta?.claudeCode?.toolName ?? call.name,
|
||||
status: update.status ?? call.status,
|
||||
title: update.title ?? call.title,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const agent = startAgent(work, onNotification);
|
||||
await agent.request("initialize", initializeParams);
|
||||
const created = await agent.request("session/new", { cwd: work, mcpServers: [] });
|
||||
if (!check(created.result?.sessionId, "session/new", JSON.stringify(created.error))) {
|
||||
console.error((await agent.stop()).stderr);
|
||||
return;
|
||||
}
|
||||
const sessionId = created.result.sessionId;
|
||||
|
||||
const started = Date.now();
|
||||
const prompt = await agent.request("session/prompt", {
|
||||
sessionId,
|
||||
prompt: [
|
||||
{
|
||||
type: "text",
|
||||
text: [
|
||||
"This is an automated smoke test of your tools. Do each step with the named tool, in order, one tool call per step:",
|
||||
`1. Bash: run exactly \`${searchCommand(token)}\``,
|
||||
"2. Read: read notes/alpha.md.",
|
||||
"3. Read: read pixel.png and note its color.",
|
||||
`4. Edit: in notes/alpha.md replace "${token}" with "EDITED".`,
|
||||
"5. Bash: run `cat notes/alpha.md`.",
|
||||
'6. Agent: launch a subagent (subagent_type "Explore") that counts the .ts files under src/ and reports the number.',
|
||||
"Then reply with one line: SMOKE-DONE color=<the color of pixel.png> tsfiles=<the subagent's count>.",
|
||||
].join("\n"),
|
||||
},
|
||||
],
|
||||
});
|
||||
check(
|
||||
prompt.result?.stopReason === "end_turn",
|
||||
"prompt ends with end_turn",
|
||||
JSON.stringify(prompt.result ?? prompt.error),
|
||||
);
|
||||
console.log(` (turn took ${Math.round((Date.now() - started) / 1000)}s)`);
|
||||
|
||||
const calls = [...toolCalls.values()];
|
||||
if (process.env.SMOKE_DEBUG) console.log(JSON.stringify(calls, null, 1));
|
||||
const searched = searchResults(work);
|
||||
check(
|
||||
searched.grep.includes("alpha.md") && searched.grep.includes("gamma.ts"),
|
||||
"grep found the token",
|
||||
searched.grep,
|
||||
);
|
||||
check(
|
||||
searched.find.includes("alpha.md") && searched.find.includes("beta.md"),
|
||||
"find listed the .md files",
|
||||
searched.find,
|
||||
);
|
||||
check(
|
||||
/^ugrep /.test(searched.grepVersion),
|
||||
"grep ran Claude's embedded ugrep",
|
||||
searched.grepVersion,
|
||||
);
|
||||
check(/^bfs /.test(searched.findVersion), "find ran Claude's embedded bfs", searched.findVersion);
|
||||
console.log(` (CLAUDE_CODE_EXECPATH=${searched.execPath})`);
|
||||
for (const name of ["Read", "Edit", "Bash"]) {
|
||||
const used = calls.filter((c) => c.name === name);
|
||||
check(
|
||||
used.length > 0 && used.every((c) => c.status === "completed"),
|
||||
`${name} ran and completed`,
|
||||
JSON.stringify(used),
|
||||
);
|
||||
}
|
||||
const subagent = calls.filter((c) => c.name === "Agent" || c.name === "Task");
|
||||
check(
|
||||
subagent.some((c) => c.status === "completed"),
|
||||
"subagent ran and completed",
|
||||
JSON.stringify(subagent),
|
||||
);
|
||||
const failed = calls.filter((c) => c.status === "failed");
|
||||
check(failed.length === 0, "no tool call failed", JSON.stringify(failed));
|
||||
check(
|
||||
readFileSync(join(work, "notes", "alpha.md"), "utf8").includes("EDITED"),
|
||||
"Edit changed the file on disk",
|
||||
);
|
||||
check(
|
||||
/SMOKE-DONE/.test(text) && /color=\W*red/i.test(text),
|
||||
"image read as red",
|
||||
text.slice(-300),
|
||||
);
|
||||
check(/tsfiles=\W*1\b/.test(text), "subagent counted 1 .ts file", text.slice(-300));
|
||||
|
||||
// A cancel interrupts a running Bash command and ends the turn as cancelled.
|
||||
const cancelled = agent.request("session/prompt", {
|
||||
sessionId,
|
||||
prompt: [
|
||||
{ type: "text", text: "Use the Bash tool to run `sleep 60`. Do not run anything else." },
|
||||
],
|
||||
});
|
||||
const deadline = Date.now() + 60_000;
|
||||
const bashRunning = () =>
|
||||
[...toolCalls.values()].some((c) => c.name === "Bash" && c.status !== "completed");
|
||||
while (!bashRunning() && Date.now() < deadline) {
|
||||
await new Promise((r) => setTimeout(r, 200));
|
||||
}
|
||||
agent.notify("session/cancel", { sessionId });
|
||||
const cancelResult = await cancelled;
|
||||
check(
|
||||
cancelResult.result?.stopReason === "cancelled",
|
||||
"session/cancel ends the turn as cancelled",
|
||||
JSON.stringify(cancelResult.result ?? cancelResult.error),
|
||||
);
|
||||
|
||||
const listed = await agent.request("session/list", { cwd: work });
|
||||
check(
|
||||
listed.result?.sessions?.some((s) => s.sessionId === sessionId),
|
||||
"session/list finds the session",
|
||||
JSON.stringify(listed.result ?? listed.error),
|
||||
);
|
||||
const { code, stderr } = await agent.stop();
|
||||
check(code === 0, "exits 0 when stdin closes", code);
|
||||
if (failures > 0) console.error(stderr);
|
||||
|
||||
// A fresh process, so the replay comes from the transcript on disk.
|
||||
let replayed = "";
|
||||
const reloaded = startAgent(work, (message) => {
|
||||
const update = message.params?.update;
|
||||
if (update?.sessionUpdate === "user_message_chunk" && update.content.type === "text")
|
||||
replayed += update.content.text;
|
||||
});
|
||||
await reloaded.request("initialize", initializeParams);
|
||||
const loaded = await reloaded.request("session/load", { sessionId, cwd: work, mcpServers: [] });
|
||||
check(!loaded.error, "session/load in a new process", JSON.stringify(loaded.error));
|
||||
check(replayed.includes(token), "session/load replays the first prompt", replayed.slice(0, 200));
|
||||
|
||||
// Fork and delete go through the SDK's transcript helpers, not the CLI.
|
||||
const forked = await reloaded.request("session/fork", { sessionId, cwd: work, mcpServers: [] });
|
||||
const forkId = forked.result?.sessionId;
|
||||
check(
|
||||
forkId && forkId !== sessionId,
|
||||
"session/fork",
|
||||
JSON.stringify(forked.result ?? forked.error),
|
||||
);
|
||||
if (forkId) {
|
||||
const deleted = await reloaded.request("session/delete", { sessionId: forkId });
|
||||
const after = await reloaded.request("session/list", { cwd: work });
|
||||
check(
|
||||
!deleted.error && !after.result?.sessions?.some((s) => s.sessionId === forkId),
|
||||
"session/delete removes the fork",
|
||||
JSON.stringify(deleted.error ?? after.result),
|
||||
);
|
||||
}
|
||||
await reloaded.stop();
|
||||
}
|
||||
|
||||
console.log(failures === 0 ? "\nsmoke test passed" : `\n${failures} check(s) failed`);
|
||||
process.exit(failures === 0 ? 0 : 1);
|
||||
909
src/acp-agent.ts
909
src/acp-agent.ts
File diff suppressed because it is too large
Load Diff
19
src/agent-command.ts
Normal file
19
src/agent-command.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* The command that starts this agent again with the flags it was started with,
|
||||
* for a client to run in a terminal (e.g. `terminal-auth` login).
|
||||
*
|
||||
* Under Node, `process.argv` is `[node, script, ...flags]`, so the command is
|
||||
* `node script ...flags`. In a `bun build --compile` executable it is
|
||||
* `["bun", "/$bunfs/root/<name>", ...flags]` (`B:\~BUN\root\<name>` on
|
||||
* Windows): `process.execPath` is the executable itself and `argv[1]` names a
|
||||
* file inside it, which must not be passed back as an argument.
|
||||
*/
|
||||
export function agentCommand(argv: readonly string[] = process.argv): {
|
||||
command: string;
|
||||
args: string[];
|
||||
} {
|
||||
const [, script, ...flags] = argv;
|
||||
if (script === undefined) return { command: process.execPath, args: [] };
|
||||
const compiled = script.includes("$bunfs") || script.includes("~BUN");
|
||||
return { command: process.execPath, args: compiled ? flags : [script, ...flags] };
|
||||
}
|
||||
@@ -863,18 +863,29 @@ function recordPublished(task: AsyncTask, fields: Record<string, unknown>): void
|
||||
* Recovers a background Bash task from the structured `backgroundTaskId` of
|
||||
* its tool result. The text of a tool result never gives a task id: a
|
||||
* foreground command can print any text.
|
||||
*
|
||||
* Claude Code sends no `tool_use_result` with a subagent's tool results. For
|
||||
* those, `startedTaskOf` gives the background `local_bash` task whose
|
||||
* `task_started` named the Bash call, which comes before the result.
|
||||
*/
|
||||
export function backgroundBashTaskFromToolResult(
|
||||
content: unknown,
|
||||
toolUseResult: unknown,
|
||||
toolUses: Record<string, { name: string; input: unknown }>,
|
||||
startedTaskOf?: (toolUseId: string) => string | undefined,
|
||||
): (AsyncTaskStarted & { taskId: string; toolCallId: string }) | undefined {
|
||||
if (!Array.isArray(content)) return undefined;
|
||||
const toolResults = content.flatMap(toolResultBlock);
|
||||
const bashResults = toolResults.filter((result) => toolUses[result.toolUseId]?.name === "Bash");
|
||||
if (bashResults.length === 0) return undefined;
|
||||
|
||||
const backgroundResults = structuredBackgroundResults(toolUseResult, toolUses);
|
||||
let backgroundResults = structuredBackgroundResults(toolUseResult, toolUses);
|
||||
if (backgroundResults.length === 0 && startedTaskOf) {
|
||||
backgroundResults = bashResults.flatMap((result) => {
|
||||
const taskId = result.isError ? undefined : startedTaskOf(result.toolUseId);
|
||||
return taskId ? [{ taskId, toolUseId: result.toolUseId }] : [];
|
||||
});
|
||||
}
|
||||
const distinctTaskIds = new Set(backgroundResults.map((result) => result.taskId));
|
||||
if (distinctTaskIds.size !== 1) return undefined;
|
||||
const taskId = [...distinctTaskIds][0];
|
||||
|
||||
131
src/background-output.ts
Normal file
131
src/background-output.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* The output of a command that went to the background, read from the file
|
||||
* that Claude Code writes it to. Claude Code streams no output of such a
|
||||
* command, so its display terminal would show only the placeholder of the
|
||||
* Bash result ("Command running in background with ID …") until the command
|
||||
* exits. ACP v2 asks an Agent to keep a listed terminal's output current
|
||||
* whenever it can read it (the v2 prompt lifecycle, "Background work").
|
||||
*
|
||||
* The file is polled: watching a file is not reliable on every platform, and
|
||||
* a missing file only means that nothing was written yet.
|
||||
*/
|
||||
import { open } from "node:fs/promises";
|
||||
import { StringDecoder } from "node:string_decoder";
|
||||
|
||||
/** How often a running command's output file is read. */
|
||||
export const BACKGROUND_OUTPUT_POLL_MS = 500;
|
||||
|
||||
/** The most bytes one read takes, so a burst of output does not block the loop. */
|
||||
export const BACKGROUND_OUTPUT_READ_BYTES = 256 * 1024;
|
||||
|
||||
/**
|
||||
* The most unread bytes that are still sent. A command that writes faster
|
||||
* than the polls read falls behind. Past this, the reads skip to the file's
|
||||
* last bytes, as a snapshot: a terminal shows the latest output, and a
|
||||
* client keeps a bounded amount of it anyway.
|
||||
*/
|
||||
export const BACKGROUND_OUTPUT_MAX_BACKLOG_BYTES = 1024 * 1024;
|
||||
|
||||
/**
|
||||
* Text that the file adds. A snapshot replaces the terminal's output so far:
|
||||
* the first one replaces the placeholder of the Bash result, and a later one
|
||||
* follows a skip or a file that shrank. Other text appends to it.
|
||||
*/
|
||||
export type BackgroundOutput = { text: string; replaces: boolean };
|
||||
|
||||
/**
|
||||
* Follows the output file `path` of one background command and hands each
|
||||
* piece of new text to `publish`, in order. Reads never overlap. A read that
|
||||
* fails, for example because the file does not exist yet, is tried again at
|
||||
* the next poll. `publish` must not reject: the next read waits for it.
|
||||
*/
|
||||
export class BackgroundOutputTail {
|
||||
private offset = 0;
|
||||
private decoder = new StringDecoder("utf8");
|
||||
/** Whether the next text replaces the terminal's output. */
|
||||
private replaces = true;
|
||||
private stopped = false;
|
||||
private reading: Promise<void> = Promise.resolve();
|
||||
private readonly timer: ReturnType<typeof setInterval>;
|
||||
|
||||
constructor(
|
||||
private readonly path: string,
|
||||
private readonly publish: (output: BackgroundOutput) => Promise<void>,
|
||||
) {
|
||||
this.timer = setInterval(() => void this.read(false), BACKGROUND_OUTPUT_POLL_MS);
|
||||
// A command that runs on must not keep the agent process alive.
|
||||
this.timer.unref();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the rest of the file and stops. The command ended, so what the file
|
||||
* holds is its whole output, and it goes out before the terminal's exit.
|
||||
*/
|
||||
async finish(): Promise<void> {
|
||||
clearInterval(this.timer);
|
||||
await this.read(true);
|
||||
this.stopped = true;
|
||||
}
|
||||
|
||||
/** Stops without reading more: the session ended. */
|
||||
stop(): void {
|
||||
clearInterval(this.timer);
|
||||
this.stopped = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads what the file adds, one read of at most
|
||||
* {@link BACKGROUND_OUTPUT_READ_BYTES} at a time, and publishes each read's
|
||||
* text before the next. `toEnd` reads until the end of the file, and ends a
|
||||
* character that the command cut off with a replacement character.
|
||||
*/
|
||||
private read(toEnd: boolean): Promise<void> {
|
||||
this.reading = this.reading.then(async () => {
|
||||
if (this.stopped) return;
|
||||
let file;
|
||||
try {
|
||||
file = await open(this.path, "r");
|
||||
} catch {
|
||||
// Nothing written yet, or the file is gone: try again at the next
|
||||
// poll. At the end, the terminal keeps the output it has.
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const { size } = await file.stat();
|
||||
// A file that shrank is a new one: its output starts over. Past the
|
||||
// backlog, the reads skip to the file's last bytes.
|
||||
const start = size < this.offset ? 0 : this.offset;
|
||||
const skipTo = Math.max(start, size - BACKGROUND_OUTPUT_MAX_BACKLOG_BYTES);
|
||||
if (skipTo !== this.offset) {
|
||||
this.offset = skipTo;
|
||||
this.decoder = new StringDecoder("utf8");
|
||||
this.replaces = true;
|
||||
}
|
||||
const buffer = Buffer.alloc(BACKGROUND_OUTPUT_READ_BYTES);
|
||||
let bytesRead: number;
|
||||
do {
|
||||
({ bytesRead } = await file.read(buffer, 0, buffer.length, this.offset));
|
||||
this.offset += bytesRead;
|
||||
const text = this.decoder.write(buffer.subarray(0, bytesRead));
|
||||
if (text !== "") await this.send(text);
|
||||
} while (toEnd && bytesRead > 0);
|
||||
if (toEnd) {
|
||||
const rest = this.decoder.end();
|
||||
// A command that wrote nothing still replaces the placeholder.
|
||||
if (rest !== "" || this.replaces) await this.send(rest);
|
||||
}
|
||||
} catch {
|
||||
// The read failed: try again at the next poll.
|
||||
} finally {
|
||||
await file.close();
|
||||
}
|
||||
});
|
||||
return this.reading;
|
||||
}
|
||||
|
||||
private async send(text: string): Promise<void> {
|
||||
const replaces = this.replaces;
|
||||
this.replaces = false;
|
||||
await this.publish({ text, replaces });
|
||||
}
|
||||
}
|
||||
629
src/background-work.ts
Normal file
629
src/background-work.ts
Normal file
@@ -0,0 +1,629 @@
|
||||
/**
|
||||
* The background work of a session: the work that Claude Code keeps running
|
||||
* independently of the session's foreground work, which ACP v2 lists on every
|
||||
* `state_update` of the session as `background` (the v2 prompt lifecycle,
|
||||
* "Background work").
|
||||
*
|
||||
* The lists are built from Claude Code's live background task set
|
||||
* (`background_tasks_changed`). Claude Code marks `ambient` its own
|
||||
* housekeeping and every live-update watcher; those are left out, except a
|
||||
* task that a tool call started, such as a `Monitor` call's. The root session and each
|
||||
* announced subagent session (the subagents RFD form) has its own list. Each
|
||||
* task is listed once, in the list of the session that runs it:
|
||||
*
|
||||
* - A command that went to the background: its display terminal, from the
|
||||
* Bash tool result until its task ends (`Session.backgroundTerminals`).
|
||||
* - A detached subagent: its child session, in its parent's list, while it
|
||||
* works, and while it is idle with background work of its own.
|
||||
* - A task that a tool call started, such as a `Monitor`, a `Workflow` or a
|
||||
* backgrounded MCP call: that tool call, kept `in_progress` (or `paused`)
|
||||
* from its tool result until its task ends (`Session.backgroundToolCalls`).
|
||||
* - Any other task, once its `task_started` came and the tool call that
|
||||
* started it, if any, returned: a `_claude/task` item with the task's id
|
||||
* and description. For example, a task whose tool call ended before the
|
||||
* task joined the level.
|
||||
*
|
||||
* Only a session whose interrupt spares background tasks reports its lists
|
||||
* (`Session.reportsBackground`): `session/cancel` must leave listed work
|
||||
* running.
|
||||
*/
|
||||
import { RequestError } from "@agentclientprotocol/sdk/unstable";
|
||||
import type { AcpSessionNotification } from "./acp-subagents.js";
|
||||
import type { NativeSubagent } from "./native-subagents.js";
|
||||
import { type AcpToolCallRenderer, V2_CANCELLED, V2_PAUSED } from "./tool-calls/renderer.js";
|
||||
import { type BackgroundOutput, BackgroundOutputTail } from "./background-output.js";
|
||||
|
||||
/** An item of a `background` list. */
|
||||
export type BackgroundItem =
|
||||
| { type: "terminal"; terminalId: string }
|
||||
| { type: "tool_call"; toolCallId: string }
|
||||
| { type: "subagent"; sessionId: string }
|
||||
| { type: "_claude/task"; taskId: string; description: string };
|
||||
|
||||
/** The display terminal of a command that went to the background (see `Session.backgroundTerminals`). */
|
||||
export interface BackgroundTerminal {
|
||||
/** The Bash tool call, whose id names the terminal. */
|
||||
toolCallId: string;
|
||||
/** The subagent tool call that ran the command, if any. */
|
||||
parentToolUseId?: string;
|
||||
/** The file that Claude Code writes the command's output to, from the Bash result. */
|
||||
outputFilePath?: string;
|
||||
/** Reads that file into the terminal while the command runs. */
|
||||
output?: BackgroundOutputTail;
|
||||
}
|
||||
|
||||
/** A tool call whose task runs on in the background (see `Session.backgroundToolCalls`). */
|
||||
export interface BackgroundToolCall {
|
||||
toolCallId: string;
|
||||
/** The tool use of the call, which Claude Code no longer caches after its result. */
|
||||
toolUse: { name: string; input: unknown };
|
||||
/** The subagent tool call that made the call, if any. */
|
||||
parentToolUseId?: string;
|
||||
paused?: boolean;
|
||||
}
|
||||
|
||||
/** How a background task ended, as Claude Code reports it. Undefined when it did not say. */
|
||||
export type BackgroundTaskEnd = "completed" | "failed" | "stopped" | undefined;
|
||||
|
||||
/** The live background task set of `background_tasks_changed`, by task id. */
|
||||
export type BackgroundLevel = Map<
|
||||
string,
|
||||
{ ambient: boolean; taskType: string; description: string; parentTaskId?: string }
|
||||
>;
|
||||
|
||||
/** The work state of a session, as its `state_update` names it. */
|
||||
export type WorkStateName = "idle" | "running" | "requires_action" | "unknown";
|
||||
|
||||
/** A new list of the session `sessionId`, with what its repeated state needs. */
|
||||
export interface BackgroundReport {
|
||||
sessionId: string;
|
||||
items: BackgroundItem[];
|
||||
/** The session's work state now, or undefined when it has none yet. */
|
||||
state: WorkStateName | undefined;
|
||||
/** The parent of a subagent session, which mirrors the child's state. */
|
||||
parentSessionId?: string;
|
||||
}
|
||||
|
||||
/** Where the agent reports the lists (see the agent's `background` option). */
|
||||
export interface BackgroundSink {
|
||||
/** The list of a session changed, or is reported for the first time. */
|
||||
changed(report: BackgroundReport): void;
|
||||
/** The session ended: its list is no longer reported. */
|
||||
forget(sessionId: string): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The state of a session that other modules own, and that the background
|
||||
* work reads: Claude Code's tasks as the consumer tracks them, the subagent
|
||||
* sessions, and the query that stops a task.
|
||||
*/
|
||||
export interface BackgroundOwner {
|
||||
liveBackgroundTasks: Map<string, { parentToolUseId?: string; isSubagent: boolean }>;
|
||||
nativeSubagentsByTaskId?: Map<string, NativeSubagent>;
|
||||
query: { stopTask(taskId: string): Promise<void> };
|
||||
}
|
||||
|
||||
/** A task of a `background_tasks_changed` payload. */
|
||||
export type LevelTask = {
|
||||
task_id: string;
|
||||
task_type: string;
|
||||
description: string;
|
||||
parent_task_id?: string;
|
||||
ambient?: boolean;
|
||||
};
|
||||
|
||||
/** The most returned tool calls that {@link SessionBackgroundWork} remembers. */
|
||||
const MAX_RETURNED_CALLS = 1024;
|
||||
|
||||
/** The tools whose structured result names the task that the call started. */
|
||||
const TASK_TOOLS = new Set(["Monitor", "Workflow"]);
|
||||
|
||||
/**
|
||||
* The background work of one root session, and of its subagent sessions: the
|
||||
* terminals and tool calls of the tasks that run in the background, and what
|
||||
* the client is told of them.
|
||||
*
|
||||
* Terminals are kept for every client that renders them, as before the
|
||||
* background lists. The rest is kept only when `reported`.
|
||||
*/
|
||||
export class SessionBackgroundWork {
|
||||
/** Claude Code's live background task set, from its last `background_tasks_changed`. */
|
||||
private level: BackgroundLevel = new Map();
|
||||
/** The terminals of the commands that went to the background, by task id. */
|
||||
private readonly terminals = new Map<string, BackgroundTerminal>();
|
||||
/** The tool calls whose tasks went on in the background, by task id. */
|
||||
private readonly toolCalls = new Map<string, BackgroundToolCall>();
|
||||
/**
|
||||
* The tool calls that returned, oldest first. A task that a call started
|
||||
* is part of that call until it returns, and the foreground work waits on
|
||||
* it. The task's `task_started` can come after the call returned. Bounded
|
||||
* by {@link MAX_RETURNED_CALLS}: a task joins the level around the time its
|
||||
* call returns.
|
||||
*/
|
||||
private readonly returned = new Set<string>();
|
||||
|
||||
/**
|
||||
* `reported`: whether the client gets the lists. Only when Claude Code's
|
||||
* interrupt spares background tasks, as `perTaskStopAffordance` makes it.
|
||||
*/
|
||||
constructor(
|
||||
private readonly sessionId: string,
|
||||
readonly reported: boolean,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Keeps the display terminal of the command `taskId` running after its Bash
|
||||
* result, until its task ends (see `withRunningTerminal`).
|
||||
*/
|
||||
terminalStarted(taskId: string, terminal: BackgroundTerminal): void {
|
||||
this.terminals.set(taskId, terminal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads what a tool result message tells of the background tasks:
|
||||
*
|
||||
* - The returned calls no longer hold the tasks that they started.
|
||||
* - Each call whose task goes on in the background is registered: a
|
||||
* `Monitor` or `Workflow` call, whose structured result names its task,
|
||||
* or a call that a live task names as its tool use, such as a
|
||||
* backgrounded MCP call. The task must be in the level: one that ended
|
||||
* already leaves its call as it is. Claude Code marks every live-update
|
||||
* watcher `ambient`, including the task of a `Monitor` call; a call
|
||||
* started it, so it is work the client can see and stop, and is
|
||||
* registered all the same. Ambient tasks without a call of their own,
|
||||
* such as watchers Claude Code starts by itself, are never registered.
|
||||
*
|
||||
* Returns the ids of the registered calls, whose result then reports
|
||||
* `in_progress` (see `withRunningToolCall`).
|
||||
*/
|
||||
toolResults(
|
||||
owner: BackgroundOwner,
|
||||
content: unknown,
|
||||
toolUseResult: unknown,
|
||||
toolUses: Record<string, { name: string; input: unknown }>,
|
||||
parentToolUseId: string | null,
|
||||
): Set<string> {
|
||||
const registered = new Set<string>();
|
||||
if (!this.reported || !Array.isArray(content)) return registered;
|
||||
const results = content.filter(
|
||||
(block): block is { type: "tool_result"; tool_use_id: string; is_error?: boolean } =>
|
||||
typeof block === "object" &&
|
||||
block !== null &&
|
||||
block.type === "tool_result" &&
|
||||
typeof block.tool_use_id === "string",
|
||||
);
|
||||
for (const { tool_use_id: toolCallId } of results) {
|
||||
this.returned.add(toolCallId);
|
||||
if (this.returned.size > MAX_RETURNED_CALLS) {
|
||||
this.returned.delete(this.returned.values().next().value!);
|
||||
}
|
||||
}
|
||||
const succeeded = results.filter((block) => block.is_error !== true);
|
||||
const structuredTaskId =
|
||||
succeeded.length === 1 &&
|
||||
typeof toolUseResult === "object" &&
|
||||
toolUseResult !== null &&
|
||||
typeof (toolUseResult as { taskId?: unknown }).taskId === "string"
|
||||
? (toolUseResult as { taskId: string }).taskId
|
||||
: undefined;
|
||||
for (const { tool_use_id: toolCallId } of succeeded) {
|
||||
const toolUse = toolUses[toolCallId];
|
||||
if (!toolUse) continue;
|
||||
const taskId =
|
||||
(TASK_TOOLS.has(toolUse.name) ? structuredTaskId : undefined) ??
|
||||
[...owner.liveBackgroundTasks].find(
|
||||
([, task]) => task.parentToolUseId === toolCallId && !task.isSubagent,
|
||||
)?.[0];
|
||||
const task = taskId === undefined ? undefined : this.level.get(taskId);
|
||||
if (!task || task.taskType === "local_bash" || task.taskType === "local_agent") {
|
||||
continue;
|
||||
}
|
||||
this.toolCalls.set(taskId!, {
|
||||
toolCallId,
|
||||
toolUse,
|
||||
...(parentToolUseId ? { parentToolUseId } : {}),
|
||||
});
|
||||
registered.add(toolCallId);
|
||||
}
|
||||
return registered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts reading the output of the background command `taskId` into its
|
||||
* terminal, when the client gets the lists and the Bash result named the
|
||||
* command's output file. `send` sends an update of the terminal's tool
|
||||
* call, routed as the call's other updates. Called once the Bash result's
|
||||
* own updates are sent: the first output replaces the placeholder that they
|
||||
* gave the terminal.
|
||||
*/
|
||||
followOutput(taskId: string, send: Send): void {
|
||||
const terminal = this.terminals.get(taskId);
|
||||
if (!this.reported || !terminal?.outputFilePath || terminal.output) return;
|
||||
terminal.output = new BackgroundOutputTail(terminal.outputFilePath, (output) =>
|
||||
send(terminalOutputUpdate(this.sessionId, terminal, output)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The task `taskId` ended. Reads the rest of its command's output, then
|
||||
* exits its terminal, and gives a tool call whose task it was its final
|
||||
* status: `cancelled` for a task that Claude Code stopped, and `completed`
|
||||
* for one that ended without saying how, such as one that the level
|
||||
* dropped: it no longer runs, and reported no failure. Claude Code reports
|
||||
* no exit code for a command, and `completed` does not mean 0: Claude Code
|
||||
* accepts some non-zero codes as a success, such as grep's 1.
|
||||
*/
|
||||
async taskEnded(taskId: string, end: BackgroundTaskEnd, send: Send): Promise<void> {
|
||||
const terminal = this.terminals.get(taskId);
|
||||
if (terminal) {
|
||||
await terminal.output?.finish();
|
||||
this.terminals.delete(taskId);
|
||||
await send(terminalExit(this.sessionId, terminal));
|
||||
}
|
||||
const toolCall = this.toolCalls.get(taskId);
|
||||
if (toolCall) {
|
||||
this.toolCalls.delete(taskId);
|
||||
await send(
|
||||
toolCallStatusUpdate(
|
||||
this.sessionId,
|
||||
toolCall,
|
||||
end === "stopped" ? V2_CANCELLED : end === "failed" ? "failed" : "completed",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The update that reports the background tool call of the task `taskId` as
|
||||
* `paused`, or as `in_progress` again, when `paused` changes it. Claude Code
|
||||
* pauses a workflow this way.
|
||||
*/
|
||||
taskPaused(taskId: string, paused: boolean): AcpSessionNotification | undefined {
|
||||
const toolCall = this.toolCalls.get(taskId);
|
||||
if (!toolCall || (toolCall.paused ?? false) === paused) return undefined;
|
||||
toolCall.paused = paused;
|
||||
return toolCallStatusUpdate(this.sessionId, toolCall, paused ? V2_PAUSED : "in_progress");
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes Claude Code's new live background task set. The terminals and tool
|
||||
* calls whose tasks it no longer holds end first, before a list drops them,
|
||||
* as v2 requires. A terminal or tool call is registered at its tool result,
|
||||
* after its task joined the level, so a later level without the task means
|
||||
* that it ended. Claude Code usually sends a task's end before that level,
|
||||
* which ends them first, but the SDK does not promise that order.
|
||||
*/
|
||||
async levelChanged(tasks: LevelTask[], send: Send): Promise<void> {
|
||||
if (!this.reported) return;
|
||||
const level: BackgroundLevel = new Map(
|
||||
tasks.map((task) => [
|
||||
task.task_id,
|
||||
{
|
||||
ambient: task.ambient === true,
|
||||
taskType: task.task_type,
|
||||
description: task.description,
|
||||
...(task.parent_task_id !== undefined ? { parentTaskId: task.parent_task_id } : {}),
|
||||
},
|
||||
]),
|
||||
);
|
||||
for (const taskId of [...this.terminals.keys(), ...this.toolCalls.keys()]) {
|
||||
if (!level.has(taskId)) await this.taskEnded(taskId, undefined, send);
|
||||
}
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* The query closed: Claude Code's background tasks end with its process.
|
||||
* Stops reading output, and returns the updates that exit the root
|
||||
* session's terminals and cancel its tool calls. The level empties, so the
|
||||
* next lists are empty. A subagent's command or tool call is left as it
|
||||
* was: it is on the child's stream, which the closed query's routing owned.
|
||||
*/
|
||||
queryClosed(): AcpSessionNotification[] {
|
||||
for (const terminal of this.terminals.values()) terminal.output?.stop();
|
||||
if (!this.reported) return [];
|
||||
const updates: AcpSessionNotification[] = [];
|
||||
for (const [taskId, terminal] of this.terminals) {
|
||||
if (terminal.parentToolUseId) continue;
|
||||
this.terminals.delete(taskId);
|
||||
updates.push(terminalExit(this.sessionId, terminal));
|
||||
}
|
||||
for (const [taskId, toolCall] of this.toolCalls) {
|
||||
if (toolCall.parentToolUseId) continue;
|
||||
this.toolCalls.delete(taskId);
|
||||
updates.push(toolCallStatusUpdate(this.sessionId, toolCall, V2_CANCELLED));
|
||||
}
|
||||
this.level = new Map();
|
||||
this.returned.clear();
|
||||
return updates;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `background` list of the root session and of each of its announced
|
||||
* subagent sessions, with what their repeated states need, deeper sessions
|
||||
* first and the root last: a child's own list goes out before its parent's
|
||||
* list drops it. Each list is empty while the level has not been reported:
|
||||
* Claude Code sends none before the first background task starts.
|
||||
*/
|
||||
reports(owner: BackgroundOwner, rootState: WorkStateName): BackgroundReport[] {
|
||||
const children = [...(owner.nativeSubagentsByTaskId ?? [])].filter(
|
||||
([, child]) => child.announced,
|
||||
);
|
||||
const childByTask = new Map(children);
|
||||
const childByToolUse = new Map(
|
||||
children.flatMap(([, child]) =>
|
||||
child.parentToolUseId ? [[child.parentToolUseId, child] as const] : [],
|
||||
),
|
||||
);
|
||||
const lists = new Map<string, BackgroundItem[]>([
|
||||
[this.sessionId, []],
|
||||
...children.map(([, child]): [string, BackgroundItem[]] => [child.sessionId, []]),
|
||||
]);
|
||||
// A subagent's command or tool call runs on the child's stream.
|
||||
const ownerOf = (parentToolUseId: string | undefined) =>
|
||||
parentToolUseId ? childByToolUse.get(parentToolUseId)?.sessionId : this.sessionId;
|
||||
for (const [taskId, task] of this.level) {
|
||||
// A registered call's task is listed even when ambient, as a `Monitor`
|
||||
// call's is (see `toolResults`).
|
||||
const toolCall = this.toolCalls.get(taskId);
|
||||
if (toolCall) {
|
||||
const session = ownerOf(toolCall.parentToolUseId);
|
||||
if (session)
|
||||
lists.get(session)!.push({ type: "tool_call", toolCallId: toolCall.toolCallId });
|
||||
continue;
|
||||
}
|
||||
if (task.ambient) continue;
|
||||
const terminal = this.terminals.get(taskId);
|
||||
if (terminal) {
|
||||
const session = ownerOf(terminal.parentToolUseId);
|
||||
if (session)
|
||||
lists.get(session)!.push({ type: "terminal", terminalId: terminal.toolCallId });
|
||||
continue;
|
||||
}
|
||||
// A command without a terminal yet is one that foreground work waits on.
|
||||
// A subagent is listed below, as its session.
|
||||
if (task.taskType === "local_bash" || task.taskType === "local_agent") continue;
|
||||
// A task joins the level before its `task_started`, and before the tool
|
||||
// call that starts it returns. Until both, the task is unknown or part
|
||||
// of that tool call.
|
||||
const live = owner.liveBackgroundTasks.get(taskId);
|
||||
if (!live || (live.parentToolUseId && !this.returned.has(live.parentToolUseId))) continue;
|
||||
const parent = task.parentTaskId ? childByTask.get(task.parentTaskId) : undefined;
|
||||
lists
|
||||
.get(parent?.sessionId ?? this.sessionId)!
|
||||
.push({ type: "_claude/task", taskId, description: task.description });
|
||||
}
|
||||
// A child is listed in its parent's list while it works in the background,
|
||||
// and while it is idle with background work of its own. Deeper children
|
||||
// first, so a child's list is whole before its parent's reads it.
|
||||
const sessions = new Map(children.map(([, child]) => [child.sessionId, child]));
|
||||
const depth = (child: NativeSubagent): number => {
|
||||
const parent = sessions.get(child.parentSessionId);
|
||||
return parent ? depth(parent) + 1 : 0;
|
||||
};
|
||||
const ordered = children.sort(([, a], [, b]) => depth(b) - depth(a));
|
||||
for (const [taskId, child] of ordered) {
|
||||
const task = this.level.get(taskId);
|
||||
const working =
|
||||
child.workState !== undefined &&
|
||||
child.workState !== "idle" &&
|
||||
task !== undefined &&
|
||||
!task.ambient;
|
||||
if (working || lists.get(child.sessionId)!.length > 0) {
|
||||
lists.get(child.parentSessionId)?.push({ type: "subagent", sessionId: child.sessionId });
|
||||
}
|
||||
}
|
||||
return [
|
||||
...ordered.map(([, child]) => ({
|
||||
sessionId: child.sessionId,
|
||||
items: lists.get(child.sessionId)!,
|
||||
state: workStateName(child.workState),
|
||||
parentSessionId: child.parentSessionId,
|
||||
})),
|
||||
{ sessionId: this.sessionId, items: lists.get(this.sessionId)!, state: rootState },
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The current state of each background tool call in `toolCallIds`: the
|
||||
* call as `renderer` shows its tool use, with its status now (see
|
||||
* `ClaudeAcpAgent.publishBackgroundToolCalls`).
|
||||
*/
|
||||
toolCallStates(
|
||||
toolCallIds: string[],
|
||||
renderer: AcpToolCallRenderer,
|
||||
cwd: string,
|
||||
): AcpSessionNotification[] {
|
||||
return [...this.toolCalls.values()]
|
||||
.filter((toolCall) => toolCallIds.includes(toolCall.toolCallId))
|
||||
.map((toolCall) => {
|
||||
const update = renderer.toolCall({ id: toolCall.toolCallId, ...toolCall.toolUse }, { cwd });
|
||||
const status = toolCall.paused ? V2_PAUSED : "in_progress";
|
||||
return {
|
||||
sessionId: this.sessionId,
|
||||
update: { ...update, status } as AcpSessionNotification["update"],
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* The task of the terminal or tool call `target` that the session
|
||||
* `sessionId` lists, or undefined when it lists no such item.
|
||||
*/
|
||||
listedTask(
|
||||
owner: BackgroundOwner,
|
||||
sessionId: string,
|
||||
target: BackgroundTarget,
|
||||
): string | undefined {
|
||||
if (!this.reported) return undefined;
|
||||
const listed = this.reports(owner, "idle")
|
||||
.find((report) => report.sessionId === sessionId)
|
||||
?.items.some((item) =>
|
||||
"terminalId" in target
|
||||
? item.type === "terminal" && item.terminalId === target.terminalId
|
||||
: item.type === "tool_call" && item.toolCallId === target.toolCallId,
|
||||
);
|
||||
if (!listed) return undefined;
|
||||
const id = "terminalId" in target ? target.terminalId : target.toolCallId;
|
||||
const entries = "terminalId" in target ? this.terminals : this.toolCalls;
|
||||
return [...entries].find(([, entry]) => entry.toolCallId === id)?.[0];
|
||||
}
|
||||
}
|
||||
|
||||
type Send = (notification: AcpSessionNotification) => Promise<void>;
|
||||
|
||||
/** A terminal or tool call that `terminal/cancel` or `tool_call/cancel` names. */
|
||||
export type BackgroundTarget = { terminalId: string } | { toolCallId: string };
|
||||
|
||||
/**
|
||||
* Stops the task of a terminal or tool call that the session `sessionId`
|
||||
* lists (v2 `terminal/cancel` and `tool_call/cancel`). `sessions` are the
|
||||
* root sessions: a subagent session's list is built with its root's. The
|
||||
* terminal exits, or the tool call gets its final status, when Claude Code
|
||||
* reports the task stopped.
|
||||
*/
|
||||
export async function cancelBackgroundWork(
|
||||
sessions: Array<BackgroundOwner & { background?: SessionBackgroundWork }>,
|
||||
sessionId: string,
|
||||
target: BackgroundTarget,
|
||||
): Promise<void> {
|
||||
const notCancellable = () =>
|
||||
"terminalId" in target
|
||||
? RequestError.invalidParams(
|
||||
{ sessionId, terminalId: target.terminalId },
|
||||
`Terminal ${target.terminalId} is not a command running in the background, so it cannot be cancelled.`,
|
||||
)
|
||||
: RequestError.invalidParams(
|
||||
{ sessionId, toolCallId: target.toolCallId },
|
||||
`Tool call ${target.toolCallId} is not running in the background, so it cannot be cancelled.`,
|
||||
);
|
||||
for (const session of sessions) {
|
||||
const taskId = session.background?.listedTask(session, sessionId, target);
|
||||
if (taskId === undefined) continue;
|
||||
try {
|
||||
await session.query.stopTask(taskId);
|
||||
} catch (error) {
|
||||
// The task ended meanwhile: it has ended on the client too, or is about to.
|
||||
if (session.background?.listedTask(session, sessionId, target) === undefined) {
|
||||
throw notCancellable();
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
throw notCancellable();
|
||||
}
|
||||
|
||||
/** The update that gives the terminal of `terminal` the text `output`. */
|
||||
function terminalOutputUpdate(
|
||||
sessionId: string,
|
||||
terminal: BackgroundTerminal,
|
||||
output: BackgroundOutput,
|
||||
): AcpSessionNotification {
|
||||
const data = { terminal_id: terminal.toolCallId, data: output.text };
|
||||
return {
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: terminal.toolCallId,
|
||||
_meta: {
|
||||
...(terminal.parentToolUseId
|
||||
? { claudeCode: { parentToolUseId: terminal.parentToolUseId } }
|
||||
: {}),
|
||||
...(output.replaces ? { terminal_output: data } : { terminal_output_delta: data }),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** The update that exits the terminal of `terminal`, with no exit code. */
|
||||
function terminalExit(sessionId: string, terminal: BackgroundTerminal): AcpSessionNotification {
|
||||
return {
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: terminal.toolCallId,
|
||||
_meta: {
|
||||
...(terminal.parentToolUseId
|
||||
? { claudeCode: { parentToolUseId: terminal.parentToolUseId } }
|
||||
: {}),
|
||||
terminal_exit: { terminal_id: terminal.toolCallId, exit_code: null, signal: null },
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function toolCallStatusUpdate(
|
||||
sessionId: string,
|
||||
toolCall: BackgroundToolCall,
|
||||
status: NonNullable<
|
||||
Extract<AcpSessionNotification["update"], { sessionUpdate: "tool_call_update" }>["status"]
|
||||
>,
|
||||
): AcpSessionNotification {
|
||||
return {
|
||||
sessionId,
|
||||
update: {
|
||||
sessionUpdate: "tool_call_update",
|
||||
toolCallId: toolCall.toolCallId,
|
||||
status,
|
||||
...(toolCall.parentToolUseId
|
||||
? { _meta: { claudeCode: { parentToolUseId: toolCall.parentToolUseId } } }
|
||||
: {}),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes the lists of each session that reports them, each time one
|
||||
* changes. The sink sends them to the client synchronously, so a list follows
|
||||
* the updates sent before it.
|
||||
*/
|
||||
export class BackgroundWorkReporter {
|
||||
/** The list last published for each session, as JSON, and the root session it is built with. */
|
||||
private readonly published = new Map<string, { json: string; root: string }>();
|
||||
|
||||
constructor(private readonly sink?: BackgroundSink) {}
|
||||
|
||||
/** Whether the lists are reported at all. */
|
||||
get enabled(): boolean {
|
||||
return this.sink !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes each list of the root session `rootSessionId` that changed. The
|
||||
* first call for a session publishes its list, also when it is empty.
|
||||
* `rootState` is the root session's state now.
|
||||
*/
|
||||
sync(
|
||||
rootSessionId: string,
|
||||
session: BackgroundOwner & { background?: SessionBackgroundWork },
|
||||
rootState: WorkStateName,
|
||||
): void {
|
||||
if (!this.sink || !session.background?.reported) return;
|
||||
for (const report of session.background.reports(session, rootState)) {
|
||||
const json = JSON.stringify(report.items);
|
||||
if (this.published.get(report.sessionId)?.json === json) continue;
|
||||
this.published.set(report.sessionId, { json, root: rootSessionId });
|
||||
this.sink.changed(report);
|
||||
}
|
||||
}
|
||||
|
||||
/** The root session `rootSessionId` ended, and its subagent sessions with it. */
|
||||
forget(rootSessionId: string): void {
|
||||
for (const [sessionId, { root }] of this.published) {
|
||||
if (root !== rootSessionId) continue;
|
||||
this.published.delete(sessionId);
|
||||
this.sink?.forget(sessionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A child's work state, when it is one that v2 names. */
|
||||
function workStateName(state: string | undefined): WorkStateName | undefined {
|
||||
return state === "idle" ||
|
||||
state === "running" ||
|
||||
state === "requires_action" ||
|
||||
state === "unknown"
|
||||
? state
|
||||
: undefined;
|
||||
}
|
||||
12
src/binary-entry.ts
Normal file
12
src/binary-entry.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
// Entry of the release executable (`scripts/build-binary.mjs`). It registers the
|
||||
// Claude CLI shipped next to the executable before importing the agent:
|
||||
// index.ts starts serving (or, with --cli, spawns the CLI) while it evaluates,
|
||||
// and a static import would evaluate it before this module's body runs.
|
||||
import { realpathSync } from "node:fs";
|
||||
import { dirname } from "node:path";
|
||||
import { useBundledClaudeCli } from "./claude-cli.js";
|
||||
|
||||
// realpath, so a symlink to the executable (e.g. in /usr/local/bin) still finds
|
||||
// the CLI next to the real file.
|
||||
useBundledClaudeCli(dirname(realpathSync(process.execPath)));
|
||||
await import("./index.js");
|
||||
88
src/claude-cli.ts
Normal file
88
src/claude-cli.ts
Normal file
@@ -0,0 +1,88 @@
|
||||
import { existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
const CLI_FILE_NAME = process.platform === "win32" ? "claude.exe" : "claude";
|
||||
|
||||
let bundledCliDirectory: string | undefined;
|
||||
|
||||
/**
|
||||
* Called by the executable's entry (`src/binary-entry.ts`) before the agent
|
||||
* starts. A `bun build --compile` executable has no `node_modules` to resolve
|
||||
* the SDK's platform package from, so the release archive ships the Claude CLI
|
||||
* next to it. The CLI isn't embedded: a child process can't run a file inside
|
||||
* Bun's `$bunfs`, so an embedded copy would have to be extracted to disk first.
|
||||
*/
|
||||
export function useBundledClaudeCli(directory: string): void {
|
||||
bundledCliDirectory = directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Claude CLI binary to spawn: `CLAUDE_CODE_EXECUTABLE` if set, then the CLI
|
||||
* shipped next to the executable, then the SDK's platform-specific package.
|
||||
*/
|
||||
export async function claudeCliPath(): Promise<string> {
|
||||
if (process.env.CLAUDE_CODE_EXECUTABLE) {
|
||||
return process.env.CLAUDE_CODE_EXECUTABLE;
|
||||
}
|
||||
if (bundledCliDirectory !== undefined) {
|
||||
return bundledClaudeCliPath(bundledCliDirectory);
|
||||
}
|
||||
return installedClaudeCliPath();
|
||||
}
|
||||
|
||||
function bundledClaudeCliPath(directory: string): string {
|
||||
const path = join(directory, CLI_FILE_NAME);
|
||||
// Without this check, spawning a missing CLI fails with a bare ENOENT.
|
||||
if (!existsSync(path)) {
|
||||
throw new Error(
|
||||
`The Claude CLI is missing: expected ${path}. Keep ${CLI_FILE_NAME} from the release archive ` +
|
||||
"in the same directory as claude-agent-acp, or set CLAUDE_CODE_EXECUTABLE to a Claude CLI binary.",
|
||||
);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
async function installedClaudeCliPath(): Promise<string> {
|
||||
// The SDK's CLI is a native binary shipped as a platform-specific optional
|
||||
// dependency of @anthropic-ai/claude-agent-sdk. Resolve via a require bound
|
||||
// to the SDK so nested installs are found even when npm doesn't hoist.
|
||||
const { createRequire } = await import("node:module");
|
||||
const req = createRequire(import.meta.resolve("@anthropic-ai/claude-agent-sdk"));
|
||||
const ext = process.platform === "win32" ? ".exe" : "";
|
||||
// On linux, both glibc and musl variants may be installed side-by-side
|
||||
// (e.g. bunx hydrates every optional dep), so picking one by trial is
|
||||
// unreliable: the wrong binary segfaults at runtime instead of failing to
|
||||
// spawn. Detect the runtime libc and prefer the matching variant, falling
|
||||
// back to the other only if the preferred one isn't installed.
|
||||
const candidates =
|
||||
process.platform === "linux"
|
||||
? isMuslLibc()
|
||||
? [
|
||||
`@anthropic-ai/claude-agent-sdk-linux-${process.arch}-musl/claude${ext}`,
|
||||
`@anthropic-ai/claude-agent-sdk-linux-${process.arch}/claude${ext}`,
|
||||
]
|
||||
: [
|
||||
`@anthropic-ai/claude-agent-sdk-linux-${process.arch}/claude${ext}`,
|
||||
`@anthropic-ai/claude-agent-sdk-linux-${process.arch}-musl/claude${ext}`,
|
||||
]
|
||||
: [`@anthropic-ai/claude-agent-sdk-${process.platform}-${process.arch}/claude${ext}`];
|
||||
for (const candidate of candidates) {
|
||||
try {
|
||||
return req.resolve(candidate);
|
||||
} catch {
|
||||
// try next candidate
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Claude native binary not found for ${process.platform}-${process.arch}. ` +
|
||||
`Reinstall @anthropic-ai/claude-agent-sdk without --omit=optional, or set CLAUDE_CODE_EXECUTABLE.`,
|
||||
);
|
||||
}
|
||||
|
||||
function isMuslLibc(): boolean {
|
||||
// process.report.getReport().header.glibcVersionRuntime is populated when
|
||||
// Node is dynamically linked against glibc, and absent on musl.
|
||||
const report = process.report?.getReport() as
|
||||
{ header?: { glibcVersionRuntime?: string } } | undefined;
|
||||
return !report?.header?.glibcVersionRuntime;
|
||||
}
|
||||
@@ -45,6 +45,7 @@ export type ClearContextSession<Turn extends ClearContextTurn = ClearContextTurn
|
||||
turnQueue?: Turn[];
|
||||
pendingExitPlanContextReset?: ClearContextReset;
|
||||
contextUsedTokens?: number;
|
||||
contextWindowSize: number;
|
||||
sentUserUuids?: Set<string>;
|
||||
input: { push(message: SDKUserMessage): unknown };
|
||||
};
|
||||
@@ -61,10 +62,13 @@ export type ClearContextCoordinatorHost<
|
||||
): Promise<Session>;
|
||||
applyFastMode(session: Session, enabled: boolean): Promise<void>;
|
||||
applyUltracode(session: Session, enabled: boolean): Promise<void>;
|
||||
/** Publishes the fresh context's mode, config options, and usage: the
|
||||
* context starts empty in a window of `contextWindowSize` tokens. */
|
||||
publishSessionState(
|
||||
sessionId: string,
|
||||
mode: PermissionMode,
|
||||
configOptions: SessionConfigOption[],
|
||||
contextWindowSize: number,
|
||||
): Promise<void>;
|
||||
continuationMessage(sessionId: string, plan: string, promptUuid: string): SDKUserMessage;
|
||||
ensureConsumer(session: Session, sessionId: string): void;
|
||||
@@ -165,7 +169,12 @@ export async function continuePlanInFreshContext<
|
||||
freshSession.contextUsedTokens = 0;
|
||||
|
||||
try {
|
||||
await host.publishSessionState(sessionId, reset.mode, freshSession.configOptions);
|
||||
await host.publishSessionState(
|
||||
sessionId,
|
||||
reset.mode,
|
||||
freshSession.configOptions,
|
||||
freshSession.contextWindowSize,
|
||||
);
|
||||
} catch (error) {
|
||||
host.logError("Failed to publish clear-context session state:", error);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AIR_CONTEXT_COMPACTION_KEY, withAirMeta } from "./air-extension.js";
|
||||
|
||||
export const CONTEXT_COMPACTION_META_VERSION = 1;
|
||||
|
||||
export type ContextCompactionTrigger = "manual" | "automatic";
|
||||
export type ContextCompactionTrigger = "manual" | "automatic" | "idle";
|
||||
|
||||
export interface ContextCompactionMetadata {
|
||||
version: typeof CONTEXT_COMPACTION_META_VERSION;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ClientCapabilities, SessionNotification } from "@agentclientprotocol/sdk/unstable";
|
||||
import {
|
||||
ContextCompactionMetadata,
|
||||
ContextCompactionTrigger,
|
||||
createContextCompactionMeta,
|
||||
} from "./context-compaction-meta.js";
|
||||
import { compactionToolCall } from "./tool-calls/reporters/compaction.js";
|
||||
@@ -408,14 +409,29 @@ function withoutError({
|
||||
return facts;
|
||||
}
|
||||
|
||||
export function contextCompactionMetadataFromBoundary(compactMetadata: {
|
||||
trigger: "manual" | "auto";
|
||||
pre_tokens: number;
|
||||
post_tokens?: number;
|
||||
duration_ms?: number;
|
||||
}): Omit<ContextCompactionMetadata, "version"> {
|
||||
function compactionTrigger(
|
||||
cliTrigger: "manual" | "auto",
|
||||
sentByAdapter: boolean,
|
||||
): ContextCompactionTrigger {
|
||||
// The CLI's own automatic compaction stays automatic, even inside the adapter's /compact turn.
|
||||
if (cliTrigger === "auto") return "automatic";
|
||||
// The CLI reports every /compact as manual; only the adapter knows it sent this one itself.
|
||||
if (sentByAdapter) return "idle";
|
||||
return "manual";
|
||||
}
|
||||
|
||||
/** `idleCompaction` marks a `/compact` that the adapter sent itself (see `IdleCompaction`). */
|
||||
export function contextCompactionMetadataFromBoundary(
|
||||
compactMetadata: {
|
||||
trigger: "manual" | "auto";
|
||||
pre_tokens: number;
|
||||
post_tokens?: number;
|
||||
duration_ms?: number;
|
||||
},
|
||||
{ idleCompaction = false }: { idleCompaction?: boolean } = {},
|
||||
): Omit<ContextCompactionMetadata, "version"> {
|
||||
return {
|
||||
trigger: compactMetadata.trigger === "auto" ? "automatic" : "manual",
|
||||
trigger: compactionTrigger(compactMetadata.trigger, idleCompaction),
|
||||
preTokens: compactMetadata.pre_tokens,
|
||||
...(compactMetadata.post_tokens !== undefined
|
||||
? { postTokens: compactMetadata.post_tokens }
|
||||
|
||||
12
src/diff.ts
12
src/diff.ts
@@ -89,7 +89,7 @@ export type PatchForm = "air" | "v2";
|
||||
/**
|
||||
* How a git patch names its file. `git` is git's own form: the leading slash
|
||||
* dropped and the `a/` and `b/` prefixes added. `absolute` is the form of an
|
||||
* ACP v2 `git_patch`, whose paths must be absolute: the path itself.
|
||||
* ACP v2 `git_patch`, whose paths must be absolute: the native path itself.
|
||||
*/
|
||||
type GitPatchPaths = "git" | "absolute";
|
||||
|
||||
@@ -438,11 +438,11 @@ export function gitPatchText(
|
||||
}
|
||||
|
||||
function gitPatchHeader(filePath: string, change: FileChange, paths: GitPatchPaths): string[] {
|
||||
// A Windows path gets forward slashes so the header names the same file on
|
||||
// every platform.
|
||||
const slashed = filePath.replaceAll("\\", "/");
|
||||
// git drops one leading slash of an absolute path.
|
||||
const name = paths === "git" ? slashed.replace(/^\/+/u, "") : slashed;
|
||||
// git's form uses forward slashes, so the header names the same file on
|
||||
// every platform, and drops one leading slash of an absolute path. An ACP v2
|
||||
// patch keeps the native path so that, once unquoted, it equals the `changes`
|
||||
// entry: `C:\work\App.ts` is written `"C:\\work\\App.ts"`.
|
||||
const name = paths === "git" ? filePath.replaceAll("\\", "/").replace(/^\/+/u, "") : filePath;
|
||||
const oldName = quoteGitPath(paths === "git" ? "a/" : "", name);
|
||||
const newName = quoteGitPath(paths === "git" ? "b/" : "", name);
|
||||
// git ends a ---/+++ name that contains a space with a tab, for GNU patch.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { CreateElicitationResponse } from "@agentclientprotocol/sdk/unstable";
|
||||
import type {
|
||||
CreateElicitationRequest,
|
||||
ElicitationAcceptAction,
|
||||
CreateElicitationResponse,
|
||||
ElicitationPropertySchema,
|
||||
ElicitationSchema,
|
||||
EnumOption,
|
||||
@@ -75,17 +74,22 @@ export function mcpElicitationToCreateRequest(
|
||||
}
|
||||
|
||||
/**
|
||||
* Content of an accepted elicitation response.
|
||||
* Content of an accepted elicitation response, or `{}` when the response is
|
||||
* no accept or its `content` is no JSON object.
|
||||
*
|
||||
* Uses the SDK's validating guard rather than an `action === "accept"` check:
|
||||
* the guard both narrows past the union's custom/future variant and validates
|
||||
* the payload, so a malformed accept (right tag, ill-typed content) yields
|
||||
* empty content — the same classification the SDK's wire validators apply.
|
||||
* The values are not checked. v1 allows a string, number, boolean, or string
|
||||
* array; v2 also allows any other JSON value, such as an object. An MCP
|
||||
* server checks the content against its own `requestedSchema`, so it gets the
|
||||
* content as the client sent it: before, an accept whose content held an
|
||||
* object reached the server as `{ action: "accept", content: {} }`. Callers
|
||||
* that read a field must check its type.
|
||||
*/
|
||||
function acceptedElicitationContent(
|
||||
response: CreateElicitationResponse,
|
||||
): NonNullable<ElicitationAcceptAction["content"]> {
|
||||
return CreateElicitationResponse.isAccept(response) ? (response.content ?? {}) : {};
|
||||
function acceptedElicitationContent(response: CreateElicitationResponse): Record<string, unknown> {
|
||||
if (response.action !== "accept") return {};
|
||||
const content: unknown = (response as { content?: unknown }).content;
|
||||
return content !== null && typeof content === "object" && !Array.isArray(content)
|
||||
? (content as Record<string, unknown>)
|
||||
: {};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +101,11 @@ export function createElicitationResponseToElicitResult(
|
||||
): ElicitationResult {
|
||||
switch (response.action) {
|
||||
case "accept":
|
||||
return { action: "accept", content: acceptedElicitationContent(response) };
|
||||
// `ElicitResult` types the values as v1 does. The MCP server checks them.
|
||||
return {
|
||||
action: "accept",
|
||||
content: acceptedElicitationContent(response) as ElicitationResult["content"],
|
||||
};
|
||||
case "decline":
|
||||
return { action: "decline" };
|
||||
case "cancel":
|
||||
@@ -295,7 +303,7 @@ export function applyAskElicitationResponse(
|
||||
questions: AskUserQuestion[],
|
||||
options: { reportUnanswered?: boolean } = {},
|
||||
): AskUserQuestionOutcome {
|
||||
// Typed against the output schema: as of SDK 0.3.312 only it lists
|
||||
// Typed against the output schema: as of SDK 0.3.318 only it lists
|
||||
// `unanswered`, though the tool reads the same annotations from its input.
|
||||
const annotations: NonNullable<AskUserQuestionOutput["annotations"]> = {};
|
||||
const withAnnotations = (answers: AskUserQuestionOutput["answers"]) => ({
|
||||
@@ -325,13 +333,13 @@ export function applyAskElicitationResponse(
|
||||
const custom = content[questionCustomFieldKey(index)];
|
||||
const customText = typeof custom === "string" ? custom.trim() : "";
|
||||
|
||||
// A pick is a string, number, or boolean. Other values, such as an object
|
||||
// that a v2 client may send, are dropped instead of read as "[object Object]".
|
||||
const value = content[questionFieldKey(index)];
|
||||
const picks: string[] =
|
||||
value === undefined || value === null
|
||||
? []
|
||||
: Array.isArray(value)
|
||||
? value.filter((item) => item !== undefined && item !== null && item !== "").map(String)
|
||||
: [String(value)];
|
||||
const picks: string[] = (Array.isArray(value) ? value : [value])
|
||||
.filter(isElicitationScalar)
|
||||
.map(String)
|
||||
.filter((item) => item !== "");
|
||||
|
||||
// A multi-select is additive, and the form offers the selection and the
|
||||
// custom box as independent fields — a user who fills both means both, so
|
||||
@@ -374,10 +382,16 @@ export function applyAskElicitationResponse(
|
||||
return { action: "answered", updatedInput: withAnnotations(answers) };
|
||||
}
|
||||
|
||||
function isElicitationScalar(value: unknown): value is string | number | boolean {
|
||||
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce an arbitrary MCP `requestedSchema` into an ACP `ElicitationSchema`.
|
||||
* The two are structurally compatible JSON Schemas; we just guarantee the
|
||||
* `type: "object"` discriminator is present.
|
||||
* `type: "object"` discriminator and a `properties` map are present. The v2
|
||||
* schema requires both, so a client on SDK 2.2.0 or later rejects an MCP
|
||||
* schema such as `{ type: "object" }` that has no `properties`.
|
||||
*/
|
||||
function normalizeElicitationSchema(
|
||||
schema: Record<string, unknown> | undefined,
|
||||
@@ -385,7 +399,8 @@ function normalizeElicitationSchema(
|
||||
if (!schema || typeof schema !== "object") {
|
||||
return { type: "object", properties: {} };
|
||||
}
|
||||
return { ...(schema as ElicitationSchema), type: "object" };
|
||||
const { properties } = schema as Partial<ElicitationSchema>;
|
||||
return { ...(schema as ElicitationSchema), type: "object", properties: properties ?? {} };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -213,7 +213,7 @@ export class ExitPlanCoordinator<
|
||||
try {
|
||||
const clearContextHost: ClearContextCoordinatorHost<Session, Turn> = {
|
||||
...this.host,
|
||||
publishSessionState: async (id, mode, configOptions) => {
|
||||
publishSessionState: async (id, mode, configOptions, contextWindowSize) => {
|
||||
await this.host.sessionUpdate({
|
||||
sessionId: id,
|
||||
update: { sessionUpdate: "current_mode_update", currentModeId: mode },
|
||||
@@ -222,6 +222,12 @@ export class ExitPlanCoordinator<
|
||||
sessionId: id,
|
||||
update: { sessionUpdate: "config_option_update", configOptions },
|
||||
});
|
||||
// Otherwise the client shows the old context's usage until the fresh
|
||||
// context first reports its own.
|
||||
await this.host.sessionUpdate({
|
||||
sessionId: id,
|
||||
update: { sessionUpdate: "usage_update", used: 0, size: contextWindowSize },
|
||||
});
|
||||
// The approved plan becomes the session's plan once the fresh
|
||||
// context that carries it out exists. Its ExitPlanMode ended with
|
||||
// an error result, so toAcpNotifications did not publish it.
|
||||
|
||||
@@ -176,9 +176,37 @@ function resolveFromFullHistory(
|
||||
return occurrenceMatches.length === 1 ? occurrenceMatches[0]?.uuid : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether `error` is the Claude SDK's report that `sessionId` has no
|
||||
* transcript: `forkSession` and `importSessionToStore` throw
|
||||
* `Error("Session <id> not found")`, and both throw
|
||||
* `"Invalid sessionId: <id>"` for an id that is not a UUID.
|
||||
*/
|
||||
function isUnknownSessionError(error: unknown, sessionId: string): boolean {
|
||||
if (!(error instanceof Error)) return false;
|
||||
return (
|
||||
error.message === `Session ${sessionId} not found` ||
|
||||
error.message === `Invalid sessionId: ${sessionId}`
|
||||
);
|
||||
}
|
||||
|
||||
export async function forkSession(
|
||||
params: ForkSessionRequest,
|
||||
dependencies: ForkSessionDependencies,
|
||||
): Promise<ForkSessionResponse> {
|
||||
try {
|
||||
return await forkTranscript(params, dependencies);
|
||||
} catch (error) {
|
||||
if (isUnknownSessionError(error, params.sessionId)) {
|
||||
throw RequestError.sessionNotFound(params.sessionId);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function forkTranscript(
|
||||
params: ForkSessionRequest,
|
||||
dependencies: ForkSessionDependencies,
|
||||
): Promise<ForkSessionResponse> {
|
||||
const timing = new SessionTiming(dependencies.logger, "fork", params.sessionId);
|
||||
const point = forkPoint(params._meta);
|
||||
|
||||
240
src/idle-compaction.ts
Normal file
240
src/idle-compaction.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
export type PromptCacheTtl = "5m" | "1h";
|
||||
|
||||
export type IdleCompactionHost = {
|
||||
/** Claude is working (`startTurn`'s check) or a permission request / user input is pending. */
|
||||
isBusy(): boolean;
|
||||
/** Context size after the last main-thread request, or undefined if unknown. */
|
||||
contextTokens(): number | undefined;
|
||||
/** Current merged Claude Code settings. */
|
||||
settings(): {
|
||||
idleCompaction?: boolean;
|
||||
autoCompactEnabled?: boolean;
|
||||
env?: Record<string, string | undefined>;
|
||||
};
|
||||
/** Runs `/compact` as an adapter-originated turn; settles with that turn. */
|
||||
compact(): Promise<unknown>;
|
||||
/** Debug-level log. */
|
||||
log(message: string): void;
|
||||
};
|
||||
|
||||
export type IdleCompactionOptions = {
|
||||
env?: Record<string, string | undefined>;
|
||||
setTimeout?: (callback: () => void, ms: number) => unknown;
|
||||
};
|
||||
|
||||
/** The longest delay `setTimeout` takes; a longer one fires at once. */
|
||||
const MAX_TIMER_MS = 2_147_483_647;
|
||||
const HOUR_MS = 3_600_000;
|
||||
const DEFAULT_MIN_TOKENS = 200_000;
|
||||
const MIN_TOKENS_FLOOR = 100_000;
|
||||
// 54 min for a 1h cache: leaves a margin for the gap between the provider
|
||||
// writing the cache and the adapter receiving the response.
|
||||
const DEFAULT_DELAY_MS = 0.9 * HOUR_MS;
|
||||
// Node timers do not run while the machine sleeps, so one can fire hours after
|
||||
// its deadline, on a cache that expired meanwhile. Same threshold as Claude Code.
|
||||
const LAPSED_AFTER_MS = 60_000;
|
||||
// The values Claude Code reads as "on" for env flags such as DISABLE_COMPACT
|
||||
// (case-insensitive, trimmed).
|
||||
const TRUTHY_ENV = new Set(["1", "true", "yes", "on"]);
|
||||
|
||||
function isTruthyEnv(value: string | undefined): boolean {
|
||||
return value !== undefined && TRUTHY_ENV.has(value.trim().toLowerCase());
|
||||
}
|
||||
|
||||
function parseCacheTtl(usage: unknown): PromptCacheTtl | undefined {
|
||||
const creation = (usage as { cache_creation?: unknown } | null | undefined)?.cache_creation;
|
||||
if (typeof creation !== "object" || creation === null) return undefined;
|
||||
const { ephemeral_1h_input_tokens: hour, ephemeral_5m_input_tokens: fiveMin } = creation as {
|
||||
ephemeral_1h_input_tokens?: unknown;
|
||||
ephemeral_5m_input_tokens?: unknown;
|
||||
};
|
||||
if (typeof hour === "number" && hour > 0) return "1h";
|
||||
if (typeof fiveMin === "number" && fiveMin > 0) return "5m";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compacts a session shortly before its one-hour prompt cache expires, so the
|
||||
* next prompt writes a short summary instead of the whole context. Claude Code
|
||||
* has this feature but arms it only for "attended" sessions, which SDK sessions
|
||||
* are not. One instance per session.
|
||||
*/
|
||||
export class IdleCompaction {
|
||||
private readonly env: Record<string, string | undefined>;
|
||||
private readonly setTimer: (callback: () => void, ms: number) => unknown;
|
||||
private ttl: PromptCacheTtl | undefined;
|
||||
private lastRequestAt: number | undefined;
|
||||
private lastMessageId: string | undefined;
|
||||
/** Set when `/compact` was sent, cleared by the next request: a compaction that failed,
|
||||
* or left the context large, would otherwise re-arm at once and loop until the user prompts. */
|
||||
private compactedSinceLastRequest = false;
|
||||
private timer: unknown;
|
||||
private compacting = false;
|
||||
private disposed = false;
|
||||
private warnedInvalidDelay = false;
|
||||
/** `status` of the last `rate_limit_event`; unknown until one arrives. */
|
||||
private rateLimitStatus: string | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly host: IdleCompactionHost,
|
||||
options: IdleCompactionOptions = {},
|
||||
) {
|
||||
this.env = options.env ?? process.env;
|
||||
this.setTimer = options.setTimeout ?? ((cb, ms) => setTimeout(cb, ms));
|
||||
}
|
||||
|
||||
/** Whether an idle compaction it started is still running. `acp-agent.ts` reports
|
||||
* `trigger: "idle"` while it is true. A client's `/compact` queued behind is read
|
||||
* only after the adapter's turn's `result`, which clears `compacting`; this relies
|
||||
* on the CLI emitting that compaction's `compact_boundary` after the previous
|
||||
* result, which nothing here enforces. */
|
||||
get isCompacting(): boolean {
|
||||
return this.compacting;
|
||||
}
|
||||
|
||||
/** A main-thread response arrived. Records its time and cache TTL, and drops any armed timer.
|
||||
* The provider writes the cache when the request starts, so the deadline is measured from the
|
||||
* response's first sighting: the `message_start` stream event, or its first `assistant` message
|
||||
* when it was not streamed. The CLI sends one `assistant` message per content block, and a
|
||||
* 7-minute response would otherwise put the deadline 7 minutes after the cache was written.
|
||||
* A later call with the same `messageId` only updates the TTL. */
|
||||
noteRequest(usage: unknown, messageId?: string): void {
|
||||
if (this.disposed) return;
|
||||
this.ttl = parseCacheTtl(usage) ?? this.ttl;
|
||||
if (messageId !== undefined && messageId === this.lastMessageId) return;
|
||||
this.lastMessageId = messageId;
|
||||
this.lastRequestAt = Date.now();
|
||||
this.compactedSinceLastRequest = false;
|
||||
this.disarm("new request");
|
||||
}
|
||||
|
||||
/** The session became idle. Arms the timer if every condition holds, else logs why not. */
|
||||
onIdle(): void {
|
||||
if (this.disposed) return;
|
||||
const skip = this.skipReason();
|
||||
if (skip) {
|
||||
this.host.log(`[idle-compaction] skip: ${skip}`);
|
||||
return;
|
||||
}
|
||||
this.disarm("rearm");
|
||||
const deadline = this.lastRequestAt! + this.delayMs();
|
||||
this.timer = this.setTimer(() => void this.fire(), Math.max(0, deadline - Date.now()));
|
||||
(this.timer as { unref?: () => void } | undefined)?.unref?.();
|
||||
this.host.log(`[idle-compaction] armed deadline=${new Date(deadline).toISOString()}`);
|
||||
}
|
||||
|
||||
/** A `rate_limit_event` arrived (`SDKRateLimitInfo`). Anything but `allowed` skips compaction,
|
||||
* as in Claude Code. This is account state, so `reset()` keeps it. */
|
||||
noteRateLimit(info: unknown): void {
|
||||
const status = (info as { status?: unknown } | null | undefined)?.status;
|
||||
if (typeof status === "string") this.rateLimitStatus = status;
|
||||
}
|
||||
|
||||
/** Claude Code reported its compaction as failed. Its turn still ends normally, so `compact()` does not reject. */
|
||||
noteCompactionFailed(error: string | undefined): void {
|
||||
if (!this.compacting) return;
|
||||
this.host.log(`[idle-compaction] compaction failed: ${error ?? "no reason given"}`);
|
||||
}
|
||||
|
||||
/** The conversation was replaced (`/clear`): forgets the recorded request and TTL, and drops any armed timer. */
|
||||
reset(): void {
|
||||
this.ttl = undefined;
|
||||
this.lastRequestAt = undefined;
|
||||
this.lastMessageId = undefined;
|
||||
this.compactedSinceLastRequest = false;
|
||||
this.disarm("conversation reset");
|
||||
}
|
||||
|
||||
/** Drops the armed timer, if any. `reason` is only logged. */
|
||||
disarm(reason: string): void {
|
||||
if (this.timer === undefined) return;
|
||||
clearTimeout(this.timer as ReturnType<typeof setTimeout>);
|
||||
this.timer = undefined;
|
||||
this.host.log(`[idle-compaction] disarmed: ${reason}`);
|
||||
}
|
||||
|
||||
/** Disarms and ignores every later call. */
|
||||
dispose(): void {
|
||||
this.disarm("disposed");
|
||||
this.disposed = true;
|
||||
}
|
||||
|
||||
private async fire(): Promise<void> {
|
||||
this.timer = undefined;
|
||||
if (this.disposed) return;
|
||||
const skip = this.skipReason();
|
||||
if (skip) {
|
||||
this.host.log(`[idle-compaction] skip at fire: ${skip}`);
|
||||
return;
|
||||
}
|
||||
this.host.log("[idle-compaction] firing /compact");
|
||||
this.compacting = true;
|
||||
this.compactedSinceLastRequest = true;
|
||||
try {
|
||||
await this.host.compact();
|
||||
} catch (error) {
|
||||
this.host.log(`[idle-compaction] compaction failed: ${error}`);
|
||||
} finally {
|
||||
this.compacting = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Why no compaction should be scheduled right now, or undefined if all conditions hold. */
|
||||
private skipReason(): string | undefined {
|
||||
if (this.compacting) return "compaction already running";
|
||||
const disabled = this.disabledBy();
|
||||
if (disabled) return `disabled by ${disabled}`;
|
||||
if (this.lastRequestAt === undefined) return "no request recorded in this process";
|
||||
if (Date.now() > this.lastRequestAt + this.delayMs() + LAPSED_AFTER_MS) {
|
||||
return "cache lapsed: more than 60 s past the deadline";
|
||||
}
|
||||
if (this.rateLimitStatus !== undefined && this.rateLimitStatus !== "allowed") {
|
||||
return `rate limit status is ${this.rateLimitStatus}`;
|
||||
}
|
||||
if (this.compactedSinceLastRequest) return "already compacted for this request";
|
||||
if (this.ttl !== "1h") return `cache TTL is ${this.ttl ?? "unknown"}, not 1h`;
|
||||
const tokens = this.host.contextTokens();
|
||||
const min = this.minTokens();
|
||||
if (tokens === undefined || tokens < min) {
|
||||
return `context ${tokens ?? "unknown"} tokens is below the ${min} minimum`;
|
||||
}
|
||||
if (this.host.isBusy()) return "session is busy";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private disabledBy(): string | undefined {
|
||||
const settings = this.host.settings();
|
||||
if (settings.idleCompaction === false) return "idleCompaction setting";
|
||||
if (settings.autoCompactEnabled === false) return "autoCompactEnabled setting";
|
||||
for (const name of ["DISABLE_COMPACT", "DISABLE_AUTO_COMPACT"]) {
|
||||
if (isTruthyEnv(this.claudeCodeEnv(name))) return name;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** The CLI applies the settings `env` block after the launch env, so it wins. */
|
||||
private claudeCodeEnv(name: string): string | undefined {
|
||||
return this.host.settings().env?.[name] ?? this.env[name];
|
||||
}
|
||||
|
||||
/** `0` and invalid values fall back to 200,000, as in the CLI, which declares the variable
|
||||
* with `min: 1` and computes `Math.max(100000, env ?? 200000)`. */
|
||||
private minTokens(): number {
|
||||
const raw = this.claudeCodeEnv("CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS");
|
||||
const parsed = raw !== undefined && /^\d+$/.test(raw.trim()) ? Number(raw.trim()) : 0;
|
||||
return Math.max(MIN_TOKENS_FLOOR, parsed > 0 ? parsed : DEFAULT_MIN_TOKENS);
|
||||
}
|
||||
|
||||
private delayMs(): number {
|
||||
const raw = this.env.CLAUDE_AGENT_ACP_IDLE_COMPACT_DELAY_MS;
|
||||
if (raw === undefined) return DEFAULT_DELAY_MS;
|
||||
if (/^\d+$/.test(raw.trim()) && Number(raw.trim()) <= MAX_TIMER_MS) return Number(raw.trim());
|
||||
if (!this.warnedInvalidDelay) {
|
||||
this.warnedInvalidDelay = true;
|
||||
this.host.log(
|
||||
`[idle-compaction] ignoring invalid CLAUDE_AGENT_ACP_IDLE_COMPACT_DELAY_MS=${raw}`,
|
||||
);
|
||||
}
|
||||
return DEFAULT_DELAY_MS;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { claudeCliPath } from "./acp-agent.js";
|
||||
import { claudeCliPath } from "./claude-cli.js";
|
||||
import { applyManagedPolicyEnv } from "./managed-policy.js";
|
||||
import { acpProtocolsFromEnv, serveAcp } from "./serve.js";
|
||||
import packageJson from "../package.json" with { type: "json" };
|
||||
|
||||
@@ -111,8 +111,11 @@ function needsReconnect(status: McpServerStatus): boolean {
|
||||
function codeSpan(text: string): string {
|
||||
const longestRun = Math.max(0, ...(text.match(/`+/g) ?? []).map((run) => run.length));
|
||||
const fence = "`".repeat(longestRun + 1);
|
||||
// CommonMark strips one space from each end of a span, so a pad keeps the text unchanged.
|
||||
const pad = text.startsWith("`") || text.endsWith("`") || /^ .*[^ ].* $/.test(text) ? " " : "";
|
||||
// CommonMark strips one space from each end of a span that is not all spaces
|
||||
// (line endings count as spaces), so a pad keeps the text unchanged. Plain
|
||||
// string checks, not one regex: `^ .*[^ ].* $` backtracks quadratically.
|
||||
const strippedByCommonMark = text.startsWith(" ") && text.endsWith(" ") && /[^ \r\n]/.test(text);
|
||||
const pad = text.startsWith("`") || text.endsWith("`") || strippedByCommonMark ? " " : "";
|
||||
return `${fence}${pad}${text}${pad}${fence}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
type SessionConfigOption,
|
||||
type SessionNotification,
|
||||
} from "@agentclientprotocol/sdk/unstable";
|
||||
import { realpath } from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import type { AcpSessionNotification, SubagentForm, SubagentState } from "./acp-subagents.js";
|
||||
import { AIR_SUBAGENT_KEY, airExtensionMeta } from "./air-extension.js";
|
||||
import { MODEL_CONFIG_ID } from "./session-model.js";
|
||||
@@ -56,14 +58,23 @@ export type NativeSubagent = {
|
||||
/** The RFD form: the calls that delegated to the child, whose runs handed back a report. */
|
||||
handedBack?: Set<string>;
|
||||
announced?: boolean;
|
||||
/**
|
||||
* The RFD form: the `cwd` that the client holds for the child. Undefined or
|
||||
* null while the child inherits its parent's working directory.
|
||||
*/
|
||||
reportedCwd?: string | null;
|
||||
terminalState?: SubagentState;
|
||||
/** Connection-local single-flight state; never serialized on the wire. */
|
||||
announcePromise?: Promise<void>;
|
||||
/** Connection-local: serializes the child's `cwd` reports; never serialized on the wire. */
|
||||
cwdPublishing?: Promise<void>;
|
||||
/** Connection-local single-flight state; never serialized on the wire. */
|
||||
terminalPromise?: Promise<void>;
|
||||
};
|
||||
|
||||
export type NativeSubagentSession = {
|
||||
/** The working directory of the root session, which a child inherits unless it reports its own. */
|
||||
cwd?: string;
|
||||
nativeSubagentsByTaskId?: Map<string, NativeSubagent>;
|
||||
nativeSubagentTaskIdByToolUseId?: Map<string, string>;
|
||||
nativeSubagentParentByToolUseId?: Map<string, string>;
|
||||
@@ -133,6 +144,8 @@ export type HistoricalSubagent = {
|
||||
launchId: string;
|
||||
/** The agent that made that call. None means the root session. */
|
||||
parentAgentId?: string;
|
||||
/** Its working directory, when Claude Code placed it elsewhere, e.g. in a worktree. */
|
||||
cwd?: string;
|
||||
name?: string;
|
||||
agentType?: string;
|
||||
description?: string;
|
||||
@@ -172,6 +185,11 @@ export class NativeSubagentRuntime {
|
||||
private readonly identityByToolUse = new Map<string, SubagentIdentity>();
|
||||
private readonly controlByToolUse = new Map<string, AcpSessionNotification>();
|
||||
private readonly configBySession = new Map<string, ChildConfiguration>();
|
||||
/**
|
||||
* The RFD form: the working directory of each child, by session id, as its
|
||||
* hooks last reported it. A hook can come before the child is announced.
|
||||
*/
|
||||
private readonly cwdBySession = new Map<string, string>();
|
||||
private readonly childByParentToolUse = new Map<string, NativeSubagent>();
|
||||
/**
|
||||
* The child session of each tool call that went to a child session. A later
|
||||
@@ -274,6 +292,30 @@ export class NativeSubagentRuntime {
|
||||
return child?.announced ? child.workState : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* The RFD form: the `subagent_update` that tells a client that holds nothing
|
||||
* of the announced child `sessionId` of this live session what it is now:
|
||||
* its labels, its directory, its `cancel` capability, and its work state.
|
||||
* Undefined when no such child runs here.
|
||||
*/
|
||||
currentUpdate(sessionId: string): AcpSessionNotification | undefined {
|
||||
if (this.form !== "rfd") return undefined;
|
||||
const child = this.childOfSession(sessionId);
|
||||
if (!child?.announced || !child.workState) return undefined;
|
||||
return {
|
||||
sessionId: child.parentSessionId,
|
||||
update: {
|
||||
sessionUpdate: "subagent_update",
|
||||
sessionId: child.sessionId,
|
||||
...(child.title ? { title: child.title } : {}),
|
||||
...(child.description ? { description: child.description } : {}),
|
||||
...(child.reportedCwd ? { cwd: child.reportedCwd } : {}),
|
||||
capabilities: { cancel: {} },
|
||||
state: { state: child.workState },
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the model of a child response, an exact model id, as the entry of
|
||||
* the root session's `model` option that matches it, else as the id (see
|
||||
@@ -400,6 +442,83 @@ export class NativeSubagentRuntime {
|
||||
await publishing;
|
||||
}
|
||||
|
||||
/**
|
||||
* The RFD form: takes the working directory of the child `agentId`, the
|
||||
* `cwd` of one of its hooks. A child that Claude Code runs in its own
|
||||
* worktree (Agent `isolation: "worktree"`) reports the worktree. The client
|
||||
* gets the `cwd` only when it differs from the parent's, in the
|
||||
* announcement or in a `subagent_update` right after it. Claude Code runs a
|
||||
* child's SubagentStart hook before its first model request, so the `cwd`
|
||||
* reaches the client before the child's first tool call.
|
||||
*/
|
||||
async reportCwd(agentId: string, cwd: string): Promise<void> {
|
||||
if (this.form !== "rfd" || agentId === this.rootSessionId || !path.isAbsolute(cwd)) return;
|
||||
const known = this.children.get(agentId) ?? this.childOfSession(agentId);
|
||||
const sessionId = known?.sessionId ?? agentId;
|
||||
if (!known && !this.cwdBySession.has(sessionId)) {
|
||||
const pending = [...this.cwdBySession.keys()].filter((id) => !this.childOfSession(id)).length;
|
||||
if (pending >= MAX_PENDING_PARENTS) {
|
||||
this.logger.log(
|
||||
`Session ${this.rootSessionId}: dropping cwd for unannounced subagent ${agentId}; pending buffer limit reached`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.cwdBySession.set(sessionId, cwd);
|
||||
if (!known) return;
|
||||
// An announcement in flight may have been built without this `cwd`.
|
||||
if (known.announcePromise) await known.announcePromise.catch(() => {});
|
||||
if (known.announced) await this.publishCwd(known);
|
||||
}
|
||||
|
||||
/**
|
||||
* The `cwd` of `child` that the client does not hold yet: its working
|
||||
* directory when that differs from its parent's, `null` when it is back in
|
||||
* the parent's after it reported another, else undefined.
|
||||
*/
|
||||
private async unreportedCwd(child: NativeSubagent): Promise<string | null | undefined> {
|
||||
const cwd = this.cwdBySession.get(child.sessionId);
|
||||
if (cwd === undefined) return undefined;
|
||||
const inherited = this.effectiveCwd(child.parentSessionId);
|
||||
if (inherited !== undefined && (await sameDirectory(cwd, inherited))) {
|
||||
return child.reportedCwd ? null : undefined;
|
||||
}
|
||||
return cwd === child.reportedCwd ? undefined : cwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* The working directory of the session `sessionId` as the client holds it:
|
||||
* the root's from session setup, a child's reported `cwd`, else its
|
||||
* parent's.
|
||||
*/
|
||||
private effectiveCwd(sessionId: string): string | undefined {
|
||||
const seen = new Set<string>();
|
||||
let child = this.childOfSession(sessionId);
|
||||
while (child && !seen.has(child.sessionId)) {
|
||||
if (child.reportedCwd) return child.reportedCwd;
|
||||
seen.add(child.sessionId);
|
||||
child = this.childOfSession(child.parentSessionId);
|
||||
}
|
||||
return this.session.cwd;
|
||||
}
|
||||
|
||||
/** The RFD form: sends the `cwd` of the announced `child` that the client does not hold. */
|
||||
private async publishCwd(child: NativeSubagent): Promise<void> {
|
||||
if (this.form !== "rfd") return;
|
||||
// Concurrent hooks of one child report the same `cwd` once.
|
||||
const publishing = (child.cwdPublishing ?? Promise.resolve()).then(async () => {
|
||||
const cwd = await this.unreportedCwd(child);
|
||||
if (cwd === undefined) return;
|
||||
await this.publish({
|
||||
sessionId: child.parentSessionId,
|
||||
update: { sessionUpdate: "subagent_update", sessionId: child.sessionId, cwd },
|
||||
});
|
||||
child.reportedCwd = cwd;
|
||||
});
|
||||
child.cwdPublishing = publishing.catch(() => {});
|
||||
await publishing;
|
||||
}
|
||||
|
||||
private async routeUpdate(
|
||||
notification: AcpSessionNotification,
|
||||
deliver: Publish,
|
||||
@@ -923,9 +1042,14 @@ export class NativeSubagentRuntime {
|
||||
this.childByParentToolUse.set(entry.launchId, child);
|
||||
}
|
||||
if (child.announced) continue;
|
||||
// A hook of the resumed agent may have reported a newer `cwd`.
|
||||
if (entry.cwd && !this.cwdBySession.has(child.sessionId)) {
|
||||
this.cwdBySession.set(child.sessionId, entry.cwd);
|
||||
}
|
||||
if (entry.agentId === agentId) {
|
||||
await this.announce(child);
|
||||
} else {
|
||||
const cwd = await this.unreportedCwd(child);
|
||||
await this.publish({
|
||||
sessionId: child.parentSessionId,
|
||||
update: {
|
||||
@@ -933,8 +1057,10 @@ export class NativeSubagentRuntime {
|
||||
sessionId: child.sessionId,
|
||||
...(child.title ? { title: child.title } : {}),
|
||||
...(child.description ? { description: child.description } : {}),
|
||||
...(cwd ? { cwd } : {}),
|
||||
},
|
||||
});
|
||||
if (cwd) child.reportedCwd = cwd;
|
||||
child.announced = true;
|
||||
}
|
||||
for (const pending of this.takePending(entry.launchId)) await deliver(pending);
|
||||
@@ -1103,6 +1229,7 @@ export class NativeSubagentRuntime {
|
||||
private withdraw(taskId: string, child: NativeSubagent): void {
|
||||
this.children.delete(taskId);
|
||||
this.configBySession.delete(child.sessionId);
|
||||
this.cwdBySession.delete(child.sessionId);
|
||||
if (child.parentToolUseId) {
|
||||
this.takePending(child.parentToolUseId);
|
||||
this.cleanupControl(child.parentToolUseId);
|
||||
@@ -1125,12 +1252,16 @@ export class NativeSubagentRuntime {
|
||||
}
|
||||
|
||||
/**
|
||||
* Announces `child` in the client's form, then its configuration. A runtime
|
||||
* without a form never does.
|
||||
* Announces `child` in the client's form, with its `cwd` in the RFD form,
|
||||
* then its configuration. A runtime without a form never does.
|
||||
*/
|
||||
private async announce(child: NativeSubagent): Promise<void> {
|
||||
if (!this.form) return;
|
||||
await announceNativeSubagent(child, this.publish, this.form);
|
||||
const cwd =
|
||||
this.form === "rfd" && !child.announced ? await this.unreportedCwd(child) : undefined;
|
||||
await announceNativeSubagent(child, this.publish, this.form, cwd ?? undefined);
|
||||
// A hook that reported a `cwd` while the announcement was being built.
|
||||
await this.publishCwd(child);
|
||||
await this.publishConfiguration(child);
|
||||
}
|
||||
|
||||
@@ -1396,6 +1527,7 @@ export class NativeSubagentRuntime {
|
||||
this.identityByToolUse.clear();
|
||||
this.controlByToolUse.clear();
|
||||
this.configBySession.clear();
|
||||
this.cwdBySession.clear();
|
||||
this.childByParentToolUse.clear();
|
||||
this.taskFinishPromises.clear();
|
||||
this.senderByToolUse.clear();
|
||||
@@ -1601,6 +1733,7 @@ export async function announceNativeSubagent(
|
||||
child: NativeSubagent,
|
||||
publish: Publish,
|
||||
form: SubagentForm,
|
||||
cwd?: string,
|
||||
): Promise<void> {
|
||||
if (child.announced) return;
|
||||
if (child.announcePromise) return child.announcePromise;
|
||||
@@ -1614,10 +1747,12 @@ export async function announceNativeSubagent(
|
||||
sessionId: child.sessionId,
|
||||
...(child.title ? { title: child.title } : {}),
|
||||
...(child.description ? { description: child.description } : {}),
|
||||
...(cwd ? { cwd } : {}),
|
||||
capabilities: { cancel: {} },
|
||||
state: { state: "running" },
|
||||
},
|
||||
});
|
||||
if (cwd) child.reportedCwd = cwd;
|
||||
child.announced = true;
|
||||
// The immediate parent made the Agent/Task call that launched the child.
|
||||
if (child.prompt) {
|
||||
@@ -2155,3 +2290,15 @@ function promptField(prompt: string | undefined): { prompt?: string } {
|
||||
function nonBlankString(value: unknown): string | undefined {
|
||||
return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether `left` and `right` are the same directory, also when one is
|
||||
* spelled through a symlink, e.g. `/tmp/project` and `/private/tmp/project`
|
||||
* on macOS. A path that does not exist is compared as written.
|
||||
*/
|
||||
export async function sameDirectory(left: string, right: string): Promise<boolean> {
|
||||
if (path.resolve(left) === path.resolve(right)) return true;
|
||||
const real = (dir: string) => realpath(dir).catch(() => path.resolve(dir));
|
||||
const [realLeft, realRight] = await Promise.all([real(left), real(right)]);
|
||||
return realLeft === realRight;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PermissionMode } from "@anthropic-ai/claude-agent-sdk";
|
||||
import type { PermissionMode, Settings } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
interface PermissionModeLogger {
|
||||
error: (...args: unknown[]) => void;
|
||||
@@ -58,3 +58,10 @@ export function resolvePermissionMode(
|
||||
|
||||
return mapped;
|
||||
}
|
||||
|
||||
/** Claude Code reads `disableAutoMode` both at the top level and under `permissions`. */
|
||||
export function autoModeDisabled(settings: Settings): boolean {
|
||||
return (
|
||||
settings.disableAutoMode === "disable" || settings.permissions?.disableAutoMode === "disable"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -387,16 +387,6 @@ function isSdkNotFound(error: unknown): boolean {
|
||||
return error instanceof Error && /^Session \S+ not found in /.test(error.message);
|
||||
}
|
||||
|
||||
/** The error the SDK `deleteSession` gives for a session id it rejects or
|
||||
* does not find, which a client without `sessionIndex` got before. */
|
||||
function sdkDeleteError(sessionId: string): Error {
|
||||
return new Error(
|
||||
isSessionId(sessionId)
|
||||
? `Session ${sessionId} not found in any project directory`
|
||||
: `Invalid sessionId: ${sessionId}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* `session/delete` of a client that is neither AIR nor a `sessionIndex` client:
|
||||
* the SDK delete of the session's transcript. A session without one succeeds,
|
||||
@@ -422,16 +412,18 @@ export async function deleteSessionIfStored(
|
||||
/**
|
||||
* `session/delete` of an AIR client without `sessionIndex`, which uses delete
|
||||
* to mark a session done: archives it instead, so the transcript survives. A
|
||||
* session without a transcript fails as the SDK delete did.
|
||||
* session without a transcript has nothing to archive and succeeds, as ACP
|
||||
* asks of a delete of a session that never existed (see
|
||||
* {@link deleteSessionIfStored}).
|
||||
*/
|
||||
export async function archiveInsteadOfDelete(
|
||||
sessionId: string,
|
||||
service: SessionIndexService,
|
||||
): Promise<void> {
|
||||
if (!isSessionId(sessionId)) throw sdkDeleteError(sessionId);
|
||||
if (!isSessionId(sessionId)) return;
|
||||
// The SDK delete skips empty transcripts, so they do not count.
|
||||
const found = await service.index.findTranscripts(sessionId);
|
||||
if (found.length === 0) throw sdkDeleteError(sessionId);
|
||||
if (found.length === 0) return;
|
||||
await service.retitle(sessionId, archiveTo(true), { sidecar: "existing" });
|
||||
}
|
||||
|
||||
|
||||
@@ -66,29 +66,50 @@ type ModeConfigSession = SessionMode & {
|
||||
configOptions: SessionConfigOption[];
|
||||
};
|
||||
|
||||
type InitializeSessionModeParams = {
|
||||
query: Pick<Query, "setPermissionMode">;
|
||||
requestedMode: PermissionMode;
|
||||
currentModelInfo?: ModelInfo;
|
||||
currentModelId: string;
|
||||
/** Which optional modes the session's mode catalog offers. */
|
||||
export type ModeAvailability = {
|
||||
/** When false, bypassPermissions is omitted from the mode catalog. */
|
||||
allowBypass: boolean;
|
||||
/** When false (`disableAutoMode: "disable"` in settings), auto is omitted. */
|
||||
allowAuto: boolean;
|
||||
};
|
||||
|
||||
type InitializeSessionModeParams = ModeAvailability & {
|
||||
query: Pick<Query, "setPermissionMode">;
|
||||
requestedMode: PermissionMode;
|
||||
/** The mode is the built-in default: no request, transcript or setting chose it. */
|
||||
builtInDefault?: boolean;
|
||||
currentModelInfo?: ModelInfo;
|
||||
currentModelId: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* The permission mode a new Claude query starts in.
|
||||
*
|
||||
* An explicit mode wins. A resume or a load continues in the mode of the last
|
||||
* user record of the transcript. If that mode is unknown or not available now,
|
||||
* for example bypass, the session starts in `defaultMode` of the settings.
|
||||
* user record of the transcript. If that mode is unknown or absent from the
|
||||
* session's mode catalog, use an available `defaultMode` from settings, or
|
||||
* `default` when that setting is unavailable too.
|
||||
*
|
||||
* With no `defaultMode` set, the session starts in `auto` when the catalog
|
||||
* offers it and in `default` otherwise (`builtInDefault: true`), like an
|
||||
* interactive Claude Code session. Claude Code also starts organizations with
|
||||
* the HIPAA configuration in `default`; the SDK does not report that
|
||||
* configuration, so those sessions start in `auto` here.
|
||||
*/
|
||||
export function resolveInitialPermissionMode(
|
||||
sources: { explicit?: PermissionMode; resumed?: string; defaultMode?: unknown },
|
||||
logger: { error: (...args: unknown[]) => void },
|
||||
allowBypass: boolean,
|
||||
): PermissionMode {
|
||||
availability: ModeAvailability,
|
||||
): { mode: PermissionMode; builtInDefault: boolean } {
|
||||
const { allowBypass } = availability;
|
||||
const available = (mode: PermissionMode) =>
|
||||
buildAvailableModes(availability).some((entry) => entry.id === mode);
|
||||
if (sources.explicit !== undefined) {
|
||||
return resolvePermissionMode(sources.explicit, logger, allowBypass);
|
||||
return {
|
||||
mode: resolvePermissionMode(sources.explicit, logger, allowBypass),
|
||||
builtInDefault: false,
|
||||
};
|
||||
}
|
||||
if (sources.resumed !== undefined) {
|
||||
let rejected = false;
|
||||
@@ -97,13 +118,23 @@ export function resolveInitialPermissionMode(
|
||||
{ error: () => (rejected = true) },
|
||||
allowBypass,
|
||||
);
|
||||
if (!rejected) return mode;
|
||||
if (!rejected && available(mode)) {
|
||||
return { mode, builtInDefault: false };
|
||||
}
|
||||
logger.error(
|
||||
`Ignoring permission mode "${sources.resumed}" of the resumed transcript: ` +
|
||||
`not available in this session.`,
|
||||
);
|
||||
}
|
||||
return resolvePermissionMode(sources.defaultMode, logger, allowBypass);
|
||||
if (sources.defaultMode === undefined) {
|
||||
return { mode: available("auto") ? "auto" : "default", builtInDefault: true };
|
||||
}
|
||||
const configuredMode = resolvePermissionMode(sources.defaultMode, logger, allowBypass);
|
||||
// A rejected transcript mode falls back only to a mode this session can offer.
|
||||
if (sources.resumed !== undefined && !available(configuredMode)) {
|
||||
return { mode: "default", builtInDefault: false };
|
||||
}
|
||||
return { mode: configuredMode, builtInDefault: false };
|
||||
}
|
||||
|
||||
/** Owns session-mode policy and the ACP/SDK synchronization it requires. */
|
||||
@@ -113,22 +144,40 @@ export class SessionModeManager<S extends SessionMode> {
|
||||
async initialize({
|
||||
query,
|
||||
requestedMode,
|
||||
builtInDefault = false,
|
||||
currentModelInfo,
|
||||
currentModelId,
|
||||
allowBypass,
|
||||
allowAuto,
|
||||
}: InitializeSessionModeParams): Promise<{
|
||||
modes: SessionModeState;
|
||||
autoModeFallbackWarningPending: boolean;
|
||||
}> {
|
||||
const availableModes = this.buildAvailableModes(allowBypass);
|
||||
const availableModes = buildAvailableModes(
|
||||
{ allowBypass, allowAuto },
|
||||
this.options.airClient?.() ?? false,
|
||||
);
|
||||
let effectiveMode = requestedMode;
|
||||
let autoModeFallbackWarningPending = false;
|
||||
|
||||
if (
|
||||
const autoUnsupported =
|
||||
effectiveMode === "auto" &&
|
||||
currentModelInfo !== undefined &&
|
||||
currentModelInfo.supportsAutoMode !== true
|
||||
) {
|
||||
currentModelInfo.supportsAutoMode !== true;
|
||||
if (!this.isAvailable(availableModes, effectiveMode)) {
|
||||
this.options.logError(
|
||||
`permissions.defaultMode "${effectiveMode}" is not available in ` +
|
||||
`this session; falling back to "default".`,
|
||||
);
|
||||
effectiveMode = "default";
|
||||
await this.trySyncMode(query, effectiveMode, "Failed to sync clamped permissionMode to SDK:");
|
||||
} else if (autoUnsupported && builtInDefault) {
|
||||
// Like Claude Code: a built-in Auto default the model can't serve starts
|
||||
// in Manual, without a warning. Nobody chose Auto, so don't escalate to
|
||||
// acceptEdits.
|
||||
effectiveMode = "default";
|
||||
await this.trySyncMode(query, effectiveMode, "Failed to sync clamped permissionMode to SDK:");
|
||||
} else if (autoUnsupported) {
|
||||
this.options.logError(
|
||||
`permissions.defaultMode "auto" is not available for model ` +
|
||||
`"${currentModelId}"; falling back to "${AUTO_MODE_FALLBACK}".`,
|
||||
@@ -136,13 +185,6 @@ export class SessionModeManager<S extends SessionMode> {
|
||||
effectiveMode = AUTO_MODE_FALLBACK;
|
||||
autoModeFallbackWarningPending = true;
|
||||
await this.trySyncMode(query, effectiveMode, "Failed to sync clamped permissionMode to SDK:");
|
||||
} else if (!this.isAvailable(availableModes, effectiveMode)) {
|
||||
this.options.logError(
|
||||
`permissions.defaultMode "${effectiveMode}" is not available in ` +
|
||||
`this session; falling back to "default".`,
|
||||
);
|
||||
effectiveMode = "default";
|
||||
await this.trySyncMode(query, effectiveMode, "Failed to sync clamped permissionMode to SDK:");
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -350,50 +392,6 @@ export class SessionModeManager<S extends SessionMode> {
|
||||
}
|
||||
}
|
||||
|
||||
private buildAvailableModes(allowBypass: boolean): SessionModeState["availableModes"] {
|
||||
// Only AIR gets the mode kind.
|
||||
const air = this.options.airClient?.() ?? false;
|
||||
const kind = (value: string) => {
|
||||
const meta = airOnlyMeta(air, AIR_KIND_KEY, value);
|
||||
return meta ? { _meta: meta } : {};
|
||||
};
|
||||
const modes: SessionModeState["availableModes"] = [
|
||||
{
|
||||
id: "default",
|
||||
name: "Manual",
|
||||
description: "Always ask before making changes",
|
||||
...kind("standard"),
|
||||
},
|
||||
{
|
||||
id: "acceptEdits",
|
||||
name: "Accept edits",
|
||||
description: "Automatically accept all file edits",
|
||||
...kind("standard"),
|
||||
},
|
||||
{
|
||||
id: "plan",
|
||||
name: "Plan",
|
||||
description: "Create a plan before making changes",
|
||||
...kind("plan"),
|
||||
},
|
||||
{
|
||||
id: "auto",
|
||||
name: "Auto",
|
||||
description: "Claude handles permission decisions",
|
||||
...kind("auto_review"),
|
||||
},
|
||||
];
|
||||
if (allowBypass) {
|
||||
modes.push({
|
||||
id: "bypassPermissions",
|
||||
name: "Bypass permissions",
|
||||
description: "Accepts all permissions",
|
||||
...kind("full_access"),
|
||||
});
|
||||
}
|
||||
return modes;
|
||||
}
|
||||
|
||||
private async trySyncMode(
|
||||
query: Pick<Query, "setPermissionMode">,
|
||||
mode: PermissionMode,
|
||||
@@ -406,3 +404,51 @@ export class SessionModeManager<S extends SessionMode> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function buildAvailableModes(
|
||||
{ allowBypass, allowAuto }: ModeAvailability,
|
||||
air = false,
|
||||
): SessionModeState["availableModes"] {
|
||||
// Only AIR gets the mode kind.
|
||||
const kind = (value: string) => {
|
||||
const meta = airOnlyMeta(air, AIR_KIND_KEY, value);
|
||||
return meta ? { _meta: meta } : {};
|
||||
};
|
||||
const modes: SessionModeState["availableModes"] = [
|
||||
{
|
||||
id: "default",
|
||||
name: "Manual",
|
||||
description: "Always ask before making changes",
|
||||
...kind("standard"),
|
||||
},
|
||||
{
|
||||
id: "acceptEdits",
|
||||
name: "Accept edits",
|
||||
description: "Automatically accept all file edits",
|
||||
...kind("standard"),
|
||||
},
|
||||
{
|
||||
id: "plan",
|
||||
name: "Plan",
|
||||
description: "Create a plan before making changes",
|
||||
...kind("plan"),
|
||||
},
|
||||
];
|
||||
if (allowAuto) {
|
||||
modes.push({
|
||||
id: "auto",
|
||||
name: "Auto",
|
||||
description: "Claude handles permission decisions",
|
||||
...kind("auto_review"),
|
||||
});
|
||||
}
|
||||
if (allowBypass) {
|
||||
modes.push({
|
||||
id: "bypassPermissions",
|
||||
name: "Bypass permissions",
|
||||
description: "Accepts all permissions",
|
||||
...kind("full_access"),
|
||||
});
|
||||
}
|
||||
return modes;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export type UltracodeSettingsReport = {
|
||||
};
|
||||
|
||||
// `Query.getSettings()` exists at runtime (sdk.mjs) but is missing from the
|
||||
// SDK's type declarations as of 0.3.312.
|
||||
// SDK's type declarations as of 0.3.318.
|
||||
type GetSettingsQuery = Query & {
|
||||
getSettings?: () => Promise<{
|
||||
applied?: { ultracodeAvailable?: unknown; ultracodeRequested?: unknown };
|
||||
|
||||
42
src/startup-failure.ts
Normal file
42
src/startup-failure.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { RequestError } from "@agentclientprotocol/sdk/unstable";
|
||||
import type { SDKStartupFailureReason } from "@anthropic-ai/claude-agent-sdk";
|
||||
|
||||
/** Makes the CLI write an `error_during_execution` result with a
|
||||
* `startup_failure_reason` before it exits on a known startup failure. Without
|
||||
* it, some failures (e.g. `proxy_invalid`) end with stderr and an exit code
|
||||
* alone. The SDK then rejects `initializationResult()` with an error that
|
||||
* carries the reason as `startupFailureReason`. */
|
||||
export const STARTUP_FAILURE_RESULTS_ENV = { CLAUDE_CODE_STARTUP_FAILURE_RESULTS: "1" };
|
||||
|
||||
/** The SDK's prefix on the message of an error built from an error result. */
|
||||
const ERROR_RESULT_PREFIX = "Claude Code returned an error result: ";
|
||||
|
||||
/** Reasons that signing in again, or with another account, can fix. */
|
||||
const AUTH_REQUIRED_REASONS: ReadonlySet<SDKStartupFailureReason> = new Set([
|
||||
"gateway_signin_required",
|
||||
"org_pin_mismatch",
|
||||
"org_config_refused",
|
||||
]);
|
||||
|
||||
/** The ACP error for a CLI that refused to start, or `undefined` when `error`
|
||||
* carries no `startupFailureReason` (older CLIs, failures without a known
|
||||
* cause). The message is the CLI's own, which says what to fix, e.g.
|
||||
* `Invalid proxy URL in HTTPS_PROXY: … Fix or unset HTTPS_PROXY and restart
|
||||
* Claude Code.`; `data.startupFailureReason` carries the reason. */
|
||||
export function startupFailureError(error: unknown): RequestError | undefined {
|
||||
if (!(error instanceof Error)) return undefined;
|
||||
const reason = (error as { startupFailureReason?: unknown }).startupFailureReason;
|
||||
if (typeof reason !== "string" || reason === "") return undefined;
|
||||
|
||||
const message = error.message.startsWith(ERROR_RESULT_PREFIX)
|
||||
? error.message.slice(ERROR_RESULT_PREFIX.length)
|
||||
: error.message;
|
||||
const data = { startupFailureReason: reason };
|
||||
if (AUTH_REQUIRED_REASONS.has(reason as SDKStartupFailureReason)) {
|
||||
return RequestError.authRequired(data, message);
|
||||
}
|
||||
if (reason === "cwd_unavailable") {
|
||||
return RequestError.invalidParams(data, message);
|
||||
}
|
||||
return RequestError.internalError(data, message);
|
||||
}
|
||||
@@ -24,6 +24,11 @@ export interface SubagentRecord {
|
||||
background: boolean;
|
||||
/** Whether the user stopped it. */
|
||||
stoppedByUser: boolean;
|
||||
/**
|
||||
* Its working directory, when Claude Code placed it outside its parent's:
|
||||
* in a worktree of its own or of an ancestor, or in a `cwd` of its own.
|
||||
*/
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
/** Where the subagent transcripts of a session are. */
|
||||
@@ -43,7 +48,9 @@ export interface SubagentHistory {
|
||||
* Claude keeps the history of a subagent in its own transcript,
|
||||
* `<session>/subagents/agent-<id>.jsonl`, next to the session transcript.
|
||||
* The `agent-<id>.meta.json` file beside it names the launching tool use.
|
||||
* The ids are empty for a session without a local transcript.
|
||||
* For a child that Claude Code placed elsewhere, it has `worktreePath`,
|
||||
* `inheritedWorktreePath` or `cwd`; then the child's working directory is the
|
||||
* `cwd` of its transcript's records. The ids are empty for a session without a local transcript.
|
||||
*/
|
||||
export async function subagentHistory(sessionId: string): Promise<SubagentHistory> {
|
||||
const agents = new Map<string, SubagentRecord>();
|
||||
@@ -67,6 +74,12 @@ export async function subagentHistory(sessionId: string): Promise<SubagentHistor
|
||||
> | null;
|
||||
if (typeof meta?.toolUseId !== "string") return;
|
||||
const text = (value: unknown) => (typeof value === "string" ? value : undefined);
|
||||
const placement = [meta.cwd, meta.worktreePath, meta.inheritedWorktreePath]
|
||||
.map(text)
|
||||
.find((value) => value && path.isAbsolute(value));
|
||||
const cwd = placement
|
||||
? ((await recordedCwd(path.join(directory, `agent-${match[1]!}.jsonl`))) ?? placement)
|
||||
: undefined;
|
||||
agents.set(meta.toolUseId, {
|
||||
agentId: match[1]!,
|
||||
name: text(meta.name),
|
||||
@@ -74,6 +87,7 @@ export async function subagentHistory(sessionId: string): Promise<SubagentHistor
|
||||
description: text(meta.description),
|
||||
background: meta.requestShape === "background",
|
||||
stoppedByUser: meta.stoppedByUser === true,
|
||||
...(cwd ? { cwd } : {}),
|
||||
});
|
||||
} catch {
|
||||
// A damaged meta file leaves its subagent without history.
|
||||
@@ -87,6 +101,31 @@ export async function subagentHistory(sessionId: string): Promise<SubagentHistor
|
||||
return dir ? { agents, dir } : { agents };
|
||||
}
|
||||
|
||||
/**
|
||||
* The `cwd` of the first record of the transcript `file` that has one, or
|
||||
* undefined when the file cannot be read. Claude Code writes the working
|
||||
* directory of the session or subagent on each record.
|
||||
*/
|
||||
async function recordedCwd(file: string): Promise<string | undefined> {
|
||||
const stream = createReadStream(file, { encoding: "utf8" });
|
||||
try {
|
||||
for await (const line of readline.createInterface({ input: stream, crlfDelay: Infinity })) {
|
||||
if (!line.includes('"cwd"')) continue;
|
||||
try {
|
||||
const cwd = (JSON.parse(line) as { cwd?: unknown } | null)?.cwd;
|
||||
if (typeof cwd === "string" && path.isAbsolute(cwd)) return cwd;
|
||||
} catch {
|
||||
// A damaged record; a later one can have the `cwd`.
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// An unreadable transcript; the caller falls back to the metadata's path.
|
||||
} finally {
|
||||
stream.destroy();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** The folder of the subagent transcripts, next to the session transcript `transcript`. */
|
||||
function subagentsDirectory(transcript: string, sessionId: string): string {
|
||||
return path.join(path.dirname(transcript), sessionId, "subagents");
|
||||
@@ -162,6 +201,7 @@ export async function subagentLineage(
|
||||
agentId: current,
|
||||
launchId: launch.launchId,
|
||||
...(launcher !== null ? { parentAgentId: launcher } : {}),
|
||||
...(launch.record.cwd ? { cwd: launch.record.cwd } : {}),
|
||||
...(launch.record.name ? { name: launch.record.name } : {}),
|
||||
...(launch.record.agentType ? { agentType: launch.record.agentType } : {}),
|
||||
...(launch.record.description ? { description: launch.record.description } : {}),
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
*/
|
||||
import type { SessionConfigOption } from "@agentclientprotocol/sdk/unstable";
|
||||
import type { SessionMessage } from "@anthropic-ai/claude-agent-sdk";
|
||||
import { statSync } from "node:fs";
|
||||
import type { AcpSessionNotification, SubagentState } from "./acp-subagents.js";
|
||||
import {
|
||||
childModelOption,
|
||||
@@ -47,6 +48,7 @@ import {
|
||||
responseModelEntry,
|
||||
rfdEndState,
|
||||
rfdLabels,
|
||||
sameDirectory,
|
||||
type SubagentModels,
|
||||
type WorkState,
|
||||
} from "./native-subagents.js";
|
||||
@@ -71,6 +73,8 @@ export type ReplayChild = {
|
||||
/** The state of the child's last persisted task notification. */
|
||||
notified?: SubagentState;
|
||||
announced: boolean;
|
||||
/** The `cwd` that the replay reported for it; undefined while it inherits its parent's. */
|
||||
cwd?: string;
|
||||
promptSent: boolean;
|
||||
/** Whether it handed a report to its parent with a SubagentHandback call. */
|
||||
handedBack?: boolean;
|
||||
@@ -118,6 +122,8 @@ export class RfdSubagentReplay {
|
||||
* {@link currentStates}, after the load response.
|
||||
*/
|
||||
private readonly mapsDuringReplay = true,
|
||||
/** The working directory of the root session, which a child inherits unless it reports its own. */
|
||||
private readonly rootCwd?: string,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -166,8 +172,9 @@ export class RfdSubagentReplay {
|
||||
|
||||
/**
|
||||
* Announces `child` on its parent, as live: running, with the parent's
|
||||
* labels. Then it sends `firstModel`, the model of the child's first
|
||||
* response, when the transcript has one.
|
||||
* labels, and with its recorded `cwd` when that differs from its parent's.
|
||||
* Then it sends `firstModel`, the model of the child's first response, when
|
||||
* the transcript has one.
|
||||
*/
|
||||
async announce(child: ReplayChild, firstModel?: string): Promise<void> {
|
||||
if (child.announced) return;
|
||||
@@ -176,6 +183,12 @@ export class RfdSubagentReplay {
|
||||
child.record.agentType ?? child.input.subagent_type,
|
||||
child.record.description ?? child.input.description,
|
||||
);
|
||||
const inherited = this.effectiveCwd(child.parentSessionId);
|
||||
const cwd =
|
||||
child.record.cwd &&
|
||||
(inherited === undefined || !(await sameDirectory(child.record.cwd, inherited)))
|
||||
? child.record.cwd
|
||||
: undefined;
|
||||
await this.publish({
|
||||
sessionId: child.parentSessionId,
|
||||
update: {
|
||||
@@ -183,13 +196,30 @@ export class RfdSubagentReplay {
|
||||
sessionId: child.sessionId,
|
||||
...(labels.title ? { title: labels.title } : {}),
|
||||
...(labels.description ? { description: labels.description } : {}),
|
||||
...(cwd ? { cwd } : {}),
|
||||
state: { state: "running" },
|
||||
},
|
||||
});
|
||||
child.cwd = cwd;
|
||||
child.announced = true;
|
||||
await this.responseModel(child, firstModel);
|
||||
}
|
||||
|
||||
/**
|
||||
* The working directory of the session `sessionId` as the client holds it:
|
||||
* a child's reported `cwd`, else its parent's, up to the root's.
|
||||
*/
|
||||
private effectiveCwd(sessionId: string): string | undefined {
|
||||
const seen = new Set<string>();
|
||||
let child = this.byAgentId.get(sessionId);
|
||||
while (child && !seen.has(child.sessionId)) {
|
||||
if (child.cwd) return child.cwd;
|
||||
seen.add(child.sessionId);
|
||||
child = this.byAgentId.get(child.parentSessionId);
|
||||
}
|
||||
return this.rootCwd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes the model of a replayed response of the child `owner`. A child
|
||||
* whose model changes gets its `model` option again.
|
||||
@@ -370,6 +400,10 @@ export class RfdSubagentReplay {
|
||||
* when a live session is loaded again. Such a child reports that state and
|
||||
* can be cancelled, as live. Any other child cannot be running, because the
|
||||
* process that ran it is gone, so its replayed end is its current state.
|
||||
*
|
||||
* A replayed `cwd` whose directory is gone, such as a worktree that Claude
|
||||
* Code removed when the child finished, is cleared with `cwd: null`, as the
|
||||
* RFD requires after a reconnection.
|
||||
*/
|
||||
currentStates(
|
||||
live: (sessionId: string) => WorkState["state"] | undefined,
|
||||
@@ -395,6 +429,7 @@ export class RfdSubagentReplay {
|
||||
sessionUpdate: "subagent_update",
|
||||
sessionId: child.sessionId,
|
||||
...(liveState !== undefined ? { capabilities: { cancel: {} } } : {}),
|
||||
...(child.cwd && !isDirectory(child.cwd) ? { cwd: null } : {}),
|
||||
state,
|
||||
},
|
||||
},
|
||||
@@ -574,6 +609,15 @@ function textOf(content: unknown): string {
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
/** Whether `dir` is an existing directory. */
|
||||
function isDirectory(dir: string): boolean {
|
||||
try {
|
||||
return statSync(dir).isDirectory();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** A message that a SendMessage call delivered to the child. */
|
||||
function isDelivery(message: SessionMessage): boolean {
|
||||
return (message as { origin?: { kind?: unknown } | null }).origin?.kind === "coordinator";
|
||||
|
||||
@@ -42,6 +42,7 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
value: "claude-sonnet-4-6",
|
||||
displayName: "Claude Sonnet 4.5",
|
||||
description: "Default",
|
||||
supportsAutoMode: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
@@ -284,7 +285,7 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
|
||||
it("drops escalating defaultMode when it comes from project-tier settings", async () => {
|
||||
// bypassPermissions in .claude/settings.json (a repo-committed tier) is
|
||||
// filtered by the SDK's trust policy and clamps to 'default'.
|
||||
// filtered by the SDK's trust policy, so the built-in default applies.
|
||||
const projectDir = path.join(tempDir, "project");
|
||||
await fs.promises.mkdir(path.join(projectDir, ".claude"), { recursive: true });
|
||||
await fs.promises.writeFile(
|
||||
@@ -303,8 +304,8 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
_meta: { disableBuiltInTools: true },
|
||||
});
|
||||
|
||||
expect(getCapturedOptions().permissionMode).toBe("default");
|
||||
expect(response.modes.currentModeId).toBe("default");
|
||||
expect(getCapturedOptions().permissionMode).toBe("auto");
|
||||
expect(response.modes.currentModeId).toBe("auto");
|
||||
});
|
||||
|
||||
it("honors the host opt-out from bypassPermissions", async () => {
|
||||
@@ -380,7 +381,7 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
},
|
||||
);
|
||||
|
||||
it("defaults to 'default' when no permissions.defaultMode is set", async () => {
|
||||
it("defaults to 'auto' when no permissions.defaultMode is set", async () => {
|
||||
const projectDir = path.join(tempDir, "project");
|
||||
await fs.promises.mkdir(projectDir, { recursive: true });
|
||||
|
||||
@@ -395,8 +396,37 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
_meta: { disableBuiltInTools: true },
|
||||
});
|
||||
|
||||
expect(getCapturedOptions().permissionMode).toBe("default");
|
||||
expect(getCapturedOptions().permissionMode).toBe("auto");
|
||||
expect(response.modes.currentModeId).toBe("auto");
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ name: "top-level disableAutoMode", settings: { disableAutoMode: "disable" } },
|
||||
{
|
||||
name: "permissions.disableAutoMode with defaultMode 'auto'",
|
||||
settings: { permissions: { disableAutoMode: "disable", defaultMode: "auto" } },
|
||||
},
|
||||
])("starts in 'default' without Auto in the catalog for $name", async ({ settings }) => {
|
||||
await fs.promises.writeFile(path.join(tempDir, "settings.json"), JSON.stringify(settings));
|
||||
const projectDir = path.join(tempDir, "project");
|
||||
await fs.promises.mkdir(projectDir, { recursive: true });
|
||||
|
||||
mockQuery();
|
||||
|
||||
const { ClaudeAcpAgent } = await import("../acp-agent.js");
|
||||
const agent: ClaudeAcpAgentType = new ClaudeAcpAgent(createMockClient());
|
||||
(agent as any).logger = { log: () => {}, error: () => {} };
|
||||
|
||||
const response = await (agent as any).createSession({
|
||||
cwd: projectDir,
|
||||
mcpServers: [],
|
||||
_meta: { disableBuiltInTools: true },
|
||||
});
|
||||
|
||||
expect(response.modes.currentModeId).toBe("default");
|
||||
expect(response.modes.availableModes.map((mode: { id: string }) => mode.id)).not.toContain(
|
||||
"auto",
|
||||
);
|
||||
});
|
||||
|
||||
describe("on resume", () => {
|
||||
@@ -464,6 +494,16 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
expect(response.modes.currentModeId).toBe("plan");
|
||||
});
|
||||
|
||||
it("uses the available configured mode when the restored mode is not in the catalog", async () => {
|
||||
const { permissionMode, response } = await resume([user("dontAsk")]);
|
||||
|
||||
expect(permissionMode).toBe("plan");
|
||||
expect(response.modes.currentModeId).toBe("plan");
|
||||
expect(response.configOptions.find((option: any) => option.id === "mode").currentValue).toBe(
|
||||
"plan",
|
||||
);
|
||||
});
|
||||
|
||||
it("uses permissions.defaultMode when bypass is not available now", async () => {
|
||||
const { permissionMode, response } = await resume([user("bypassPermissions")], {
|
||||
claudeCode: { options: { allowDangerouslySkipPermissions: false } },
|
||||
@@ -525,17 +565,18 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
return createSession(params, options);
|
||||
};
|
||||
|
||||
await (agent as any).recreateSignedOutQuery(sessionId, (agent as any).sessions[sessionId]);
|
||||
const husk = (agent as any).sessions[sessionId];
|
||||
await (agent as any).recreateSignedOutQuery(sessionId, husk);
|
||||
|
||||
expect(creations).toEqual([
|
||||
{ resume: sessionId, permissionMode: "default" },
|
||||
{ reuseSessionId: sessionId, permissionMode: "default" },
|
||||
{ resume: sessionId, permissionMode: "default", replacingSession: husk },
|
||||
{ reuseSessionId: sessionId, permissionMode: "default", replacingSession: husk },
|
||||
]);
|
||||
expect(getCapturedOptions().permissionMode).toBe("default");
|
||||
});
|
||||
});
|
||||
|
||||
it("falls back to 'default' when permissions.defaultMode is invalid", async () => {
|
||||
it("falls back to the built-in default when permissions.defaultMode is invalid", async () => {
|
||||
await fs.promises.writeFile(
|
||||
path.join(tempDir, "settings.json"),
|
||||
JSON.stringify({
|
||||
@@ -559,9 +600,9 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
_meta: { disableBuiltInTools: true },
|
||||
});
|
||||
|
||||
// Bad mode is ignored at the usage site; session creation must not throw.
|
||||
expect(getCapturedOptions().permissionMode).toBe("default");
|
||||
expect(response.modes.currentModeId).toBe("default");
|
||||
// Settings resolution drops the bad mode; session creation must not throw.
|
||||
expect(getCapturedOptions().permissionMode).toBe("auto");
|
||||
expect(response.modes.currentModeId).toBe("auto");
|
||||
});
|
||||
|
||||
it("ignores model from settings when it is not a string", async () => {
|
||||
@@ -703,6 +744,30 @@ describe("ClaudeAcpAgent settings", () => {
|
||||
expect(modeIds).not.toContain("dontAsk");
|
||||
});
|
||||
|
||||
it("starts the built-in Auto default in Manual on an unsupported model", async () => {
|
||||
const projectDir = path.join(tempDir, "project");
|
||||
await fs.promises.mkdir(projectDir, { recursive: true });
|
||||
|
||||
const { setPermissionModeSpy } = mockQueryWithModels([
|
||||
{ value: "claude-haiku-4-5", displayName: "Claude Haiku", description: "Fast" },
|
||||
]);
|
||||
|
||||
const { ClaudeAcpAgent } = await import("../acp-agent.js");
|
||||
const agent: ClaudeAcpAgentType = new ClaudeAcpAgent(createMockClient());
|
||||
|
||||
const response = await (agent as any).createSession({
|
||||
cwd: projectDir,
|
||||
mcpServers: [],
|
||||
_meta: { disableBuiltInTools: true },
|
||||
});
|
||||
|
||||
expect(setPermissionModeSpy).toHaveBeenCalledWith("default");
|
||||
expect(response.modes.currentModeId).toBe("default");
|
||||
expect((agent as any).sessions[response.sessionId].autoModeFallbackWarningPending).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back permissions.defaultMode='auto' to Accept edits on an unsupported model", async () => {
|
||||
await fs.promises.writeFile(
|
||||
path.join(tempDir, "settings.json"),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, it, expect, beforeAll, beforeEach, afterAll, afterEach, vi } from "vitest";
|
||||
import { spawn, spawnSync } from "child_process";
|
||||
import {
|
||||
type AnyMessage,
|
||||
AvailableCommand,
|
||||
ClientCapabilities,
|
||||
client as acpClient,
|
||||
@@ -41,7 +42,6 @@ import {
|
||||
isSyntheticLoginMessage,
|
||||
stripLocalCommandMetadata,
|
||||
ClaudeAcpAgent,
|
||||
claudeCliPath,
|
||||
computeSessionFingerprint,
|
||||
streamEventToAcpNotifications,
|
||||
messageIdForGrouping,
|
||||
@@ -55,9 +55,11 @@ import {
|
||||
type StreamedToolInputCache,
|
||||
} from "../acp-agent.js";
|
||||
import { SessionTitles } from "../session-titles.js";
|
||||
import { SessionBackgroundWork } from "../background-work.js";
|
||||
import { formatUsageResponse, isUsageCommandText, parseUsageResponse } from "../usage-markdown.js";
|
||||
import { Pushable } from "../utils.js";
|
||||
import { initializeClient, makeMockQuery } from "./helpers.js";
|
||||
import { heldRequest, initializeClient, makeMockQuery } from "./helpers.js";
|
||||
import { acpProtocolRouter } from "../serve.js";
|
||||
import * as agentSdk from "@anthropic-ai/claude-agent-sdk";
|
||||
import {
|
||||
deleteSession,
|
||||
@@ -3548,11 +3550,20 @@ describe("session/list", () => {
|
||||
expect(second.sessions.map((session) => session.sessionId)).toEqual(["session-1000"]);
|
||||
expect(second.nextCursor).toBeUndefined();
|
||||
expect(vi.mocked(listSessions).mock.calls).toEqual([
|
||||
[{ dir: "/workspace", limit: 1001, offset: 0 }],
|
||||
[{ dir: "/workspace", limit: 1001, offset: 1000 }],
|
||||
[{ dir: "/workspace", includeWorktrees: false, limit: 1001, offset: 0 }],
|
||||
[{ dir: "/workspace", includeWorktrees: false, limit: 1001, offset: 1000 }],
|
||||
]);
|
||||
});
|
||||
|
||||
it("rejects a relative cwd", async () => {
|
||||
vi.mocked(listSessions).mockClear();
|
||||
await expect(agent().listSessions({ cwd: "workspace" })).rejects.toMatchObject({
|
||||
code: -32602,
|
||||
data: { cwd: "workspace" },
|
||||
});
|
||||
expect(listSessions).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("rejects a cursor that it did not issue", async () => {
|
||||
await expect(agent().listSessions({ cursor: "page-2" })).rejects.toThrow(
|
||||
"Unknown session/list cursor",
|
||||
@@ -4006,7 +4017,8 @@ describe("subagent transcript replay", () => {
|
||||
return [
|
||||
...response,
|
||||
`${on} subagent_update ${u.sessionId} ${JSON.stringify(u.state)}` +
|
||||
(u.capabilities ? ` capabilities=${JSON.stringify(u.capabilities)}` : ""),
|
||||
(u.capabilities ? ` capabilities=${JSON.stringify(u.capabilities)}` : "") +
|
||||
("cwd" in u ? ` cwd=${JSON.stringify(u.cwd)}` : ""),
|
||||
];
|
||||
case "session_message": {
|
||||
const references = [
|
||||
@@ -4046,6 +4058,51 @@ describe("subagent transcript replay", () => {
|
||||
}
|
||||
}
|
||||
|
||||
it("announces a worktree child with its recorded cwd, and clears it when the worktree is gone", async () => {
|
||||
const worktree = "/tmp/proj/.claude/worktrees/agent-wt1";
|
||||
const trace = await replayRfd(
|
||||
[
|
||||
user("u1", "Go"),
|
||||
assistant("a1", [
|
||||
toolUse("toolu_wt", "Agent", { description: "Isolated", prompt: "Work apart" }),
|
||||
toolUse("toolu_plain", "Agent", { description: "Shared", prompt: "Work here" }),
|
||||
]),
|
||||
user("u2", [toolResult("toolu_wt", "Done."), toolResult("toolu_plain", "Done.")]),
|
||||
],
|
||||
{
|
||||
wt1: {
|
||||
meta: {
|
||||
agentType: "general-purpose",
|
||||
toolUseId: "toolu_wt",
|
||||
worktreePath: worktree,
|
||||
spawnedWithWorktree: true,
|
||||
},
|
||||
records: [
|
||||
user("w1", "Work apart", { cwd: worktree }),
|
||||
assistant("w2", [{ type: "text", text: "Done." }], { cwd: worktree }),
|
||||
],
|
||||
},
|
||||
plain1: {
|
||||
meta: { agentType: "general-purpose", toolUseId: "toolu_plain" },
|
||||
records: [user("p1", "Work here"), assistant("p2", [{ type: "text", text: "Done." }])],
|
||||
},
|
||||
},
|
||||
undefined,
|
||||
{ live: () => undefined },
|
||||
{ load: true },
|
||||
);
|
||||
|
||||
expect(trace.filter((line) => line.includes(" subagent_update "))).toEqual([
|
||||
`root subagent_update wt1 {"state":"running"} cwd="${worktree}"`,
|
||||
'root subagent_update plain1 {"state":"running"}',
|
||||
'root subagent_update plain1 {"state":"idle","stopReason":"end_turn"}',
|
||||
'root subagent_update wt1 {"state":"idle","stopReason":"end_turn"}',
|
||||
// After the response: the worktree no longer exists.
|
||||
'root subagent_update wt1 {"state":"idle","stopReason":"end_turn"} cwd=null',
|
||||
'root subagent_update plain1 {"state":"idle","stopReason":"end_turn"}',
|
||||
]);
|
||||
});
|
||||
|
||||
it("replays a fork child without the launching message and boilerplate it inherited", async () => {
|
||||
// A `subagent_type: "fork"` transcript starts with a copy of the
|
||||
// launching message (same API message id) and a directive message with
|
||||
@@ -4716,6 +4773,58 @@ describe("escape markdown", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("request validation", () => {
|
||||
function agent() {
|
||||
return new ClaudeAcpAgent({ sessionUpdate: async () => {} } as unknown as AcpClient, {
|
||||
log: () => {},
|
||||
error: () => {},
|
||||
});
|
||||
}
|
||||
|
||||
it("rejects a session/new with a relative additional directory", async () => {
|
||||
await expect(
|
||||
agent().newSession({ cwd: os.tmpdir(), mcpServers: [], additionalDirectories: ["extra"] }),
|
||||
).rejects.toMatchObject({ code: -32602, data: { additionalDirectories: ["extra"] } });
|
||||
});
|
||||
|
||||
it("rejects authenticate with an unknown method id", async () => {
|
||||
await expect(agent().authenticate({ methodId: "unknown-method" })).rejects.toMatchObject({
|
||||
code: -32602,
|
||||
data: { methodId: "unknown-method" },
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects a v1 prompt with audio before it looks up the session", async () => {
|
||||
// An unknown session would fail with -32002 if the check ran later.
|
||||
await expect(
|
||||
agent().prompt({
|
||||
sessionId: "unknown-session",
|
||||
prompt: [
|
||||
{ type: "text", text: "listen" },
|
||||
{ type: "audio", data: "AAAA", mimeType: "audio/wav" },
|
||||
],
|
||||
}),
|
||||
).rejects.toMatchObject({ code: -32602, data: { type: "audio" } });
|
||||
});
|
||||
|
||||
it("drops slash commands whose name has whitespace, and repeats of a name", async () => {
|
||||
const a = agent();
|
||||
const supportedCommands = async () => [
|
||||
{ name: "review", description: "first" },
|
||||
{ name: "review", description: "second" },
|
||||
{ name: "my command", description: "spaced" },
|
||||
{ name: "compact", description: "Compact the conversation" },
|
||||
];
|
||||
a.sessions["test-session"] = mockSessionState({ query: { supportedCommands } }, a) as any;
|
||||
const commands = await a.availableCommands("test-session");
|
||||
expect(commands.map((command) => [command.name, command.description])).toEqual([
|
||||
["review", "first"],
|
||||
["compact", "Compact the conversation"],
|
||||
["mcp", expect.any(String)],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("prompt conversion", () => {
|
||||
it("should not change built-in slash commands", () => {
|
||||
const message = promptToClaude({
|
||||
@@ -4753,6 +4862,22 @@ describe("prompt conversion", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("rewrites an MCP slash command with multi-line input, in the first text block only", () => {
|
||||
const message = promptToClaude({
|
||||
sessionId: "test",
|
||||
prompt: [
|
||||
{ type: "resource_link", uri: "file:///work/a.ts", name: "a.ts" },
|
||||
{ type: "text", text: "/mcp:server:name first line\nsecond line" },
|
||||
{ type: "text", text: "/mcp:server:other args" },
|
||||
],
|
||||
});
|
||||
expect(message.message.content).toEqual([
|
||||
{ type: "text", text: "[@a.ts](file:///work/a.ts)" },
|
||||
{ type: "text", text: "/server:name (MCP) first line\nsecond line" },
|
||||
{ type: "text", text: "/mcp:server:other args" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("sends image, PDF and text blob resources to Claude, and skips other blobs", () => {
|
||||
const blob = (uri: string, mimeType: string, data: string) => ({
|
||||
type: "resource" as const,
|
||||
@@ -4810,11 +4935,6 @@ describe("prompt conversion", () => {
|
||||
});
|
||||
|
||||
describe.skipIf(!process.env.RUN_INTEGRATION_TESTS)("SDK behavior", () => {
|
||||
it("finds vendored cli path", async () => {
|
||||
const path = await claudeCliPath();
|
||||
expect(path).toMatch(/@anthropic-ai\/claude-agent-sdk-[^/]+\/claude(\.exe)?$/);
|
||||
});
|
||||
|
||||
it("query has a 'default' model", async () => {
|
||||
const q = query({ prompt: "hi" });
|
||||
const models = await q.supportedModels();
|
||||
@@ -5076,6 +5196,7 @@ describe("permission request cancellation", () => {
|
||||
toolUseCache: {},
|
||||
emittedToolCalls: new Set(),
|
||||
liveBackgroundTasks: new Map(),
|
||||
background: new SessionBackgroundWork(sessionId, false),
|
||||
emittedAssistantText: false,
|
||||
owedTrailingIdles: 0,
|
||||
messageIdToUuid: new Map(),
|
||||
@@ -5114,10 +5235,11 @@ describe("permission request cancellation", () => {
|
||||
// Let canUseTool reach the awaited requestPermission before cancelling.
|
||||
await Promise.resolve();
|
||||
|
||||
// The tool-call signal is threaded through as the cancellation signal.
|
||||
expect(receivedSignal).toBe(controller.signal);
|
||||
// The cancellation signal follows the tool-call signal.
|
||||
expect(receivedSignal?.aborted).toBe(false);
|
||||
|
||||
controller.abort();
|
||||
expect(receivedSignal?.aborted).toBe(true);
|
||||
|
||||
await expect(pending).rejects.toThrow("Tool use aborted");
|
||||
});
|
||||
@@ -5125,7 +5247,7 @@ describe("permission request cancellation", () => {
|
||||
it("does not wait for a permission client that ignores cancellation", async () => {
|
||||
const mockClient = {
|
||||
sessionUpdate: async () => {},
|
||||
requestPermission: () => new Promise<RequestPermissionResponse>(() => {}),
|
||||
requestPermission: heldRequest<RequestPermissionResponse>,
|
||||
} as unknown as AcpClient;
|
||||
const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} });
|
||||
const session = injectSession(agent, "session-1");
|
||||
@@ -5144,14 +5266,14 @@ describe("permission request cancellation", () => {
|
||||
});
|
||||
|
||||
describe("a cancelled outcome", () => {
|
||||
function setup() {
|
||||
function setup(options: { v2?: boolean } = {}) {
|
||||
const mockClient = {
|
||||
sessionUpdate: async () => {},
|
||||
requestPermission: async (): Promise<RequestPermissionResponse> => ({
|
||||
outcome: { outcome: "cancelled" },
|
||||
}),
|
||||
} as unknown as AcpClient;
|
||||
const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} });
|
||||
const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} }, options);
|
||||
const session = injectSession(agent, "session-1");
|
||||
session.emittedToolCalls.add("tool-1");
|
||||
const ask = (agentID?: string) =>
|
||||
@@ -5173,6 +5295,29 @@ describe("permission request cancellation", () => {
|
||||
await expect(ask("agent-fg")).rejects.toThrow("Tool use aborted");
|
||||
});
|
||||
|
||||
it("denies the tool use of foreground work on v2 without a session/cancel", async () => {
|
||||
// On v2 the client also answers `cancelled` when the user dismissed the
|
||||
// prompt or its policy declined it. The turn goes on without the tool.
|
||||
const { session, ask } = setup({ v2: true });
|
||||
session.liveBackgroundTasks.set("agent-fg", { isSubagent: true });
|
||||
|
||||
for (const agentID of [undefined, "agent-fg"]) {
|
||||
await expect(ask(agentID)).resolves.toEqual({
|
||||
behavior: "deny",
|
||||
message: "User refused permission to run tool",
|
||||
toolUseID: "tool-1",
|
||||
decisionClassification: "user_reject",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("aborts the tool use of foreground work on v2 during a session/cancel", async () => {
|
||||
const { session, ask } = setup({ v2: true });
|
||||
session.cancelled = true;
|
||||
|
||||
await expect(ask()).rejects.toThrow("Tool use aborted");
|
||||
});
|
||||
|
||||
it("denies the tool use of a background subagent", async () => {
|
||||
const { session, ask } = setup();
|
||||
session.liveBackgroundTasks.set("agent-bg", { isSubagent: true, backgrounded: true });
|
||||
@@ -5252,7 +5397,7 @@ describe("permission request cancellation", () => {
|
||||
"does not wait for $name when its client ignores cancellation",
|
||||
async ({ start, aborted }) => {
|
||||
// The client holds the elicitation and never answers $/cancel_request.
|
||||
const createElicitation = vi.fn(() => new Promise<CreateElicitationResponse>(() => {}));
|
||||
const createElicitation = vi.fn(heldRequest<CreateElicitationResponse>);
|
||||
const mockClient = {
|
||||
sessionUpdate: async () => {},
|
||||
createElicitation,
|
||||
@@ -5265,39 +5410,129 @@ describe("permission request cancellation", () => {
|
||||
const controller = new AbortController();
|
||||
const pending = start(agent, controller.signal);
|
||||
await vi.waitFor(() => expect(createElicitation).toHaveBeenCalledOnce());
|
||||
// The client was asked to cancel the request, and ignores that.
|
||||
expect(createElicitation.mock.calls[0]).toEqual([expect.anything(), controller.signal]);
|
||||
const [, requestSignal] = createElicitation.mock.calls[0] as unknown as [
|
||||
unknown,
|
||||
AbortSignal,
|
||||
];
|
||||
controller.abort();
|
||||
// The client was asked to cancel the request, and ignores that.
|
||||
expect(requestSignal.aborted).toBe(true);
|
||||
|
||||
await aborted(pending);
|
||||
expect(session.openUserInputs?.size ?? 0).toBe(0);
|
||||
},
|
||||
);
|
||||
|
||||
it("observes a client rejection when the signal aborts during request creation", async () => {
|
||||
const controller = new AbortController();
|
||||
const clientOperation = Promise.reject(new Error("Request cancelled"));
|
||||
const then = vi.spyOn(clientOperation, "then");
|
||||
it.each(elicitations)(
|
||||
"cancels $name before session/close responds",
|
||||
async ({ start, aborted }) => {
|
||||
const events: string[] = [];
|
||||
const createElicitation = vi.fn((params: unknown, signal: AbortSignal) => {
|
||||
signal.addEventListener("abort", () => events.push("cancel_request"), { once: true });
|
||||
return heldRequest<CreateElicitationResponse>(params, signal);
|
||||
});
|
||||
const mockClient = {
|
||||
sessionUpdate: async () => {},
|
||||
createElicitation,
|
||||
} as unknown as AcpClient;
|
||||
const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} });
|
||||
await initializeClient(agent, { elicitation: { form: {}, url: {} } });
|
||||
const session = injectSession(agent, "session-1");
|
||||
session.emittedToolCalls.add("tool-1");
|
||||
|
||||
// Claude Code's own signal for the callback never aborts here.
|
||||
const pending = start(agent, new AbortController().signal);
|
||||
await vi.waitFor(() => expect(createElicitation).toHaveBeenCalledOnce());
|
||||
await agent.closeSession({ sessionId: "session-1" });
|
||||
events.push("closed");
|
||||
|
||||
expect(events).toEqual(["cancel_request", "closed"]);
|
||||
await aborted(pending);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "a permission request",
|
||||
start: (agent: ClaudeAcpAgent, signal: AbortSignal) =>
|
||||
agent.canUseTool("session-1")("Bash", { command: "ls" }, {
|
||||
signal,
|
||||
suggestions: [],
|
||||
toolUseID: "tool-1",
|
||||
} as any),
|
||||
},
|
||||
elicitations[0],
|
||||
])(
|
||||
"cancels $name over the connection and stops waiting for a client that ignores it",
|
||||
async ({ start }) => {
|
||||
const toAgent = new TransformStream<AnyMessage, AnyMessage>();
|
||||
const toClient = new TransformStream<AnyMessage, AnyMessage>();
|
||||
let agent!: ClaudeAcpAgent;
|
||||
acpProtocolRouter(
|
||||
{ log: () => {}, error: () => {} },
|
||||
(created) => (agent = created),
|
||||
"v1",
|
||||
).connect({ readable: toAgent.readable, writable: toClient.writable });
|
||||
const cancelled: string[] = [];
|
||||
// The client holds each request. The signal also aborts when the
|
||||
// connection closes, with another reason than `-32800`.
|
||||
const hold = ({ method, signal }: { method: string; signal: AbortSignal }) =>
|
||||
new Promise<never>(() => {
|
||||
signal.addEventListener("abort", () => {
|
||||
if ((signal.reason as { code?: unknown } | undefined)?.code === -32800) {
|
||||
cancelled.push(method);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
await acpClient({ name: "test-client" })
|
||||
.onRequest(methods.client.session.requestPermission, hold)
|
||||
.onRequest(methods.client.elicitation.create, hold)
|
||||
.connectWith(
|
||||
{ readable: toClient.readable, writable: toAgent.writable },
|
||||
async (client) => {
|
||||
await client.request(methods.agent.initialize, {
|
||||
protocolVersion: 1,
|
||||
clientCapabilities: { elicitation: { form: {} } },
|
||||
});
|
||||
const session = injectSession(agent, "session-1");
|
||||
session.emittedToolCalls.add("tool-1");
|
||||
const controller = new AbortController();
|
||||
const pending = start(agent, controller.signal);
|
||||
await vi.waitFor(() => expect(session.openUserInputs?.size).toBe(1));
|
||||
controller.abort();
|
||||
|
||||
await expect(pending).rejects.toThrow("Tool use aborted");
|
||||
await vi.waitFor(() => expect(cancelled).toHaveLength(1));
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it("cancels a permission request before session/close responds", async () => {
|
||||
const events: string[] = [];
|
||||
const mockClient = {
|
||||
sessionUpdate: async () => {},
|
||||
requestPermission: () => {
|
||||
controller.abort();
|
||||
return clientOperation;
|
||||
requestPermission: (params: RequestPermissionRequest, signal?: AbortSignal) => {
|
||||
signal?.addEventListener("abort", () => events.push("cancel_request"), { once: true });
|
||||
return heldRequest<RequestPermissionResponse>(params, signal);
|
||||
},
|
||||
} as unknown as AcpClient;
|
||||
const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} });
|
||||
const session = injectSession(agent, "session-1");
|
||||
session.emittedToolCalls.add("tool-1");
|
||||
|
||||
await expect(
|
||||
agent.canUseTool("session-1")("Bash", { command: "ls" }, {
|
||||
signal: controller.signal,
|
||||
suggestions: [],
|
||||
toolUseID: "tool-1",
|
||||
} as any),
|
||||
).rejects.toThrow("Tool use aborted");
|
||||
const pending = agent.canUseTool("session-1")("Bash", { command: "ls" }, {
|
||||
signal: new AbortController().signal,
|
||||
suggestions: [],
|
||||
toolUseID: "tool-1",
|
||||
} as any);
|
||||
await vi.waitFor(() => expect(session.openUserInputs?.size).toBe(1));
|
||||
await agent.closeSession({ sessionId: "session-1" });
|
||||
events.push("closed");
|
||||
|
||||
expect(then).toHaveBeenCalledOnce();
|
||||
expect(events).toEqual(["cancel_request", "closed"]);
|
||||
await expect(pending).rejects.toThrow("Tool use aborted");
|
||||
});
|
||||
|
||||
it("does not wait for an eager tool-call update that ignores cancellation", async () => {
|
||||
@@ -6592,7 +6827,7 @@ describe("subagent permission attribution (issue #851)", () => {
|
||||
sessionUpdate: async (notification: AcpSessionNotification) => {
|
||||
updates.push(notification);
|
||||
},
|
||||
requestPermission: () => new Promise(() => {}),
|
||||
requestPermission: heldRequest,
|
||||
} as unknown as AcpClient,
|
||||
{ log: () => {}, error: () => {} },
|
||||
);
|
||||
@@ -7129,7 +7364,7 @@ describe("subagent permission attribution (issue #851)", () => {
|
||||
updates.push(notification);
|
||||
},
|
||||
// A client that ignores $/cancel_request.
|
||||
createElicitation: () => new Promise(() => {}),
|
||||
createElicitation: heldRequest,
|
||||
} as unknown as AcpClient,
|
||||
{ log: () => {}, error: () => {} },
|
||||
);
|
||||
@@ -8425,7 +8660,7 @@ describe("subagent permission attribution (issue #851)", () => {
|
||||
requestPermission: (params: { sessionId: string }, signal?: AbortSignal) => {
|
||||
log.push(`request @${params.sessionId}`);
|
||||
signal?.addEventListener("abort", () => log.push(`withdrawn @${params.sessionId}`));
|
||||
return new Promise(() => {});
|
||||
return heldRequest(params, signal);
|
||||
},
|
||||
} as unknown as AcpClient,
|
||||
{ log: () => {}, error: () => {} },
|
||||
@@ -14388,6 +14623,8 @@ describe("session/fork", () => {
|
||||
{ sessionUpdate: async (n: SessionNotification) => updates.push(n) } as unknown as AcpClient,
|
||||
{ log: () => {}, error: () => {} },
|
||||
);
|
||||
// The scripted sessions run in a cwd that does not exist here.
|
||||
vi.spyOn(agent as any, "validateCwd").mockResolvedValue(undefined);
|
||||
const createSession = vi
|
||||
.spyOn(agent as any, "createSession")
|
||||
.mockImplementation(async (params: any, options: any) => {
|
||||
@@ -14484,6 +14721,35 @@ describe("session/fork", () => {
|
||||
).rejects.toThrow("Claude Code did not start");
|
||||
});
|
||||
|
||||
it("rejects a bad cwd or a relative additional directory before copying the transcript", async () => {
|
||||
const { agent, createSession } = forkingAgent();
|
||||
(agent as any).validateCwd.mockRestore();
|
||||
const missing = path.join(os.tmpdir(), `missing-${randomUUID()}`);
|
||||
|
||||
for (const params of [
|
||||
{ cwd: "workspace" },
|
||||
{ cwd: missing },
|
||||
{ cwd: os.tmpdir(), additionalDirectories: ["extra"] },
|
||||
]) {
|
||||
await expect(
|
||||
agent.unstable_forkSession({ sessionId: "source-id", mcpServers: [], ...params }),
|
||||
).rejects.toMatchObject({ code: -32602 });
|
||||
}
|
||||
expect(forkSession).not.toHaveBeenCalled();
|
||||
expect(createSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("reports an unknown source session as not found", async () => {
|
||||
const { agent, createSession } = forkingAgent();
|
||||
// What the Claude SDK `forkSession` throws for a session without a transcript.
|
||||
vi.mocked(forkSession).mockRejectedValueOnce(new Error("Session source-id not found"));
|
||||
|
||||
await expect(
|
||||
agent.unstable_forkSession({ sessionId: "source-id", cwd: "/workspace", mcpServers: [] }),
|
||||
).rejects.toMatchObject({ code: -32002, data: { sessionId: "source-id" } });
|
||||
expect(createSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("forks the latest turn in the requested workspace", async () => {
|
||||
const { agent, createSession } = forkingAgent();
|
||||
vi.mocked(forkSession).mockResolvedValueOnce({ sessionId: "fork-id" });
|
||||
@@ -14728,6 +14994,7 @@ describe("session/close", () => {
|
||||
toolUseCache: {},
|
||||
emittedToolCalls: new Set(),
|
||||
liveBackgroundTasks: new Map(),
|
||||
background: new SessionBackgroundWork(sessionId, false),
|
||||
emittedAssistantText: false,
|
||||
owedTrailingIdles: 0,
|
||||
messageIdToUuid: new Map(),
|
||||
@@ -14850,6 +15117,7 @@ describe("session/delete", () => {
|
||||
toolUseCache: {},
|
||||
emittedToolCalls: new Set(),
|
||||
liveBackgroundTasks: new Map(),
|
||||
background: new SessionBackgroundWork(sessionId, false),
|
||||
emittedAssistantText: false,
|
||||
owedTrailingIdles: 0,
|
||||
messageIdToUuid: new Map(),
|
||||
@@ -14945,7 +15213,10 @@ describe("getOrCreateSession param change detection", () => {
|
||||
const mockClient = {
|
||||
sessionUpdate: async () => {},
|
||||
} as unknown as AcpClient;
|
||||
return new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} });
|
||||
const agent = new ClaudeAcpAgent(mockClient, { log: () => {}, error: () => {} });
|
||||
// The injected sessions run in cwds that do not exist here, such as "/test".
|
||||
vi.spyOn(agent as any, "validateCwd").mockResolvedValue(undefined);
|
||||
return agent;
|
||||
}
|
||||
|
||||
function injectSession(
|
||||
@@ -15010,6 +15281,7 @@ describe("getOrCreateSession param change detection", () => {
|
||||
toolUseCache: {},
|
||||
emittedToolCalls: new Set(),
|
||||
liveBackgroundTasks: new Map(),
|
||||
background: new SessionBackgroundWork(sessionId, false),
|
||||
emittedAssistantText: false,
|
||||
owedTrailingIdles: 0,
|
||||
messageIdToUuid: new Map(),
|
||||
@@ -15061,6 +15333,32 @@ describe("getOrCreateSession param change detection", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps the live session when a resume or load names a bad cwd or additional directory", async () => {
|
||||
const agent = createMockAgent();
|
||||
(agent as any).validateCwd.mockRestore();
|
||||
const session = injectSession(agent, "s1", { cwd: "/old" });
|
||||
const createSessionSpy = vi.spyOn(agent as any, "createSession");
|
||||
const missing = path.join(os.tmpdir(), `missing-${randomUUID()}`);
|
||||
|
||||
for (const params of [
|
||||
{ cwd: "relative" },
|
||||
{ cwd: missing },
|
||||
{ cwd: os.tmpdir(), additionalDirectories: ["extra"] },
|
||||
]) {
|
||||
await expect(
|
||||
agent.resumeSession({ sessionId: "s1", mcpServers: [], ...params }),
|
||||
).rejects.toMatchObject({ code: -32602 });
|
||||
}
|
||||
vi.mocked(getSessionMessages).mockResolvedValueOnce([]);
|
||||
await expect(
|
||||
agent.loadSession({ sessionId: "s1", cwd: missing, mcpServers: [] }),
|
||||
).rejects.toMatchObject({ code: -32602 });
|
||||
|
||||
expect(agent.sessions["s1"]).toBe(session);
|
||||
expect(session.abortController.signal.aborted).toBe(false);
|
||||
expect(createSessionSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
// Claude Code writes the conversation at the first prompt, so a live session
|
||||
// that was never prompted has nothing to resume.
|
||||
it("starts a fresh query under the same id for a live session that was never prompted", async () => {
|
||||
@@ -18556,6 +18854,38 @@ describe("assembled assistant text fallback", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("logs session_writes_lost after the last result without sending an update", async () => {
|
||||
const updates: any[] = [];
|
||||
const error = vi.fn();
|
||||
const agent = new ClaudeAcpAgent(
|
||||
{ sessionUpdate: async (n: any) => updates.push(n) } as unknown as AcpClient,
|
||||
{ log: () => {}, error },
|
||||
);
|
||||
injectSession(agent, [
|
||||
replayedResult("done"),
|
||||
idle,
|
||||
{
|
||||
type: "system",
|
||||
subtype: "session_writes_lost",
|
||||
error_code: "ENOSPC",
|
||||
lost: ["transcript", "global_config"],
|
||||
transcript_session_ids: ["test-session"],
|
||||
uuid: randomUUID(),
|
||||
session_id: "test-session",
|
||||
},
|
||||
]);
|
||||
|
||||
await agent.prompt({ sessionId: "test-session", prompt: [{ type: "text", text: "1+2" }] });
|
||||
const sentAtTurnEnd = updates.length;
|
||||
|
||||
await vi.waitFor(() =>
|
||||
expect(error).toHaveBeenCalledWith(
|
||||
"Session test-session: Claude Code could not save transcript and global_config (ENOSPC); resuming may miss part of the conversation",
|
||||
),
|
||||
);
|
||||
expect(updates).toHaveLength(sentAtTurnEnd);
|
||||
});
|
||||
|
||||
it("marks info-level notices even when their text has no severity prefix", async () => {
|
||||
const { agent, updates } = createMockAgentWithCapture();
|
||||
injectSession(agent, [
|
||||
@@ -19465,6 +19795,7 @@ describe("post-error recovery", () => {
|
||||
toolUseCache: {},
|
||||
emittedToolCalls: new Set(),
|
||||
liveBackgroundTasks: new Map(),
|
||||
background: new SessionBackgroundWork("test-session", false),
|
||||
emittedAssistantText: false,
|
||||
owedTrailingIdles: 0,
|
||||
messageIdToUuid: new Map(),
|
||||
@@ -19989,6 +20320,72 @@ describe("post-error recovery", () => {
|
||||
await agent.sessions["test-session"]?.consumer;
|
||||
});
|
||||
|
||||
it("does not cancel a prompt received while the cancel awaits", async () => {
|
||||
// Turn 1 runs and turn 2 is queued when the cancel arrives. Turn 3 arrives
|
||||
// while the cancel awaits `contextCompaction.interrupt()`: ACP v2 cancels
|
||||
// only prompts received before `session/cancel`, so turn 3 must run.
|
||||
const agent = createMockAgent();
|
||||
let releaseInterrupt!: () => void;
|
||||
const interruptGate = new Promise<void>((resolve) => (releaseInterrupt = resolve));
|
||||
let releaseStream!: () => void;
|
||||
const streamGate = new Promise<void>((resolve) => (releaseStream = resolve));
|
||||
const orphanResult = createResultMessage({
|
||||
subtype: "success",
|
||||
stop_reason: "end_turn",
|
||||
is_error: false,
|
||||
});
|
||||
injectGeneratorSession(
|
||||
agent,
|
||||
(input) => {
|
||||
async function* messageGenerator() {
|
||||
const iter = input[Symbol.asyncIterator]();
|
||||
const u1 = await iter.next();
|
||||
yield userEcho(u1.value); // turn 1 active
|
||||
await iter.next(); // turn 2, queued before the cancel
|
||||
const u3 = await iter.next(); // turn 3, queued during the cancel
|
||||
await streamGate;
|
||||
yield { type: "system", subtype: "session_state_changed", state: "idle" }; // turn 1 cancelled
|
||||
yield orphanResult; // turn 2's result, skipped as an orphan
|
||||
yield userEcho(u3.value);
|
||||
yield createResultMessage({
|
||||
subtype: "success",
|
||||
stop_reason: "end_turn",
|
||||
is_error: false,
|
||||
});
|
||||
yield { type: "system", subtype: "session_state_changed", state: "idle" };
|
||||
}
|
||||
return messageGenerator();
|
||||
},
|
||||
{ contextCompaction: { interrupt: () => interruptGate } },
|
||||
);
|
||||
|
||||
const first = agent.prompt({
|
||||
sessionId: "test-session",
|
||||
prompt: [{ type: "text", text: "first" }],
|
||||
});
|
||||
await waitFor(() => !!agent.sessions["test-session"]?.activeTurn);
|
||||
const second = agent.prompt({
|
||||
sessionId: "test-session",
|
||||
prompt: [{ type: "text", text: "second" }],
|
||||
});
|
||||
await waitFor(() => (agent.sessions["test-session"]?.turnQueue?.length ?? 0) >= 2);
|
||||
|
||||
const cancel = agent.cancel({ sessionId: "test-session" });
|
||||
const third = agent.prompt({
|
||||
sessionId: "test-session",
|
||||
prompt: [{ type: "text", text: "third" }],
|
||||
});
|
||||
await waitFor(() => (agent.sessions["test-session"]?.turnQueue?.length ?? 0) >= 3);
|
||||
releaseInterrupt();
|
||||
await cancel;
|
||||
releaseStream();
|
||||
|
||||
await expect(first).resolves.toMatchObject({ stopReason: "cancelled" });
|
||||
await expect(second).resolves.toEqual({ stopReason: "cancelled" });
|
||||
await expect(third).resolves.toMatchObject({ stopReason: "end_turn" });
|
||||
await agent.sessions["test-session"]?.consumer;
|
||||
});
|
||||
|
||||
it("drains the orphan count, then promotes a no-echo /compact while still cancelled", async () => {
|
||||
// The case that ONLY the orphan-count gate handles (the old `!cancelled`
|
||||
// gate would hang it): cancel removes a queued turn (count=1), its orphan
|
||||
@@ -21846,7 +22243,7 @@ describe("output after a cancel", () => {
|
||||
expect(texts).toEqual(["Starting the build.", "The build", " passed."]);
|
||||
});
|
||||
|
||||
it("drops the answer to a prompt sent while the cancel was still in progress", async () => {
|
||||
it("answers a prompt sent while the cancel was still in progress", async () => {
|
||||
const interrupting = Promise.withResolvers<void>();
|
||||
const release = Promise.withResolvers<void>();
|
||||
const cancelDone = Promise.withResolvers<void>();
|
||||
@@ -21895,14 +22292,20 @@ describe("output after a cancel", () => {
|
||||
await cancelling;
|
||||
cancelDone.resolve();
|
||||
|
||||
// The cancel covers only the prompts received before it.
|
||||
await expect(first).resolves.toMatchObject({ stopReason: "cancelled" });
|
||||
await expect(second).resolves.toEqual({ stopReason: "cancelled" });
|
||||
await expect(second).resolves.toMatchObject({ stopReason: "end_turn" });
|
||||
await consumer;
|
||||
expect(texts).toEqual(["Starting the build.", "The build", " passed."]);
|
||||
expect(texts).toEqual([
|
||||
"Starting the build.",
|
||||
"Here is the second answer.",
|
||||
"The build",
|
||||
" passed.",
|
||||
]);
|
||||
expect(session.lastTurnFailed).not.toBe(true);
|
||||
});
|
||||
|
||||
it("drops the answer to a prompt sent during the cancel whose request comes before the cancel abandons it", async () => {
|
||||
it("answers a prompt sent during the cancel that Claude Code takes before the cancel ends", async () => {
|
||||
const interrupting = Promise.withResolvers<void>();
|
||||
const release = Promise.withResolvers<void>();
|
||||
const requested = Promise.withResolvers<void>();
|
||||
@@ -21955,10 +22358,16 @@ describe("output after a cancel", () => {
|
||||
await cancelling;
|
||||
swept.resolve();
|
||||
|
||||
// The cancel covers only the prompts received before it.
|
||||
await expect(first).resolves.toMatchObject({ stopReason: "cancelled" });
|
||||
await expect(second).resolves.toEqual({ stopReason: "cancelled" });
|
||||
await expect(second).resolves.toMatchObject({ stopReason: "end_turn" });
|
||||
await consumer;
|
||||
expect(texts).toEqual(["Starting the build.", "The build", " passed."]);
|
||||
expect(texts).toEqual([
|
||||
"Starting the build.",
|
||||
"Here is the second answer.",
|
||||
"The build",
|
||||
" passed.",
|
||||
]);
|
||||
});
|
||||
|
||||
it("keeps the prompts an earlier cancel stopped when the user cancels again", async () => {
|
||||
@@ -26538,7 +26947,7 @@ describe("turn steering (_session/steering)", () => {
|
||||
"uses priority:'now' again once $name is withdrawn, though its client never settles it",
|
||||
async ({ start }) => {
|
||||
// A client that ignores $/cancel_request: its request never settles.
|
||||
const userInputRequest = vi.fn(() => new Promise<never>(() => {}));
|
||||
const userInputRequest = vi.fn(heldRequest<never>);
|
||||
const input = new Pushable<any>();
|
||||
const inputPush = vi.spyOn(input, "push");
|
||||
const agent = new ClaudeAcpAgent(
|
||||
@@ -27822,6 +28231,7 @@ describe("session/cancel wedge recovery (issue #680)", () => {
|
||||
toolUseCache: {},
|
||||
emittedToolCalls: new Set(),
|
||||
liveBackgroundTasks: new Map(),
|
||||
background: new SessionBackgroundWork("test-session", false),
|
||||
emittedAssistantText: false,
|
||||
owedTrailingIdles: 0,
|
||||
messageIdToUuid: new Map(),
|
||||
@@ -29730,6 +30140,7 @@ describe("agent selection config option", () => {
|
||||
toolUseCache: {},
|
||||
emittedToolCalls: new Set(),
|
||||
liveBackgroundTasks: new Map(),
|
||||
background: new SessionBackgroundWork(sessionId, false),
|
||||
emittedAssistantText: false,
|
||||
owedTrailingIdles: 0,
|
||||
messageIdToUuid: new Map(),
|
||||
|
||||
@@ -12,6 +12,6 @@
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>:replay-subagent:toolu_r_task","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_r_task"}},"content":{"text":"Subagent text.","type":"text"},"messageId":"msg_r_sub","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"content":{"text":"Fixed.","type":"text"},"messageId":"msg_r2","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"sessionUpdate":"subagent_state_update","state":"completed","subagentSessionId":"<session>:replay-subagent:toolu_r_task"}}}
|
||||
{"kind":"loadSession","payload":{"configOptions":[{"category":"mode","currentValue":"default","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"default"},"sessionId":"<session>"}}
|
||||
{"kind":"loadSession","payload":{"configOptions":[{"category":"mode","currentValue":"auto","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"auto"},"sessionId":"<session>"}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>:replay-subagent:toolu_r_task","update":{"configOptions":[{"category":"model","currentValue":"claude-sonnet-4-6","id":"model","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]"},"name":"mcp"}],"sessionUpdate":"available_commands_update"}}}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{"kind":"initialize","payload":{"_meta":{"jetbrains":{"air":{"capabilities":["sessionFailure","agentFileChangeReport","nativeSubagentSessions","asyncTasks","customInstructions","recommendedValue","diffPatch","planFile","backgroundSubagents"],"goal":{"actions":["set","clear"],"controlMethod":"_session/goal","version":1},"version":1}},"steering":{"supported":true}},"agentCapabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"auth":{"logout":{}},"loadSession":true,"mcpCapabilities":{"http":true,"sse":true},"promptCapabilities":{"embeddedContext":true,"image":true},"providers":{},"sessionCapabilities":{"additionalDirectories":{},"close":{},"delete":{},"fork":{},"list":{},"resume":{},"subagents":{},"systemPrompt":{"mode":{"override":{}}}}},"agentInfo":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"authMethods":[],"protocolVersion":1}}
|
||||
{"kind":"newSession","payload":{"configOptions":[{"category":"mode","currentValue":"default","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"default"},"sessionId":"<session>"}}
|
||||
{"kind":"newSession","payload":{"configOptions":[{"category":"mode","currentValue":"auto","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"jetbrains":{"air":{"kind":"standard","version":1}}},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"jetbrains":{"air":{"kind":"plan","version":1}}},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"jetbrains":{"air":{"kind":"auto_review","version":1}}},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"jetbrains":{"air":{"kind":"full_access","version":1}}},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"auto"},"sessionId":"<session>"}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]"},"name":"mcp"}],"sessionUpdate":"available_commands_update"}}}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"other","name":"AskUserQuestion","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Asking for your input","toolCallId":"toolu_ask"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"Which database?","type":"text"},"type":"content"}],"rawInput":{"questions":[{"header":"Database","multiSelect":false,"options":[{"description":"Relational","label":"Postgres","preview":"CREATE TABLE t ();"},{"description":"Key-value","label":"Redis"}],"question":"Which database?"}]},"sessionUpdate":"tool_call_update","title":"Which database?","toolCallId":"toolu_ask"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"elicitation/create","payload":{"message":"Which database?","mode":"form","requestedSchema":{"properties":{"question_0":{"oneOf":[{"_meta":{"_claude/askUserQuestionOption":{"preview":"CREATE TABLE t ();"}},"const":"Postgres","description":"Relational","title":"Postgres"},{"const":"Redis","description":"Key-value","title":"Redis"}],"title":"Database","type":"string"},"question_0_custom":{"description":"Type your own answer, or add a note to the option you chose above (optional).","title":"Other","type":"string"}},"type":"object"},"sessionId":"<session>","toolCallId":"toolu_ask"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"User has answered your questions: \"Which database?\"=\"Postgres\".","type":"text"},"type":"content"}],"rawOutput":"User has answered your questions: \"Which database?\"=\"Postgres\".","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_ask"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"terminal_update","terminalId":"toolu_bg"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"terminalId":"toolu_bg","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Terminal","toolCallId":"toolu_bg"}}}
|
||||
@@ -15,4 +15,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"exitStatus":{},"sessionUpdate":"terminal_update","terminalId":"toolu_bg"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_bg"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"terminal_update","terminalId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"terminalId":"toolu_bash","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Terminal","toolCallId":"toolu_bash"}}}
|
||||
@@ -14,4 +14,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"exitStatus":{"exitCode":1},"sessionUpdate":"terminal_update","terminalId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"tool_call_update","status":"failed","toolCallId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"terminal_update","terminalId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"terminalId":"toolu_bash","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Terminal","toolCallId":"toolu_bash"}}}
|
||||
@@ -10,9 +10,9 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"command":"ls -la"},"sessionUpdate":"tool_call_update","title":"ls -la","toolCallId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"command":"ls -la","description":"List files"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"terminalId":"toolu_bash","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{"command":"ls -la","description":"List files"},"title":"ls -la","toolCallId":"toolu_bash"},"type":"tool_call"},"title":"ls -la"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"output":{"data":"YS50cwpiLnRz"},"sessionUpdate":"terminal_update","terminalId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"exitStatus":{"exitCode":0},"sessionUpdate":"terminal_update","terminalId":"toolu_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_bash"}}}
|
||||
@@ -20,4 +20,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"ne.","type":"text"},"messageId":"msg_done","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","sessionUpdate":"compaction_update","status":"in_progress"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","error":"Context too small","sessionUpdate":"compaction_update","status":"failed"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","sessionUpdate":"compaction_update","status":"in_progress"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","content":{"text":"The summary.","type":"text"},"sessionUpdate":"compaction_summary_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","sessionUpdate":"compaction_update","status":"completed"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"usage_update","size":200000,"used":100}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":100}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","sessionUpdate":"compaction_update","status":"in_progress"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","content":{"text":"The summary.","type":"text"},"sessionUpdate":"compaction_summary_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"compactionId":"00000000-0000-4000-8000-000000000001","sessionUpdate":"compaction_update","status":"completed"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"usage_update","size":200000,"used":100}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":100}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"edit","locations":[],"name":"Edit","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Edit","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"locations":[{"path":"<cwd>/src/app.ts"}],"rawInput":{"file_path":"<cwd>/src/app.ts"},"sessionUpdate":"tool_call_update","title":"Edit src/app.ts","toolCallId":"toolu_edit"}}}
|
||||
@@ -10,9 +10,9 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"file_path":"<cwd>/src/app.ts","new_string":"value = 2","old_string":"value = 1"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"changes":[{"fileType":"text","operation":"modify","path":"<cwd>/src/app.ts"}],"patch":{"format":"git_patch","text":"diff --git <cwd>/src/app.ts <cwd>/src/app.ts\n--- <cwd>/src/app.ts\n+++ <cwd>/src/app.ts\n@@ -1 +1 @@\n-const value = 1;\n+const value = 2;\n"},"type":"diff"}],"sessionUpdate":"tool_call_update","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"changes":[{"fileType":"text","operation":"modify","path":"<cwd>/src/app.ts"}],"patch":{"format":"git_patch","text":"diff --git <cwd>/src/app.ts <cwd>/src/app.ts\n--- <cwd>/src/app.ts\n+++ <cwd>/src/app.ts\n@@ -1 +1 @@\n-const value = 1;\n+const value = 2;\n"},"type":"diff"}],"kind":"edit","locations":[{"path":"<cwd>/src/app.ts"}],"name":"Edit","rawInput":{"file_path":"<cwd>/src/app.ts","new_string":"value = 2","old_string":"value = 1"},"title":"Edit src/app.ts","toolCallId":"toolu_edit"},"type":"tool_call"},"title":"Edit src/app.ts"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"```\nThe user doesn't want to proceed with this tool use. The tool use was rejected.\n```","type":"text"},"type":"content"}],"rawOutput":"The user doesn't want to proceed with this tool use. The tool use was rejected.","sessionUpdate":"tool_call_update","status":"failed","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"edit","locations":[],"name":"Edit","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Edit","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"locations":[{"path":"<cwd>/src/app.ts"}],"rawInput":{"file_path":"<cwd>/src/app.ts"},"sessionUpdate":"tool_call_update","title":"Edit src/app.ts","toolCallId":"toolu_edit"}}}
|
||||
@@ -10,10 +10,10 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"file_path":"<cwd>/src/app.ts","new_string":"const value = 2;","old_string":"const value = 1;"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"changes":[{"fileType":"text","operation":"modify","path":"<cwd>/src/app.ts"}],"patch":{"format":"git_patch","text":"diff --git <cwd>/src/app.ts <cwd>/src/app.ts\n--- <cwd>/src/app.ts\n+++ <cwd>/src/app.ts\n@@ -1,3 +1,3 @@\n line 1\n-const value = 1;\n+const value = 2;\n line 3\n"},"type":"diff"}],"sessionUpdate":"tool_call_update","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"changes":[{"fileType":"text","operation":"modify","path":"<cwd>/src/app.ts"}],"patch":{"format":"git_patch","text":"diff --git <cwd>/src/app.ts <cwd>/src/app.ts\n--- <cwd>/src/app.ts\n+++ <cwd>/src/app.ts\n@@ -1,3 +1,3 @@\n line 1\n-const value = 1;\n+const value = 2;\n line 3\n"},"type":"diff"}],"kind":"edit","locations":[{"path":"<cwd>/src/app.ts"}],"name":"Edit","rawInput":{"file_path":"<cwd>/src/app.ts","new_string":"const value = 2;","old_string":"const value = 1;"},"title":"Edit src/app.ts","toolCallId":"toolu_edit"},"type":"tool_call"},"title":"Edit src/app.ts"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawOutput":"The file <cwd>/src/app.ts has been updated successfully.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"locations":[{"line":1,"path":"<cwd>/src/app.ts"}],"sessionUpdate":"tool_call_update","toolCallId":"toolu_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"switch_mode","name":"ExitPlanMode","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Approve Plan","toolCallId":"toolu_plan"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"# Plan\n1. Do it","type":"text"},"type":"content"}],"rawInput":{"plan":"# Plan\n1. Do it"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_plan"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes, manually approve edits","optionId":"exit-plan-default"},{"kind":"allow_always","name":"Yes, clear context (0% used) and use auto mode","optionId":"exit-plan-clear-auto"},{"kind":"allow_always","name":"Yes, and use auto mode","optionId":"exit-plan-auto"},{"kind":"allow_always","name":"Yes, and bypass permissions","optionId":"exit-plan-bypass"},{"kind":"reject_once","name":"No, keep planning","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"content":{"text":"# Plan\n1. Do it","type":"text"},"type":"content"}],"kind":"switch_mode","name":"ExitPlanMode","rawInput":{"plan":"# Plan\n1. Do it"},"title":"Approve Plan","toolCallId":"toolu_plan"},"type":"tool_call"},"title":"Ready to code?"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawOutput":"User has approved your plan. You can now start coding.\n\n## Approved Plan:\n# Plan\n1. Do it","sessionUpdate":"tool_call_update","status":"completed","title":"Exited Plan Mode","toolCallId":"toolu_plan"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"plan":{"content":"# Plan\n1. Do it","planId":"plan-mode","type":"markdown"},"sessionUpdate":"plan_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"switch_mode","name":"ExitPlanMode","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Approve Plan","toolCallId":"toolu_plan"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"# Plan\n1. Do it","type":"text"},"type":"content"}],"rawInput":{"plan":"# Plan\n1. Do it"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_plan"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes, manually approve edits","optionId":"exit-plan-default"},{"kind":"allow_always","name":"Yes, clear context (0% used) and use auto mode","optionId":"exit-plan-clear-auto"},{"kind":"allow_always","name":"Yes, and use auto mode","optionId":"exit-plan-auto"},{"kind":"allow_always","name":"Yes, and bypass permissions","optionId":"exit-plan-bypass"},{"kind":"reject_once","name":"No, keep planning","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"content":{"text":"# Plan\n1. Do it","type":"text"},"type":"content"}],"kind":"switch_mode","name":"ExitPlanMode","rawInput":{"plan":"# Plan\n1. Do it"},"title":"Approve Plan","toolCallId":"toolu_plan"},"type":"tool_call"},"title":"Ready to code?"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"```\n```\nThe user doesn't want to proceed with this tool use.\n```\n```","type":"text"},"type":"content"}],"rawOutput":"The user doesn't want to proceed with this tool use.","sessionUpdate":"tool_call_update","status":"failed","toolCallId":"toolu_plan"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"/goal Ship the feature","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"search","name":"Grep","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"grep","toolCallId":"toolu_grep"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"pattern":"value"},"sessionUpdate":"tool_call_update","title":"grep \"value\"","toolCallId":"toolu_grep"}}}
|
||||
@@ -16,4 +16,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"pattern":"**/*.ts"},"sessionUpdate":"tool_call_update","title":"Find `**/*.ts`","toolCallId":"toolu_glob"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"src/app.ts\nsrc/b.ts","type":"text"},"type":"content"}],"rawOutput":"src/app.ts\nsrc/b.ts","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_glob"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"other","name":"mcp__docs__search","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"mcp__docs__search","toolCallId":"toolu_mcp"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"q":"acp"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_mcp"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"_meta":{"claudeCode":{"mcpServer":{"name":"docs","source":"project"}}},"content":[],"kind":"other","name":"mcp__docs__search","rawInput":{"q":"acp"},"title":"mcp__docs__search","toolCallId":"toolu_mcp"},"type":"tool_call"},"title":"mcp__docs__search"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"Found 2 documents.","type":"text"},"type":"content"}],"rawOutput":[{"text":"Found 2 documents.","type":"text"}],"sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_mcp"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolResponse":{"mode":"select"}}},"kind":"read","locations":[{"path":"/memory/a.md"},{"path":"/memory/b.md"}],"name":"memory_recall","sessionUpdate":"tool_call_update","status":"completed","title":"Recalled 2 memories","toolCallId":"00000000-0000-4000-8000-000000000001"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolResponse":{"mode":"synthesize"}}},"content":[{"content":{"text":"The user prefers tabs.","type":"text"},"type":"content"}],"kind":"read","name":"memory_recall","sessionUpdate":"tool_call_update","status":"completed","title":"Recalled synthesized memory","toolCallId":"00000000-0000-4000-8000-000000000002"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"other","name":"SandboxNetworkAccess","rawInput":{"host":"example.com"},"sessionUpdate":"tool_call_update","status":"pending","title":"SandboxNetworkAccess","toolCallId":"toolu_net"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"description":"Reason: Sandbox blocks network","options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"content":{"text":"```json\n{\n \"host\": \"example.com\"\n}\n```","type":"text"},"type":"content"}],"kind":"other","name":"SandboxNetworkAccess","rawInput":{"host":"example.com"},"title":"example.com","toolCallId":"toolu_net"},"type":"tool_call"},"title":"example.com"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_net"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"other","name":"NotebookEdit","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"NotebookEdit","toolCallId":"toolu_nb"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"notebook_path":"<cwd>/n.ipynb"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_nb"}}}
|
||||
@@ -10,9 +10,9 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"cell_id":"cell-1","new_source":"print('hi')","notebook_path":"<cwd>/n.ipynb"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_nb"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"cell_id":"cell-1","edit_mode":"replace","new_source":"print('hi')","notebook_path":"<cwd>/n.ipynb"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_nb"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[],"kind":"other","name":"NotebookEdit","rawInput":{"cell_id":"cell-1","edit_mode":"replace","new_source":"print('hi')","notebook_path":"<cwd>/n.ipynb"},"title":"NotebookEdit","toolCallId":"toolu_nb"},"type":"tool_call"},"title":"NotebookEdit"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"Updated cell cell-1 with print('hi')","type":"text"},"type":"content"}],"rawOutput":"Updated cell cell-1 with print('hi')","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_nb"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"terminal_update","terminalId":"toolu_denied"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"terminalId":"toolu_denied","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Terminal","toolCallId":"toolu_denied"}}}
|
||||
@@ -14,4 +14,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"exitStatus":{},"sessionUpdate":"terminal_update","terminalId":"toolu_denied"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"terminalId":"toolu_denied","type":"terminal"}],"sessionUpdate":"tool_call_update","toolCallId":"toolu_denied"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"Work","type":"text"},"messageId":"msg_rate","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"ing.","type":"text"},"messageId":"msg_rate","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6","_claude/rateLimit":{"resetsAt":1700000000,"status":"allowed_warning","utilization":0.9}},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6","_claude/origin":{"kind":"human"}},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"read","locations":[],"name":"Read","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Read File","toolCallId":"toolu_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"locations":[{"line":1,"path":"<cwd>/a.ts"}],"rawInput":{"file_path":"<cwd>/a.ts"},"sessionUpdate":"tool_call_update","title":"Read a.ts","toolCallId":"toolu_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"```\n1\tconst a = 1;\n```","type":"text"},"type":"content"}],"rawOutput":"1\tconst a = 1;\n<system-reminder>x</system-reminder>","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -18,5 +18,5 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"Fixed.","type":"text"},"messageId":"msg_r2","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"description":"The history of 1 subagent of this session could not be restored.","sessionUpdate":"notice","severity":"info","title":"Some subagent history is not available"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"session_info_update","title":"Fix the app","updatedAt":"2026-01-01T00:00:00.000Z"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"idle"}}}
|
||||
{"kind":"response","method":"session/resume","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}]}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"idle"}}}
|
||||
{"kind":"response","method":"session/resume","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}]}}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"other","name":"Skill","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Load skill","toolCallId":"toolu_skill"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"skill":"commits"},"sessionUpdate":"tool_call_update","title":"Load skill: commits","toolCallId":"toolu_skill"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawOutput":"Launching skill: commits","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_skill"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"general-purpose","sessionId":"a2","sessionUpdate":"subagent_update","state":{"state":"running"},"title":"Background review"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"general-purpose","sessionId":"a2","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"},"title":"Background review"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Review the diff","type":"text"}],"messageId":"toolu_agent","recipientMessageId":"toolu_agent","recipientSessionId":"a2","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"content":[{"text":"Review the diff","type":"text"}],"messageId":"toolu_agent","recipientSessionId":"a2","senderMessageId":"toolu_agent","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_agent"}},"configOptions":[{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_agent"}},"content":{"text":"Reviewi","type":"text"},"messageId":"msg_async_sub","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_agent"}},"content":{"text":"ng now.","type":"text"},"messageId":"msg_async_sub","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"a2","sessionUpdate":"subagent_update","state":{"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"a2","sessionUpdate":"subagent_update","state":{"background":[],"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"a2","update":{"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"general-purpose","sessionId":"agent_late","sessionUpdate":"subagent_update","state":{"state":"running"},"title":"Check the logs"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"general-purpose","sessionId":"agent_late","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"},"title":"Check the logs"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Check logs","type":"text"}],"messageId":"toolu_late","recipientMessageId":"toolu_late","recipientSessionId":"agent_late","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"content":[{"text":"Check logs","type":"text"}],"messageId":"toolu_late","recipientSessionId":"agent_late","senderMessageId":"toolu_late","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_late"}},"configOptions":[{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_late"}},"content":[],"kind":"read","locations":[],"name":"Read","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Read File","toolCallId":"toolu_late_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"locations":[{"line":1,"path":"/var/log/app.log"}],"rawInput":{"file_path":"/var/log/app.log"},"sessionUpdate":"tool_call_update","title":"Read /var/log/app.log","toolCallId":"toolu_late_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"The logs are clean.","type":"text"}],"messageId":"toolu_late:reply","recipientSessionId":"<session>","senderSessionId":"agent_late","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_late","sessionUpdate":"subagent_update","state":{"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_late","sessionUpdate":"subagent_update","state":{"background":[],"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_late","toolResponse":{"elapsedTimeSeconds":4}}},"sessionUpdate":"tool_call_update","status":"in_progress","toolCallId":"toolu_late_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_late","update":{"content":[{"content":{"text":"```\n1\tok\n```","type":"text"},"type":"content"}],"rawOutput":"1\tok","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_late_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"general-purpose","sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"state":"running"},"title":"Fix the build"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"general-purpose","sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"},"title":"Fix the build"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Make the build pass","type":"text"}],"messageId":"toolu_native","recipientMessageId":"toolu_native","recipientSessionId":"agent_n","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"content":[{"text":"Make the build pass","type":"text"}],"messageId":"toolu_native","recipientSessionId":"agent_n","senderMessageId":"toolu_native","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_native"}},"configOptions":[{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
@@ -21,17 +21,17 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"command":"make","sessionUpdate":"terminal_update","terminalId":"toolu_native_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"rawInput":{"command":"make"},"sessionUpdate":"tool_call_update","title":"make","toolCallId":"toolu_native_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"rawInput":{"command":"make","description":"Build"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_native_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"state":"requires_action"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"background":[],"state":"requires_action"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"agent_n","subject":{"toolCall":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_native"}},"content":[{"terminalId":"toolu_native_bash","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{"command":"make","description":"Build"},"title":"make","toolCallId":"toolu_native_bash"},"type":"tool_call"},"title":"make"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"state":"running"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"output":{"data":"bWFrZTogKioqIEVycm9yIDI="},"sessionUpdate":"terminal_update","terminalId":"toolu_native_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"exitStatus":{},"sessionUpdate":"terminal_update","terminalId":"toolu_native_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"sessionUpdate":"tool_call_update","status":"failed","toolCallId":"toolu_native_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"state":"idle","stopReason":"error"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"sessionUpdate":"state_update","state":"idle","stopReason":"error"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_n","sessionUpdate":"subagent_update","state":{"background":[],"state":"idle","stopReason":"error"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_n","update":{"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"error"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"Plan","sessionId":"agent_outer","sessionUpdate":"subagent_update","state":{"state":"running"},"title":"Plan the work"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"Plan","sessionId":"agent_outer","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"},"title":"Plan the work"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Plan it","type":"text"}],"messageId":"toolu_outer","recipientMessageId":"toolu_outer","recipientSessionId":"agent_outer","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"content":[{"text":"Plan it","type":"text"}],"messageId":"toolu_outer","recipientSessionId":"agent_outer","senderMessageId":"toolu_outer","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_outer"}},"configOptions":[{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"capabilities":{"cancel":{}},"description":"Explore","sessionId":"agent_inner","sessionUpdate":"subagent_update","state":{"state":"running"},"title":"Read the spec"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"capabilities":{"cancel":{}},"description":"Explore","sessionId":"agent_inner","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"},"title":"Read the spec"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"content":[{"text":"Read spec.md","type":"text"}],"messageId":"toolu_inner","recipientMessageId":"toolu_inner","recipientSessionId":"agent_inner","senderSessionId":"agent_outer","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"content":[{"text":"Read spec.md","type":"text"}],"messageId":"toolu_inner","recipientSessionId":"agent_inner","senderMessageId":"toolu_inner","senderSessionId":"agent_outer","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_inner"}},"configOptions":[{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
@@ -19,12 +19,12 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"locations":[{"line":1,"path":"/spec.md"}],"rawInput":{"file_path":"/spec.md"},"sessionUpdate":"tool_call_update","title":"Read /spec.md","toolCallId":"toolu_grandchild_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"content":[{"content":{"text":"```\n1\tspec\n```","type":"text"},"type":"content"}],"rawOutput":"1\tspec","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_grandchild_read"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"content":[{"text":"The spec says X.","type":"text"}],"messageId":"toolu_inner:reply","recipientSessionId":"agent_outer","senderSessionId":"agent_inner","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"sessionId":"agent_inner","sessionUpdate":"subagent_update","state":{"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"sessionId":"agent_inner","sessionUpdate":"subagent_update","state":{"background":[],"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_inner","update":{"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_outer"}},"content":{"text":"Plan:","type":"text"},"messageId":"msg_outer_text","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_outer"}},"content":{"text":" do X.","type":"text"},"messageId":"msg_outer_text","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Plan: do X.","type":"text"}],"messageId":"toolu_outer:reply","recipientSessionId":"<session>","senderSessionId":"agent_outer","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_outer","sessionUpdate":"subagent_update","state":{"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_outer","sessionUpdate":"subagent_update","state":{"background":[],"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_outer","update":{"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"Explore","sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"state":"running"},"title":"Explore code"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"Explore","sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"},"title":"Explore code"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Find the parser","type":"text"}],"messageId":"toolu_task","recipientMessageId":"toolu_task","recipientSessionId":"agent_1","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"content":[{"text":"Find the parser","type":"text"}],"messageId":"toolu_task","recipientSessionId":"agent_1","senderMessageId":"toolu_task","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_task"}},"configOptions":[{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
@@ -20,13 +20,13 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"command":"rg parser","sessionUpdate":"terminal_update","terminalId":"toolu_sub_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"rawInput":{"command":"rg parser"},"sessionUpdate":"tool_call_update","title":"rg parser","toolCallId":"toolu_sub_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"rawInput":{"command":"rg parser","description":"Search"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_sub_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"state":"requires_action"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"background":[],"state":"requires_action"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"agent_1","subject":{"toolCall":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_task"}},"content":[{"terminalId":"toolu_sub_bash","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{"command":"rg parser","description":"Search"},"title":"rg parser","toolCallId":"toolu_sub_bash"},"type":"tool_call"},"title":"rg parser"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"state":"running"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"output":{"data":"eC50cw=="},"sessionUpdate":"terminal_update","terminalId":"toolu_sub_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"exitStatus":{"exitCode":0},"sessionUpdate":"terminal_update","terminalId":"toolu_sub_bash"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_sub_bash"}}}
|
||||
@@ -34,19 +34,19 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"locations":[{"path":"<cwd>/x.ts"}],"rawInput":{"file_path":"<cwd>/x.ts"},"sessionUpdate":"tool_call_update","title":"Edit x.ts","toolCallId":"toolu_sub_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"rawInput":{"file_path":"<cwd>/x.ts","old_string":"a"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_sub_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"rawInput":{"file_path":"<cwd>/x.ts","new_string":"b","old_string":"a"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_sub_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"state":"requires_action"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"background":[],"state":"requires_action"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"agent_1","subject":{"toolCall":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_task"}},"content":[],"kind":"edit","locations":[{"path":"<cwd>/x.ts"}],"name":"Edit","rawInput":{"file_path":"<cwd>/x.ts","new_string":"b","old_string":"a"},"title":"Edit x.ts","toolCallId":"toolu_sub_edit"},"type":"tool_call"},"title":"Edit x.ts"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"state":"running"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"rawOutput":"The file has been updated.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_sub_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"content":[{"changes":[{"fileType":"text","operation":"modify","path":"<cwd>/x.ts"}],"patch":{"format":"git_patch","text":"diff --git <cwd>/x.ts <cwd>/x.ts\n--- <cwd>/x.ts\n+++ <cwd>/x.ts\n@@ -1 +1 @@\n-a\n+b\n"},"type":"diff"}],"locations":[{"line":1,"path":"<cwd>/x.ts"}],"sessionUpdate":"tool_call_update","toolCallId":"toolu_sub_edit"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_task"}},"content":{"text":"Foun","type":"text"},"messageId":"msg_sub_2","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_task"}},"content":{"text":"d it.","type":"text"},"messageId":"msg_sub_2","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"The parser is in x.ts.","type":"text"}],"messageId":"toolu_task:reply","recipientSessionId":"<session>","senderSessionId":"agent_1","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_1","sessionUpdate":"subagent_update","state":{"background":[],"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_1","update":{"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"Explore","sessionId":"agent_t","sessionUpdate":"subagent_update","state":{"state":"running"},"title":"Summarize"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"capabilities":{"cancel":{}},"description":"Explore","sessionId":"agent_t","sessionUpdate":"subagent_update","state":{"background":[],"state":"running"},"title":"Summarize"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Summarize the repo","type":"text"}],"messageId":"toolu_transcript","recipientMessageId":"toolu_transcript","recipientSessionId":"agent_t","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"content":[{"text":"Summarize the repo","type":"text"}],"messageId":"toolu_transcript","recipientSessionId":"agent_t","senderMessageId":"toolu_transcript","senderSessionId":"<session>","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"_meta":{"claudeCode":{"parentToolUseId":"toolu_transcript"}},"configOptions":[{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","name":"Model","options":[{"name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionUpdate":"config_option_update"}}}
|
||||
@@ -18,7 +18,7 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"rawInput":{"pattern":"*"},"sessionUpdate":"tool_call_update","title":"Find `*`","toolCallId":"toolu_transcript_glob"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"content":[{"content":{"text":"a\nb","type":"text"},"type":"content"}],"rawOutput":"a\nb","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_transcript_glob"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"Two packages.","type":"text"}],"messageId":"toolu_transcript:reply","recipientSessionId":"<session>","senderSessionId":"agent_t","sessionUpdate":"session_message"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_t","sessionUpdate":"subagent_update","state":{"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionId":"agent_t","sessionUpdate":"subagent_update","state":{"background":[],"state":"idle","stopReason":"end_turn"}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"agent_t","update":{"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"plan":{"entries":[{"content":"Write tests","priority":"medium","status":"pending"}],"planId":"plan","type":"items"},"sessionUpdate":"plan_update"}}}
|
||||
@@ -13,13 +13,13 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"plan":{"entries":[{"content":"Write tests","priority":"medium","status":"completed"}],"planId":"plan","type":"items"},"sessionUpdate":"plan_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"plan":{"entries":[{"content":"Write tests","priority":"medium","status":"completed"}],"planId":"plan","type":"items"},"sessionUpdate":"plan_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 2","type":"text"}],"messageId":"<id-2>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-2>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"All ","type":"text"},"messageId":"msg_follow","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"done.","type":"text"},"messageId":"msg_follow","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"other","name":"TaskOutput","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"TaskOutput","toolCallId":"toolu_out"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"task_id":"bash_1"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_out"}}}
|
||||
@@ -14,4 +14,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"task_id":"bash_1"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_stop"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"Successfully stopped task: bash_1","type":"text"},"type":"content"}],"rawOutput":"Successfully stopped task: bash_1","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_stop"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"Let me thin","type":"text"},"messageId":"msg_text","sessionUpdate":"agent_thought_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"k about it.","type":"text"},"messageId":"msg_text","sessionUpdate":"agent_thought_chunk"}}}
|
||||
@@ -10,4 +10,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":{"text":"he answer.","type":"text"},"messageId":"msg_text","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"plan":{"entries":[{"content":"Writing tests","priority":"medium","status":"in_progress"},{"content":"Ship","priority":"medium","status":"pending"}],"planId":"plan","type":"items"},"sessionUpdate":"plan_update"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"terminal_update","terminalId":"toolu_slow"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"terminalId":"toolu_slow","type":"terminal"}],"kind":"execute","name":"Bash","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Terminal","toolCallId":"toolu_slow"}}}
|
||||
@@ -16,4 +16,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"exitStatus":{"exitCode":0},"sessionUpdate":"terminal_update","terminalId":"toolu_slow"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_slow"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"fetch","name":"WebFetch","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Fetch","toolCallId":"toolu_fetch"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"url":"https://example.com"},"sessionUpdate":"tool_call_update","title":"Fetch https://example.com","toolCallId":"toolu_fetch"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"Summarize the page","type":"text"},"type":"content"}],"rawInput":{"prompt":"Summarize the page","url":"https://example.com"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_fetch"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"allow_always","name":"Yes, and don't ask again for example.com","optionId":"allow-with-updates"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"content":{"text":"Summarize the page","type":"text"},"type":"content"}],"kind":"fetch","name":"WebFetch","rawInput":{"prompt":"Summarize the page","url":"https://example.com"},"title":"Fetch https://example.com","toolCallId":"toolu_fetch"},"type":"tool_call"},"title":"Fetch https://example.com"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"The page is an example.","type":"text"},"type":"content"}],"rawOutput":"The page is an example.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_fetch"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"fetch","name":"WebSearch","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Web search","toolCallId":"toolu_search"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"query":"acp protocol"},"sessionUpdate":"tool_call_update","title":"Search \"acp protocol\"","toolCallId":"toolu_search"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"content":{"text":"ACP (https://agentclientprotocol.com)\nA summary.","type":"text"},"type":"content"}],"rawOutput":"Web search results for query: \"acp protocol\"\n\nLinks: [...]","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_search"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"edit","locations":[],"name":"Write","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Preparing file…","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"locations":[{"path":"<cwd>/old.ts"}],"rawInput":{"file_path":"<cwd>/old.ts"},"sessionUpdate":"tool_call_update","title":"Write old.ts","toolCallId":"toolu_write"}}}
|
||||
@@ -12,4 +12,4 @@
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawOutput":"The file <cwd>/old.ts has been updated successfully.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"locations":[{"line":1,"path":"<cwd>/old.ts"}],"sessionUpdate":"tool_call_update","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{"kind":"response","method":"initialize","payload":{"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"providers":{},"session":{"additionalDirectories":{},"delete":{},"fork":{},"mcp":{"http":{},"stdio":{}},"prompt":{"embeddedContext":{},"image":{}},"systemPrompt":{"mode":{"override":{}}}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"response","method":"session/new","payload":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp","type":"command"}],"configOptions":[{"category":"mode","configId":"mode","currentValue":"auto","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
|
||||
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[],"kind":"edit","locations":[],"name":"Write","rawInput":{},"sessionUpdate":"tool_call_update","status":"pending","title":"Preparing file…","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"locations":[{"path":"<cwd>/new.ts"}],"rawInput":{"file_path":"<cwd>/new.ts"},"sessionUpdate":"tool_call_update","title":"Write new.ts","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"sessionUpdate":"usage_update","size":200000,"used":3}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawInput":{"content":"export const x = 1;\n","file_path":"<cwd>/new.ts"},"sessionUpdate":"tool_call_update","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"changes":[{"fileType":"text","operation":"add","path":"<cwd>/new.ts"}],"patch":{"format":"git_patch","text":"diff --git <cwd>/new.ts <cwd>/new.ts\nnew file mode 100644\n--- /dev/null\n+++ <cwd>/new.ts\n@@ -0,0 +1 @@\n+export const x = 1;\n"},"type":"diff"}],"sessionUpdate":"tool_call_update","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"requires_action"}}}
|
||||
{"kind":"request","method":"session/request_permission","payload":{"options":[{"kind":"allow_once","name":"Yes","optionId":"allow-once"},{"kind":"reject_once","name":"No","optionId":"reject"}],"sessionId":"<session>","subject":{"toolCall":{"content":[{"changes":[{"fileType":"text","operation":"add","path":"<cwd>/new.ts"}],"patch":{"format":"git_patch","text":"diff --git <cwd>/new.ts <cwd>/new.ts\nnew file mode 100644\n--- /dev/null\n+++ <cwd>/new.ts\n@@ -0,0 +1 @@\n+export const x = 1;\n"},"type":"diff"}],"kind":"edit","locations":[{"path":"<cwd>/new.ts"}],"name":"Write","rawInput":{"content":"export const x = 1;\n","file_path":"<cwd>/new.ts"},"title":"Write new.ts","toolCallId":"toolu_write"},"type":"tool_call"},"title":"Write new.ts"}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"background":[],"sessionUpdate":"state_update","state":"running"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"rawOutput":"File created successfully at: <cwd>/new.ts","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_write"}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"_claude/model":"claude-sonnet-4-6"},"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":2}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"background":[],"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}
|
||||
|
||||
@@ -500,21 +500,17 @@ export async function runScenarioV2(
|
||||
const idles: unknown[] = [];
|
||||
const failures: string[] = [];
|
||||
|
||||
const each = (message: v2.AnyWireMessage) =>
|
||||
(Array.isArray(message) ? message : [message]) as Record<string, any>[];
|
||||
const toAgent = new TransformStream<v2.AnyWireMessage, v2.AnyWireMessage>({
|
||||
const toAgent = new TransformStream<v2.AnyMessage, v2.AnyMessage>({
|
||||
transform(message, controller) {
|
||||
for (const m of each(message)) {
|
||||
if ("method" in m && "id" in m) methodsOfClientRequests.set(m.id, m.method);
|
||||
if ("method" in message && "id" in message && message.id !== null) {
|
||||
methodsOfClientRequests.set(message.id, message.method);
|
||||
}
|
||||
controller.enqueue(message);
|
||||
},
|
||||
});
|
||||
const toClient = new TransformStream<v2.AnyWireMessage, v2.AnyWireMessage>({
|
||||
const toClient = new TransformStream<v2.AnyMessage, v2.AnyMessage>({
|
||||
transform(message, controller) {
|
||||
for (const m of each(message)) {
|
||||
if (recording) raw.push(wireRecord(m, methodsOfClientRequests));
|
||||
}
|
||||
if (recording) raw.push(wireRecord(message, methodsOfClientRequests));
|
||||
controller.enqueue(message);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolName":"Edit"}},"rawOutput":"The file <cwd>/src/app.ts has been updated successfully.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_r_edit"}}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolName":"Task"}},"content":[{"content":{"text":"Report.","type":"text"},"type":"content"}],"rawOutput":"Report.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_r_task"}}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"content":{"text":"Fixed.","type":"text"},"messageId":"msg_r2","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"loadSession","payload":{"configOptions":[{"category":"mode","currentValue":"default","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"default"},"sessionId":"<session>"}}
|
||||
{"kind":"loadSession","payload":{"configOptions":[{"category":"mode","currentValue":"auto","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"auto"},"sessionId":"<session>"}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"availableCommands":[],"sessionUpdate":"available_commands_update"}}}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{"kind":"initialize","payload":{"_meta":{"goal":{"actions":["set","clear"],"controlMethod":"_session/goal","version":1},"jetbrains":{"air":{"capabilities":["sessionFailure","agentFileChangeReport","nativeSubagentSessions","asyncTasks","recommendedValue"],"version":1}},"steering":{"supported":true}},"agentCapabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"auth":{"logout":{}},"loadSession":true,"mcpCapabilities":{"http":true,"sse":true},"promptCapabilities":{"embeddedContext":true,"image":true},"providers":{},"sessionCapabilities":{"additionalDirectories":{},"close":{},"delete":{},"fork":{},"list":{},"resume":{},"subagents":{}}},"agentInfo":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"authMethods":[],"protocolVersion":1}}
|
||||
{"kind":"newSession","payload":{"configOptions":[{"category":"mode","currentValue":"default","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"default"},"sessionId":"<session>"}}
|
||||
{"kind":"newSession","payload":{"configOptions":[{"category":"mode","currentValue":"auto","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"auto"},"sessionId":"<session>"}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"availableCommands":[],"sessionUpdate":"available_commands_update"}}}
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolName":"Edit"}},"rawOutput":"The file <cwd>/src/app.ts has been updated successfully.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_r_edit"}}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolName":"Task"}},"content":[{"content":{"text":"Report.","type":"text"},"type":"content"}],"rawOutput":"Report.","sessionUpdate":"tool_call_update","status":"completed","toolCallId":"toolu_r_task"}}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"content":{"text":"Fixed.","type":"text"},"messageId":"msg_r2","sessionUpdate":"agent_message_chunk"}}}
|
||||
{"kind":"loadSession","payload":{"configOptions":[{"category":"mode","currentValue":"default","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"default"},"sessionId":"<session>"}}
|
||||
{"kind":"loadSession","payload":{"configOptions":[{"category":"mode","currentValue":"auto","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"auto"},"sessionId":"<session>"}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"availableCommands":[],"sessionUpdate":"available_commands_update"}}}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{"kind":"initialize","payload":{"_meta":{"goal":{"actions":["set","clear"],"controlMethod":"_session/goal","version":1},"jetbrains":{"air":{"capabilities":["sessionFailure","agentFileChangeReport","nativeSubagentSessions","asyncTasks","recommendedValue"],"version":1}},"steering":{"supported":true}},"agentCapabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}},"auth":{"logout":{}},"loadSession":true,"mcpCapabilities":{"http":true,"sse":true},"promptCapabilities":{"embeddedContext":true,"image":true},"providers":{},"sessionCapabilities":{"additionalDirectories":{},"close":{},"delete":{},"fork":{},"list":{},"resume":{},"subagents":{}}},"agentInfo":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"authMethods":[{"_meta":{"terminal-auth":{"args":["<argv>","--cli","auth","login","--claudeai"],"command":"<executable>","label":"Claude Login"}},"args":["--cli","auth","login","--claudeai"],"description":"Use Claude subscription ","id":"claude-ai-login","name":"Claude Subscription","type":"terminal"},{"_meta":{"terminal-auth":{"args":["<argv>","--cli","auth","login","--console"],"command":"<executable>","label":"Anthropic Console Login"}},"args":["--cli","auth","login","--console"],"description":"Use Anthropic Console (API usage billing)","id":"console-login","name":"Anthropic Console","type":"terminal"}],"protocolVersion":1}}
|
||||
{"kind":"newSession","payload":{"configOptions":[{"category":"mode","currentValue":"default","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"default"},"sessionId":"<session>"}}
|
||||
{"kind":"newSession","payload":{"configOptions":[{"category":"mode","currentValue":"auto","description":"Session permission mode","id":"mode","name":"Mode","options":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","name":"Manual","value":"default"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","id":"model","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"modes":{"availableModes":[{"_meta":{"kind":"standard"},"description":"Always ask before making changes","id":"default","name":"Manual"},{"_meta":{"kind":"standard"},"description":"Automatically accept all file edits","id":"acceptEdits","name":"Accept edits"},{"_meta":{"kind":"plan"},"description":"Create a plan before making changes","id":"plan","name":"Plan"},{"_meta":{"kind":"auto_review"},"description":"Claude handles permission decisions","id":"auto","name":"Auto"},{"_meta":{"kind":"full_access"},"description":"Accepts all permissions","id":"bypassPermissions","name":"Bypass permissions"}],"currentModeId":"auto"},"sessionId":"<session>"}}
|
||||
{"kind":"sessionUpdate","payload":{"sessionId":"<session>","update":{"availableCommands":[],"sessionUpdate":"available_commands_update"}}}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
24
src/tests/agent-command.test.ts
Normal file
24
src/tests/agent-command.test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { agentCommand } from "../agent-command.js";
|
||||
|
||||
describe("agentCommand", () => {
|
||||
it.each([
|
||||
{
|
||||
runtime: "Node",
|
||||
argv: ["/usr/bin/node", "/opt/acp/dist/index.js", "--hide-claude-auth"],
|
||||
args: ["/opt/acp/dist/index.js", "--hide-claude-auth"],
|
||||
},
|
||||
{
|
||||
runtime: "a compiled executable",
|
||||
argv: ["bun", "/$bunfs/root/claude-agent-acp", "--hide-claude-auth"],
|
||||
args: ["--hide-claude-auth"],
|
||||
},
|
||||
{
|
||||
runtime: "a compiled Windows executable",
|
||||
argv: ["bun", "B:\\~BUN\\root\\claude-agent-acp.exe", "--hide-claude-auth"],
|
||||
args: ["--hide-claude-auth"],
|
||||
},
|
||||
])("reruns $runtime with its own flags", ({ argv, args }) => {
|
||||
expect(agentCommand(argv)).toEqual({ command: process.execPath, args });
|
||||
});
|
||||
});
|
||||
@@ -1076,6 +1076,62 @@ describe("authorization", () => {
|
||||
expect([...respawned.sessionFailureState.active.values()]).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("restores the user's choices on the respawned query, then a choice sent meanwhile", async () => {
|
||||
const [agent, updates] = createRecordingAgent(true);
|
||||
hideClaudeAuth();
|
||||
const effortModels = ["sonnet", "opus"].map((value) => ({
|
||||
value,
|
||||
displayName: value,
|
||||
description: "",
|
||||
supportsAutoMode: true,
|
||||
supportsEffort: true,
|
||||
supportedEffortLevels: ["low", "medium", "high"],
|
||||
}));
|
||||
const scripts = [[[signOutResult()]], [[successResult()]]];
|
||||
let releaseRespawn!: () => void;
|
||||
const respawnGate = new Promise<void>((resolve) => (releaseRespawn = resolve));
|
||||
const queries: any[] = [];
|
||||
mockQuery.mockImplementation((args: any) => {
|
||||
const query = scriptedQuery(args, SIGNED_IN_WITH_KEY, scripts[queries.length] ?? []);
|
||||
const gate = queries.length > 0 ? respawnGate : undefined;
|
||||
query.initializationResult = async () => {
|
||||
await gate;
|
||||
return { models: effortModels, account: SIGNED_IN_WITH_KEY };
|
||||
};
|
||||
query.setModel = vi.fn(async () => {});
|
||||
query.applyFlagSettings = vi.fn(async () => {});
|
||||
queries.push(query);
|
||||
return query;
|
||||
});
|
||||
const { sessionId } = await agent.newSession(newSessionParams());
|
||||
await agent.setSessionConfigOption({ sessionId, configId: "model", value: "opus" });
|
||||
await agent.setSessionConfigOption({ sessionId, configId: "effort", value: "high" });
|
||||
await expect(agent.prompt(promptParams(sessionId))).rejects.toMatchObject({
|
||||
code: AUTH_REQUIRED_CODE,
|
||||
});
|
||||
|
||||
const turn = agent.prompt(promptParams(sessionId));
|
||||
await vi.waitFor(() => expect(queries).toHaveLength(2));
|
||||
const choice = agent.setSessionConfigOption({
|
||||
sessionId,
|
||||
configId: "effort",
|
||||
value: "low",
|
||||
});
|
||||
releaseRespawn();
|
||||
await expect(turn).resolves.toMatchObject({ stopReason: "end_turn" });
|
||||
await choice;
|
||||
|
||||
expect(queries[1].setModel).toHaveBeenCalledWith("opus");
|
||||
expect(queries[1].applyFlagSettings.mock.calls).toEqual([
|
||||
[{ effortLevel: "high" }],
|
||||
[{ effortLevel: "low" }],
|
||||
]);
|
||||
expect(updates).toContainEqual({
|
||||
sessionId,
|
||||
update: expect.objectContaining({ sessionUpdate: "config_option_update" }),
|
||||
});
|
||||
});
|
||||
|
||||
it("refuses with the plain error and no second row when still signed out", async () => {
|
||||
const [agent, updates] = createRecordingAgent(true);
|
||||
hideClaudeAuth();
|
||||
|
||||
129
src/tests/background-output.test.ts
Normal file
129
src/tests/background-output.test.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { appendFile, mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
BACKGROUND_OUTPUT_MAX_BACKLOG_BYTES,
|
||||
BACKGROUND_OUTPUT_READ_BYTES,
|
||||
type BackgroundOutput,
|
||||
BackgroundOutputTail,
|
||||
} from "../background-output.js";
|
||||
|
||||
describe("BackgroundOutputTail", () => {
|
||||
let dir: string;
|
||||
let file: string;
|
||||
let published: BackgroundOutput[];
|
||||
let tail: BackgroundOutputTail | undefined;
|
||||
const follow = () =>
|
||||
(tail = new BackgroundOutputTail(file, async (output) => void published.push(output)));
|
||||
|
||||
beforeEach(async () => {
|
||||
dir = await mkdtemp(path.join(tmpdir(), "background-output-"));
|
||||
file = path.join(dir, "bg1.output");
|
||||
published = [];
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
tail?.stop();
|
||||
await rm(dir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it("replaces the terminal's output with the file's first text, then appends what the file adds", async () => {
|
||||
await writeFile(file, "building\n");
|
||||
follow();
|
||||
await vi.waitFor(() => expect(published).toHaveLength(1), { timeout: 2000 });
|
||||
await appendFile(file, "done\n");
|
||||
await vi.waitFor(() => expect(published).toHaveLength(2), { timeout: 2000 });
|
||||
|
||||
expect(published).toEqual([
|
||||
{ text: "building\n", replaces: true },
|
||||
{ text: "done\n", replaces: false },
|
||||
]);
|
||||
});
|
||||
|
||||
it("waits for a file that does not exist yet", async () => {
|
||||
follow();
|
||||
await new Promise((resolve) => setTimeout(resolve, 700));
|
||||
expect(published).toEqual([]);
|
||||
|
||||
await writeFile(file, "started\n");
|
||||
await vi.waitFor(() => expect(published).toHaveLength(1), { timeout: 2000 });
|
||||
expect(published[0]).toEqual({ text: "started\n", replaces: true });
|
||||
});
|
||||
|
||||
it("holds a character that a read splits until its last byte is written", async () => {
|
||||
const check = Buffer.from("✓", "utf8");
|
||||
await writeFile(file, check.subarray(0, 1));
|
||||
follow();
|
||||
await new Promise((resolve) => setTimeout(resolve, 700));
|
||||
expect(published).toEqual([]);
|
||||
|
||||
await appendFile(file, check.subarray(1));
|
||||
await tail!.finish();
|
||||
expect(published).toEqual([{ text: "✓", replaces: true }]);
|
||||
});
|
||||
|
||||
it("reads the rest of the file on finish, and nothing after", async () => {
|
||||
await writeFile(file, "a");
|
||||
follow();
|
||||
await appendFile(file, "b");
|
||||
await tail!.finish();
|
||||
await appendFile(file, "c");
|
||||
await new Promise((resolve) => setTimeout(resolve, 700));
|
||||
|
||||
expect(published.map((output) => output.text).join("")).toBe("ab");
|
||||
});
|
||||
|
||||
it("sends at most the backlog, read by read, from the file's last bytes as a snapshot", async () => {
|
||||
// More than the backlog, written faster than the polls read it.
|
||||
const skipped = "x".repeat(BACKGROUND_OUTPUT_MAX_BACKLOG_BYTES);
|
||||
const kept = "y".repeat(BACKGROUND_OUTPUT_MAX_BACKLOG_BYTES - 4) + "end\n";
|
||||
await writeFile(file, skipped + kept);
|
||||
follow();
|
||||
await tail!.finish();
|
||||
|
||||
expect(published.map((output) => output.text).join("")).toBe(kept);
|
||||
expect(published[0].replaces).toBe(true);
|
||||
expect(published.slice(1).every((output) => !output.replaces)).toBe(true);
|
||||
expect(
|
||||
published.every((output) => Buffer.byteLength(output.text) <= BACKGROUND_OUTPUT_READ_BYTES),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("starts over with a snapshot when the file shrinks", async () => {
|
||||
await writeFile(file, "old output\n");
|
||||
follow();
|
||||
await vi.waitFor(() => expect(published).toHaveLength(1), { timeout: 2000 });
|
||||
await writeFile(file, "new\n");
|
||||
await tail!.finish();
|
||||
|
||||
expect(published).toEqual([
|
||||
{ text: "old output\n", replaces: true },
|
||||
{ text: "new\n", replaces: true },
|
||||
]);
|
||||
});
|
||||
|
||||
it("replaces the placeholder with an empty output when the command wrote nothing", async () => {
|
||||
await writeFile(file, "");
|
||||
follow();
|
||||
await tail!.finish();
|
||||
|
||||
expect(published).toEqual([{ text: "", replaces: true }]);
|
||||
});
|
||||
|
||||
it("publishes nothing on finish when the file never appeared", async () => {
|
||||
follow();
|
||||
await tail!.finish();
|
||||
|
||||
expect(published).toEqual([]);
|
||||
});
|
||||
|
||||
it("reads nothing after stop", async () => {
|
||||
follow();
|
||||
tail!.stop();
|
||||
await writeFile(file, "late\n");
|
||||
await new Promise((resolve) => setTimeout(resolve, 700));
|
||||
|
||||
expect(published).toEqual([]);
|
||||
});
|
||||
});
|
||||
57
src/tests/claude-cli.test.ts
Normal file
57
src/tests/claude-cli.test.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
// Fresh module state per test: the bundled CLI directory is process-wide.
|
||||
async function load() {
|
||||
vi.resetModules();
|
||||
return import("../claude-cli.js");
|
||||
}
|
||||
|
||||
describe("claudeCliPath", () => {
|
||||
let dir: string;
|
||||
|
||||
beforeEach(() => {
|
||||
dir = mkdtempSync(join(tmpdir(), "claude-cli-"));
|
||||
vi.stubEnv("CLAUDE_CODE_EXECUTABLE", "");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
const cliFileName = process.platform === "win32" ? "claude.exe" : "claude";
|
||||
|
||||
it("prefers CLAUDE_CODE_EXECUTABLE over the bundled CLI", async () => {
|
||||
const { claudeCliPath, useBundledClaudeCli } = await load();
|
||||
writeFileSync(join(dir, cliFileName), "");
|
||||
useBundledClaudeCli(dir);
|
||||
vi.stubEnv("CLAUDE_CODE_EXECUTABLE", "/opt/claude");
|
||||
|
||||
expect(await claudeCliPath()).toBe("/opt/claude");
|
||||
});
|
||||
|
||||
it("returns the CLI next to the executable", async () => {
|
||||
const { claudeCliPath, useBundledClaudeCli } = await load();
|
||||
writeFileSync(join(dir, cliFileName), "");
|
||||
useBundledClaudeCli(dir);
|
||||
|
||||
expect(await claudeCliPath()).toBe(join(dir, cliFileName));
|
||||
});
|
||||
|
||||
it("throws when the CLI is missing next to the executable", async () => {
|
||||
const { claudeCliPath, useBundledClaudeCli } = await load();
|
||||
useBundledClaudeCli(dir);
|
||||
|
||||
await expect(claudeCliPath()).rejects.toThrow(
|
||||
`The Claude CLI is missing: expected ${join(dir, cliFileName)}. Keep ${cliFileName} from the release archive`,
|
||||
);
|
||||
});
|
||||
|
||||
it.skipIf(!process.env.RUN_INTEGRATION_TESTS)("finds the installed CLI", async () => {
|
||||
const { claudeCliPath } = await load();
|
||||
expect(await claudeCliPath()).toMatch(/@anthropic-ai\/claude-agent-sdk-[^/]+\/claude(\.exe)?$/);
|
||||
});
|
||||
});
|
||||
@@ -28,6 +28,7 @@ function testSession(overrides: Partial<TestSession> = {}): TestSession {
|
||||
},
|
||||
},
|
||||
models: { currentModelId: "default" },
|
||||
contextWindowSize: 200_000,
|
||||
configOptions: [],
|
||||
currentAgent: "default",
|
||||
fastModeEnabled: false,
|
||||
@@ -464,6 +465,7 @@ describe("ExitPlanCoordinator", () => {
|
||||
expect(order).toEqual([
|
||||
"current_mode_update",
|
||||
"config_option_update",
|
||||
"usage_update",
|
||||
...(supportsPlanOperations
|
||||
? [
|
||||
"plan_update " +
|
||||
@@ -476,6 +478,10 @@ describe("ExitPlanCoordinator", () => {
|
||||
: []),
|
||||
"continuation",
|
||||
]);
|
||||
expect(host.sessionUpdate).toHaveBeenCalledWith({
|
||||
sessionId: "public-session",
|
||||
update: { sessionUpdate: "usage_update", used: 0, size: 200_000 },
|
||||
});
|
||||
if (airClient) {
|
||||
expect(host.sessionUpdate).toHaveBeenCalledWith({
|
||||
sessionId: "public-session",
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
ContextCompactionLifecycle,
|
||||
clientSupportsCompactionUpdates,
|
||||
compactionSummaryText,
|
||||
contextCompactionMetadataFromBoundary,
|
||||
isCompactSummaryMessage,
|
||||
} from "../context-compaction.js";
|
||||
|
||||
@@ -635,3 +636,20 @@ describe("ContextCompactionLifecycle (tool_call)", () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("contextCompactionMetadataFromBoundary", () => {
|
||||
/** An adapter-sent compaction is `idle` only when the CLI calls it manual; the CLI's own auto trigger stays `automatic`. */
|
||||
it.each([
|
||||
{ cli: "manual", idleCompaction: false, expected: "manual" },
|
||||
{ cli: "manual", idleCompaction: true, expected: "idle" },
|
||||
{ cli: "auto", idleCompaction: true, expected: "automatic" },
|
||||
] as const)(
|
||||
"reports $expected for a $cli boundary (idleCompaction: $idleCompaction)",
|
||||
({ cli, idleCompaction, expected }) => {
|
||||
expect(
|
||||
contextCompactionMetadataFromBoundary({ trigger: cli, pre_tokens: 1 }, { idleCompaction })
|
||||
.trigger,
|
||||
).toBe(expected);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -10,6 +10,7 @@ import type { AcpClient, ClaudeAcpAgent as ClaudeAcpAgentType } from "../acp-age
|
||||
import type { AcpSessionNotification } from "../acp-subagents.js";
|
||||
import { ALLOW_BYPASS } from "../permissions/modes.js";
|
||||
import { NativeSubagentRuntime } from "../native-subagents.js";
|
||||
import { startupFailure } from "./helpers.js";
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
@@ -321,6 +322,61 @@ describe("createSession options merging", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("reports a worktree child's cwd from its SubagentStart hook, and none for a child in the session's cwd", async () => {
|
||||
const updates: AcpSessionNotification[] = [];
|
||||
const client = createMockClient();
|
||||
client.sessionUpdate = async (notification) => {
|
||||
updates.push(notification);
|
||||
};
|
||||
const observedAgent = new ClaudeAcpAgent(client);
|
||||
await observedAgent.initialize({ protocolVersion: 1, clientCapabilities: { subagents: {} } });
|
||||
const { sessionId } = await observedAgent.newSession({ cwd: process.cwd(), mcpServers: [] });
|
||||
const session = observedAgent.sessions[sessionId]!;
|
||||
const runtime = (session.nativeSubagentRuntime = new NativeSubagentRuntime(
|
||||
"rfd",
|
||||
sessionId,
|
||||
session,
|
||||
(notification) => client.sessionUpdate(notification),
|
||||
{ log: () => {} },
|
||||
));
|
||||
const subagentStart = async (agentId: string, cwd: string) => {
|
||||
const matcher = capturedOptions!.hooks!.SubagentStart!.find((matcher) => !matcher.matcher);
|
||||
for (const hook of matcher!.hooks) {
|
||||
await hook(
|
||||
{
|
||||
hook_event_name: "SubagentStart",
|
||||
session_id: sessionId,
|
||||
cwd,
|
||||
transcript_path: "/tmp/transcript",
|
||||
agent_id: agentId,
|
||||
agent_type: "general-purpose",
|
||||
},
|
||||
undefined,
|
||||
{ signal: new AbortController().signal },
|
||||
);
|
||||
}
|
||||
};
|
||||
const worktree = path.join(process.cwd(), ".claude", "worktrees", "agent-isolated");
|
||||
await subagentStart("isolated", worktree);
|
||||
await subagentStart("shared", process.cwd());
|
||||
await runtime.taskStarted(
|
||||
{ taskId: "isolated", subagentType: "general-purpose" },
|
||||
async () => {},
|
||||
);
|
||||
await runtime.taskStarted(
|
||||
{ taskId: "shared", subagentType: "general-purpose" },
|
||||
async () => {},
|
||||
);
|
||||
const announcements = updates.flatMap(({ update }) =>
|
||||
update.sessionUpdate === "subagent_update" ? [update] : [],
|
||||
);
|
||||
expect(announcements).toMatchObject([
|
||||
{ sessionId: "isolated", cwd: worktree },
|
||||
{ sessionId: "shared" },
|
||||
]);
|
||||
expect(announcements[1]).not.toHaveProperty("cwd");
|
||||
});
|
||||
|
||||
it("reports an AIR child's model switch under its current generation", async () => {
|
||||
const updates: AcpSessionNotification[] = [];
|
||||
const client = createMockClient();
|
||||
@@ -1346,6 +1402,36 @@ describe("createSession options merging", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("startup failures", () => {
|
||||
it("asks Claude Code to report why it could not start", async () => {
|
||||
await agent.newSession({ cwd: process.cwd(), mcpServers: [] });
|
||||
expect(capturedOptions?.env?.CLAUDE_CODE_STARTUP_FAILURE_RESULTS).toBe("1");
|
||||
});
|
||||
|
||||
it.each([
|
||||
["proxy_invalid", RequestError.internalError().code, "Internal error"],
|
||||
["gateway_signin_required", RequestError.authRequired().code, "Authentication required"],
|
||||
["org_pin_mismatch", RequestError.authRequired().code, "Authentication required"],
|
||||
["org_config_refused", RequestError.authRequired().code, "Authentication required"],
|
||||
["cwd_unavailable", RequestError.invalidParams().code, "Invalid params"],
|
||||
])("rejects with %s as code %i", async (reason, code, prefix) => {
|
||||
initError = startupFailure(reason, "Fix the setting and restart Claude Code.");
|
||||
await expect(agent.newSession({ cwd: process.cwd(), mcpServers: [] })).rejects.toMatchObject({
|
||||
code,
|
||||
message: `${prefix}: Fix the setting and restart Claude Code.`,
|
||||
data: { startupFailureReason: reason },
|
||||
});
|
||||
expect(closeSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("passes on an exit error that names no reason", async () => {
|
||||
initError = new Error("Claude Code process exited with code 1. stderr: boom");
|
||||
await expect(agent.newSession({ cwd: process.cwd(), mcpServers: [] })).rejects.toBe(
|
||||
initError,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("elicitation", () => {
|
||||
it("keeps AskUserQuestion disabled and omits callbacks without elicitation capability", async () => {
|
||||
await agent.initialize({ protocolVersion: 1, clientCapabilities: {} });
|
||||
|
||||
@@ -466,6 +466,12 @@ describe("ACP v2 diffs", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps a Windows path native in a git patch, so it matches the changes entry", () => {
|
||||
expect(gitPatchText("C:\\work\\App.ts", "update", [hunk], "absolute")).toContain(
|
||||
'diff --git "C:\\\\work\\\\App.ts" "C:\\\\work\\\\App.ts"\n--- "C:\\\\work\\\\App.ts"\n+++ "C:\\\\work\\\\App.ts"\n',
|
||||
);
|
||||
});
|
||||
|
||||
it("shows no diff at tool use, where the input holds a snippet or no old text", () => {
|
||||
const renderer = new AcpToolCallRenderer(v2);
|
||||
const edit = { file_path: "/work/a.ts", old_string: "old", new_string: "new" };
|
||||
|
||||
@@ -60,6 +60,19 @@ describe("mcpElicitationToCreateRequest", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("adds an empty properties map when the MCP schema has none", () => {
|
||||
const request: ElicitationRequest = {
|
||||
serverName: "server",
|
||||
message: "Confirm?",
|
||||
mode: "form",
|
||||
requestedSchema: { type: "object" },
|
||||
};
|
||||
|
||||
const result = mcpElicitationToCreateRequest(request, SESSION_ID);
|
||||
|
||||
expect(result).toMatchObject({ requestedSchema: { type: "object", properties: {} } });
|
||||
});
|
||||
|
||||
it("maps a url-mode request and preserves the elicitation id", () => {
|
||||
const request: ElicitationRequest = {
|
||||
serverName: "server",
|
||||
@@ -119,6 +132,31 @@ describe("createElicitationResponseToElicitResult", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("forwards content values that only v2 allows, such as an object", () => {
|
||||
// ACP v2 lets an elicitation value be any JSON value. The MCP server checks
|
||||
// the content against its own schema, so none of it is dropped here.
|
||||
const content = {
|
||||
name: "Ada",
|
||||
address: { city: "London" },
|
||||
tags: ["a", 1, null],
|
||||
};
|
||||
const response = { action: "accept", content } as unknown as CreateElicitationResponse;
|
||||
expect(createElicitationResponseToElicitResult(response)).toEqual({
|
||||
action: "accept",
|
||||
content,
|
||||
});
|
||||
});
|
||||
|
||||
it("maps accept content that is no JSON object to an empty object", () => {
|
||||
for (const content of [null, "Ada", ["Ada"]]) {
|
||||
const response = { action: "accept", content } as unknown as CreateElicitationResponse;
|
||||
expect(createElicitationResponseToElicitResult(response)).toEqual({
|
||||
action: "accept",
|
||||
content: {},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("maps decline and cancel", () => {
|
||||
expect(
|
||||
createElicitationResponseToElicitResult({ action: "decline" } as CreateElicitationResponse),
|
||||
@@ -343,6 +381,28 @@ describe("applyAskElicitationResponse", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("reads only string, number, and boolean picks from v2 content", () => {
|
||||
// A v2 client may send an object or a mixed array. Such values are no
|
||||
// option label, so they count as no pick instead of "[object Object]".
|
||||
const response = {
|
||||
action: "accept",
|
||||
content: {
|
||||
question_0: { label: "A" },
|
||||
question_0_custom: { text: "ignored" },
|
||||
question_1: ["X", { label: "Y" }, null, 2],
|
||||
},
|
||||
} as unknown as CreateElicitationResponse;
|
||||
|
||||
expect(applyAskElicitationResponse(response, toolInput, questions)).toEqual({
|
||||
action: "answered",
|
||||
updatedInput: {
|
||||
questions,
|
||||
metadata: { source: "test" },
|
||||
answers: { "Multi?": "X, 2" },
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("uses a multi-select question's custom answer alone when nothing is selected", () => {
|
||||
const response = {
|
||||
action: "accept",
|
||||
@@ -639,10 +699,12 @@ describe("refusalFallbackResultFromResponse", () => {
|
||||
{ action: "accept", content: { choice: "cancelled" } },
|
||||
{ action: "accept", content: {} },
|
||||
{ action: "accept", content: { choice: "something-new" } },
|
||||
{ action: "accept", content: { choice: { value: "retry_fallback" } } },
|
||||
{ action: "accept", content: { choice: ["retry_fallback"] } },
|
||||
{ action: "accept" },
|
||||
{ action: "decline" },
|
||||
{ action: "cancel" },
|
||||
] as CreateElicitationResponse[];
|
||||
] as unknown as CreateElicitationResponse[];
|
||||
for (const response of cases) {
|
||||
expect(refusalFallbackResultFromResponse(response)).toBe("cancelled");
|
||||
}
|
||||
|
||||
@@ -256,6 +256,31 @@ describe("setSessionConfigOption Fast mode toggle", () => {
|
||||
expect(response.configOptions).toContainEqual(createFastModeConfigOption(true, false));
|
||||
});
|
||||
|
||||
it("rejects a value whose type differs from the option's advertised type", async () => {
|
||||
// Advertised as `type: "boolean"`: "on" is not a boolean.
|
||||
const booleanClient = setup({ useBooleanOption: true });
|
||||
await expect(
|
||||
booleanClient.agent.setSessionConfigOption({
|
||||
sessionId: SESSION_ID,
|
||||
configId: FAST_MODE_CONFIG_ID,
|
||||
value: FAST_MODE_ON,
|
||||
}),
|
||||
).rejects.toMatchObject({ code: -32602 });
|
||||
expect(booleanClient.applyFlagSettings).not.toHaveBeenCalled();
|
||||
|
||||
// Advertised as an on/off select: `true` is not a string.
|
||||
const selectClient = setup({ useBooleanOption: false });
|
||||
await expect(
|
||||
selectClient.agent.setSessionConfigOption({
|
||||
sessionId: SESSION_ID,
|
||||
configId: FAST_MODE_CONFIG_ID,
|
||||
type: "boolean",
|
||||
value: true,
|
||||
}),
|
||||
).rejects.toMatchObject({ code: -32602 });
|
||||
expect(selectClient.applyFlagSettings).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not change session state when the SDK rejects the flag", async () => {
|
||||
const { agent, applyFlagSettings } = setup({ useBooleanOption: true });
|
||||
applyFlagSettings.mockRejectedValueOnce(new Error("nope"));
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
* their own vi.fn spies via `overrides`.
|
||||
*/
|
||||
|
||||
import type { ClientCapabilities, InitializeRequest } from "@agentclientprotocol/sdk/unstable";
|
||||
import {
|
||||
RequestError,
|
||||
type ClientCapabilities,
|
||||
type InitializeRequest,
|
||||
} from "@agentclientprotocol/sdk/unstable";
|
||||
|
||||
/** The context-usage report the base mock query returns. `rawMaxTokens`
|
||||
* matches the agent's DEFAULT_CONTEXT_WINDOW so window-related assertions
|
||||
@@ -41,6 +45,19 @@ export function makeMockQuery(overrides: Record<string, unknown> = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* The error `initializationResult()` rejects with when Claude Code refuses to
|
||||
* start with `CLAUDE_CODE_STARTUP_FAILURE_RESULTS` set, as SDK 0.3.316 builds
|
||||
* it from the CLI's error result (same message prefix and fields).
|
||||
*/
|
||||
export function startupFailure(reason: string, cliMessage: string): Error {
|
||||
return Object.assign(new Error(`Claude Code returned an error result: ${cliMessage}`), {
|
||||
telemetryMessage: "Claude Code returned an error result",
|
||||
errorClass: "error_result",
|
||||
startupFailureReason: reason,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Declares the client capabilities through `initialize`, as a real client
|
||||
* does. The agent reads its capability choices only there.
|
||||
@@ -51,3 +68,16 @@ export async function initializeClient(
|
||||
): Promise<void> {
|
||||
await agent.initialize({ protocolVersion: 1, clientCapabilities });
|
||||
}
|
||||
|
||||
/**
|
||||
* A request to a client that never answers it, as the SDK connection returns
|
||||
* it with `stopWaitingOnCancel`: it rejects with `-32800` once `signal`
|
||||
* aborts. The real connection also sends `$/cancel_request` then.
|
||||
*/
|
||||
export function heldRequest<T>(_params?: unknown, signal?: AbortSignal): Promise<T> {
|
||||
return new Promise<T>((_resolve, reject) => {
|
||||
const cancel = () => reject(RequestError.requestCancelled(signal?.reason));
|
||||
if (signal?.aborted) cancel();
|
||||
else signal?.addEventListener("abort", cancel, { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user