mirror of
https://github.com/agentclientprotocol/claude-agent-acp.git
synced 2026-10-27 04:30:59 +00:00
v0.81.1-preview.7
719 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
388a0f5191 |
fix(session): recreate query when configured skills change (#968)
## Summary - include normalized Claude SDK `skills` in the resumed-session fingerprint - preserve the distinct semantics of omitted, `'all'`, empty, and explicit skill selections - avoid unnecessary Query recreation for reordered or duplicate skill names - keep unrelated `_meta.claudeCode.options` fields out of the fingerprint - recreate the Query with the same native session ID when skills change - merge the latest `origin/main` so the change is validated against the current session logic and SDK 0.3.238 ## Testing - clean Linux Node 22 environment with `@anthropic-ai/claude-agent-sdk@0.3.238` - `npm run build` - `npm run lint` - `npm run check` - targeted lifecycle tests: `425 passed, 9 skipped` - full test suite: `978 passed, 27 skipped` - successful lifecycle case: `newSession(['pdf']) -> resumeSession(['docx'])` Closes #955v0.81.1-preview.7 |
||
|
|
9392c69cc6 |
fix: settle steered turns on the result that answers the steer (#1166)
Fixes #1114. ## Problem A steered turn settles only at an SDK `idle`, and only once the steer's echo has been replayed and an outcome recorded. Two ways that never happens, both from #1114: - **Missing echo.** If the CLI never replays the steered message, every idle is swallowed and `session/prompt` parks until cancel or the next prompt. - **Owed-idle debt eats the settling idle.** If the steer aborts an autonomous followup, that followup's result counts a trailing idle, but the abort folds it into the one idle that spans both cycles. The debt lane absorbs that idle and the steered turn never settles. ## Fix 1. **Exact lane: settle on the result that answers the steer.** A result whose `user_message_uuids` (falling back to `user_message_uuid`) names one of the turn's steers retires that steer's echo, even if the CLI never replayed it. Once no steer is outstanding, the turn leaves the steer lane and settles at that result through the ordinary lanes, including the subagent hold and failure lanes. It owes its trailing idle like any other settling result. No timer. 2. **Idle fallback, for producers that don't stamp results: count only a result recorded after the last echo.** Before this, the outcome of the cycle the steer interrupted (or a held turn's outcome that `steer()` moved over) made the turn look ready as soon as the echo landed. `steeredAwaitingResult` is set when an echo drains and cleared when a result is recorded. 3. **A ready steered turn takes the idle ahead of owed-idle debt.** Its outcome is final, so whichever idle arrives settles it correctly. The debt is left standing: a separate trailing idle still absorbs the idle it belongs to, and one that never comes is cleared by the existing sweep at the next `running` transition. A steered turn that isn't ready still goes through the debt lane first, so an earlier turn's late idle can never settle a steered cycle that's still running. ## Live verification (CLI 2.1.280, SDK 0.3.280) A probe with the adapter's query options (`replay-user-messages`, partial messages) steered a running turn three ways: mid-generation at `now`, mid-tool-call at `now`, and mid-tool-call at `later`. All three had the same frame order: ``` RESULT stamp=ORIG stamps=[ORIG] <- interrupted (or finished) original cycle lifecycle ORIG cancelled|completed lifecycle STEER started ECHO STEER RESULT stamp=STEER stamps=[STEER] <- steered cycle lifecycle STEER completed STATE idle <- the only idle ``` So the interrupted cycle's result never names the steer, and the steered cycle's result always does. `later` doesn't fold the steer into the running turn either; it runs as its own cycle after the original finishes, with no idle in between. ## Tests Three new tests in `turn steering (_session/steering)`: - **Echo missing, stamped result:** the turn settles at the result before any idle, and the idle that follows is absorbed. Hangs on `main`. - **Steer aborts an autonomous followup, only one idle:** the turn settles. Hangs on `main`. - **Owed idle arrives after the echo but before the steered result:** the turn must not settle on it, and it ends with both cycles' usage. Passes on `main`, but fails with the post-echo readiness check removed, so it guards against settling early on a pre-steer outcome. `npm run build`, `npm run test:run` and `npm run check` pass. ## Remaining gap If the echo never replays and the result carries no stamp (older producers), the turn still waits for cancel or the next prompt, as documented before. Supersedes #1115 and #1063. Thanks to @KlausUllrich for the #1114 analysis and the result-acknowledgement idea, which this builds on. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>v0.81.1-preview.6 |
||
|
|
281e47eb81 |
fix: honor permissions.disableBypassPermissionsMode (#1165)
## Problem Claude Code refuses `bypassPermissions` when any settings tier sets `permissions.disableBypassPermissionsMode` to `"disable"`. The adapter ignored the setting: it still listed the Bypass mode, passed `allowDangerouslySkipPermissions`, and accepted `defaultMode: "bypassPermissions"` as the starting mode. ## Change Fold the setting into `allowBypass` at session creation. That single value already drives the mode catalog, the SDK flag and the spawn-time mode clamp, so all three now agree with the CLI. Like the CLI, the setting is honored from any tier. It can only take away a permission, so project settings are trusted for it. ## Validation - `npm run build`, `npm run check` and `npm run test:run` pass. - New tests set the option in user settings and in project settings. Both fail without the fix. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>v0.81.1-preview.5 |
||
|
|
43c27e97aa |
fix: offer bypass alongside auto in plan approval (#1164)
Supersedes #1140 by @s-cork. Their commit is kept as-is (rebased onto `main`), plus one follow-up commit. The fork is org-owned, so maintainers can't push to it. ## Problem ExitPlanMode always led with Auto and dropped bypass, even when the session advertised `bypassPermissions`. Clients that deliberately run in full-access mode lost that choice at plan approval. Claude Code itself offers one elevated choice and prefers bypass over Auto. It can do that because the CLI only offers bypass to users who launched with it. The adapter advertises bypass for every non-root session, so copying that priority would hide Auto for almost everyone. ## Change - Offer both Auto and bypass whenever the session advertises them (@s-cork's commit). - Follow-up: remember the mode the session left when it entered plan mode (`SessionModeManager.syncConfig`, which every mode change goes through, including plan approval since #1163). If that was `bypassPermissions`, bypass comes first and is also what the clear-context option uses. Otherwise Auto leads, as before. A remembered bypass mode is ignored if the session no longer advertises it. This also fills the gap where the clear-context choice only ever came in the Auto flavour. Partially addresses #1077. ## Validation - `npm run build`, `npm run check` and `npm run test:run` pass. - New tests cover the pre-plan mode tracking and the option order with and without a pre-plan bypass mode, including the clear-context row. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: stu <stucork@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> |
||
|
|
bd059c10e0 |
fix: mark informational chunks with metadata (#1055)
## Summary - tag SDK `informational` notices with `_meta.claudeCode.kind = "informational"` - include the notice `level` so clients can separate hook/status notices from model text - keep the existing rendered text unchanged for clients that ignore `_meta` Fixes #1042 ## Test plan - `npm test -- --run src/tests/acp-agent.test.ts -t informational` - `npm run build` - `npm run check` - `IS_SANDBOX=1 npm run test:run` - `git diff --check` --------- Signed-off-by: Emre Koca <110906681+kocaemre@users.noreply.github.com> Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>v0.81.1-preview.4 |
||
|
|
58c5db1fdc |
fix: keep the agent starting when the managed-policy tier cannot be read (#1146)
Fixes #1124. ## The defect `src/index.ts` awaited `resolveSettings` at module scope with nothing around it: ```ts const policy = await resolveSettings({ settingSources: [] }); for (const [key, value] of Object.entries(policy.effective.env ?? {})) { process.env[key] = value; } ``` That is a top-level `await` in an ESM entry point, so a rejection aborts module evaluation and the process exits before serving any ACP traffic. The client only sees a process that exited 1 with no protocol messages. Two neighbours make this the only call that can do it, and both are still true on \`main\`: - `SettingsManager.loadAllSettings` (`src/settings.ts:105-113`) wraps the same SDK call in `try`/`catch` and falls back to `{}`. - The `process.on("unhandledRejection", ...)` handler is registered at \`src/index.ts:62\`, after this await, so it does not cover it. Reading the managed tier is best-effort by nature — on a host with no MDM and no managed policy the result is empty and the agent behaves identically — so a transient `EINTR`/`EMFILE`/`EAGAIN` while reading it should leave the agent running with no policy env rather than stop it from starting. ## The change The guard lives in a new `src/managed-policy.ts` rather than inline, for one reason: `src/index.ts` is an ESM entry point with top-level side effects, so nothing in it can be imported by a test. Extracting the tier read makes the failure path testable, which is what the regression test below exercises. `applyManagedPolicyEnv` mirrors `loadAllSettings`: it takes the SDK call through a parameter defaulting to `resolveSettings` and a target env defaulting to `process.env`, reports the failure on stderr, and returns without applying anything. `src/index.ts` becomes: ```ts await applyManagedPolicyEnv(); ``` `console.error` is correct here: this runs before stdout is redirected, so the ACP stream stays clean. ## Verification Four tests in `src/tests/managed-policy.test.ts` cover the applied case, an empty tier, a tier with no `env` table, and the failure path — the last one asserts the promise **resolves** rather than rejects, with the target env untouched, which is the property the entry point depends on. ``` before after tests 17 failed | 1366 passed 17 failed | 1370 passed ``` The 17 failures are pre-existing in this checkout and untouched by this change; the four added tests account for the difference. `eslint src --ext .ts`, `tsc`, and `prettier --check` (with the repository's `.prettierrc.json`) are clean on the three files. ## Note I have not established whether those 17 pre-existing failures are host-specific or real, so I am not claiming anything about them or changing anything for them.v0.81.1-preview.3 |
||
|
|
a2f4239543 |
fix: publish effective mode after plan approval (#1163)
Supersedes #1139 by @s-cork. Their commit is kept as-is (rebased onto `main`), plus one follow-up commit. The fork is org-owned, so maintainers can't push to it. ## Problem Approving a plan through ExitPlanMode changes the SDK permission mode, but ACP clients keep showing Plan. When Auto isn't available for the current model, clients should also see the fallback mode that actually applies. ## Change - After an ExitPlanMode permission is allowed, send `current_mode_update` and `config_option_update` with the session mode as it stands after `applyPermissionFallback`. Rejection and clear-context handling don't change. - Follow-up: wrap those two notifications in a try/catch. The plan is already approved at that point, so a rejected `sessionUpdate` is logged and no longer turns the approval into a failed permission request. This matches `publishFallbackWarning`. Partially addresses #1077. It doesn't fix session restoration after a clear-context approval. ## Validation - `npm run build`, `npm run check` and `npm run test:run` pass. - Regression tests cover the ordinary default, bypass and Auto approvals, plus Auto falling back to acceptEdits. They check both the stored mode and both ACP notifications. - A new test rejects the mode notification and checks that the approval still returns `allow` with the `setMode` update. It fails without the follow-up fix. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: stu <stucork@gmail.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>v0.81.1-preview.2 |
||
|
|
90cde4b397 |
fix: render Write tool calls that use path/file_text aliases (#1161)
Claude Code 2.1.280 (SDK 0.3.280, bumped in #1157) now accepts Write calls where the model sends `path` instead of `file_path`, or `file_text`/`file_content` instead of `content`. The CLI renames these for its own validation, but the streamed `tool_use` block keeps the model's original field names. So we showed the call as "Preparing file…" with no diff or location, even though the write went through. `toolInfoFromToolUse` now reads those fields the same way the CLI does. When both spellings are present, the canonical fields win. Nothing else in the 0.3.280 / 2.1.280 changelog needed an adapter change. I checked Opus 5.5 model rows, the hand-back frame header, `requires_action` during MCP elicitation, and headless elicitation cancellation. ## Test plan - New `toolInfoFromToolUse - Write input aliases` tests - `npm run build`, `npm run check`, `npm run test:run` 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>v0.81.1-preview.1 |
||
|
|
d571358e26 |
chore(main): release 0.81.0 (#1156)
🤖 I have created a release *beep* *boop* --- ## [0.81.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.80.0...v0.81.0) (2026-09-22) ### Features * **deps:** update Claude SDK ([#1157](https://github.com/agentclientprotocol/claude-agent-acp/issues/1157)) ([v0.81.0 |
||
|
|
eb989e93f4 | feat(deps): update Claude SDK (#1157) v0.80.1-preview.2 | ||
|
|
79851b8668 | feat: Send experimental session notices for live advisories (#1155) v0.80.1-preview.1 | ||
|
|
16c9d1a3af |
chore(main): release 0.80.0 (#1151)
🤖 I have created a release *beep* *boop* --- ## [0.80.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.79.0...v0.80.0) (2026-09-22) ### Features * **deps:** Bump claude-agent-sdk to 0.3.278 ([#1147](https://github.com/agentclientprotocol/claude-agent-acp/issues/1147)) ([v0.80.0 |
||
|
|
a05aca6b81 |
fix: close interrupted compaction lifecycles (#1154)
## Summary Close unfinished ACP compactions before interrupted prompts settle. Previously, force cancellation could return `stopReason: cancelled` while leaving the compaction `in_progress`; SDK stream teardown and conversation reset had similar cleanup gaps. - Add shared, idempotent interruption cleanup for cancellation, force-cancel recovery, provider failures, SDK EOF/errors, and conversation reset. - Close compactions before resolving echo-less `/compact` commands, which may still be queued while their compaction is running. - Discard abandoned pending summaries and ignore late compaction openings, completions, chunks, and hooks until an identified live turn resumes. - Preserve normal early-summary buffering across ordinary result boundaries. - Add regression coverage for terminal-before-response ordering, echo-less cancellation, late SDK events, fresh-turn recovery, EOF/errors, reset, and best-effort delivery failures. After interruption, hooks without a command identity are conservatively omitted until a new live turn is identified, rather than risking attribution to the wrong compaction. Older echo-less commands without dispatch identity may likewise omit the ambiguous compaction lifecycle until turn activation. This fixes an implementation gap found while auditing the [Session Compaction RFD](https://github.com/agentclientprotocol/agent-client-protocol/blob/main/docs/rfds/session-compaction.mdx). No protocol or RFD changes are included. ## Validation - [x] `npm run test:run` — 1,397 passed, 28 skipped - [x] `npm run build` - [x] `npm run check` — ESLint and Prettier - [x] `git diff --check` Tests use mocked SDK streams; no live provider calls were made.v0.79.1-preview.3 |
||
|
|
5bc3b4e560 |
feat(deps): Bump claude-agent-sdk to 0.3.278 (#1147)
Bumps the minor group with 11 updates: | Package | From | To | | --- | --- | --- | | [@anthropic-ai/claude-agent-sdk](https://github.com/anthropics/claude-agent-sdk-typescript) | `0.3.274` | `0.3.276` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.5.1` | `26.6.1` | | [prettier](https://github.com/prettier/prettier) | `3.9.7` | `3.9.8` | | @anthropic-ai/claude-agent-sdk-darwin-arm64 | `0.3.274` | `0.3.276` | | @anthropic-ai/claude-agent-sdk-darwin-x64 | `0.3.274` | `0.3.276` | | @anthropic-ai/claude-agent-sdk-linux-arm64 | `0.3.274` | `0.3.276` | | @anthropic-ai/claude-agent-sdk-linux-arm64-musl | `0.3.274` | `0.3.276` | | @anthropic-ai/claude-agent-sdk-linux-x64 | `0.3.274` | `0.3.276` | | @anthropic-ai/claude-agent-sdk-linux-x64-musl | `0.3.274` | `0.3.276` | | @anthropic-ai/claude-agent-sdk-win32-arm64 | `0.3.274` | `0.3.276` | | @anthropic-ai/claude-agent-sdk-win32-x64 | `0.3.274` | `0.3.276` | Updates `@anthropic-ai/claude-agent-sdk` from 0.3.274 to 0.3.276 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/anthropics/claude-agent-sdk-typescript/releases">@anthropic-ai/claude-agent-sdk's releases</a>.</em></p> <blockquote> <h2>v0.3.276</h2> <h2>What's changed</h2> <ul> <li>Updated to parity with Claude Code v2.1.276</li> </ul> <h2>Update</h2> <pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.276 # or yarn add @anthropic-ai/claude-agent-sdk@0.3.276 # or pnpm add @anthropic-ai/claude-agent-sdk@0.3.276 # or bun add @anthropic-ai/claude-agent-sdk@0.3.276 </code></pre> <h2>v0.3.275</h2> <h2>What's changed</h2> <ul> <li>Fixed a deferred tool call's result being emitted with internal keys such as <code>toolUseResult</code> instead of <code>tool_use_result</code> when the tool re-runs at the start of a resumed turn</li> <li>Fixed <code>getSessionMessages()</code> and <code>forkSession()</code> sometimes missing a turn's assistant message when called right after the turn's <code>result</code> message</li> <li>Fixed <code>forkSession({ upToMessageId })</code> rejecting a client-supplied <code>SDKUserMessage.uuid</code> that is not in UUID format</li> <li>Fixed <code>forkSession</code> rejecting the id that <code>getSessionMessages</code> returns for a message sent while Claude was working, and a fork showing a re-run prompt twice</li> <li>Fixed <code>getSessionMessages()</code> omitting a task notification or other queued message that Claude read while running a tool; it now comes back where Claude read it</li> <li>Updated to parity with Claude Code v2.1.275</li> </ul> <h2>Update</h2> <pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.275 # or yarn add @anthropic-ai/claude-agent-sdk@0.3.275 # or pnpm add @anthropic-ai/claude-agent-sdk@0.3.275 # or bun add @anthropic-ai/claude-agent-sdk@0.3.275 </code></pre> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/anthropics/claude-agent-sdk-typescript/blob/main/CHANGELOG.md">@anthropic-ai/claude-agent-sdk's changelog</a>.</em></p> <blockquote> <h2>0.3.276</h2> <ul> <li>Updated to parity with Claude Code v2.1.276</li> </ul> <h2>0.3.275</h2> <ul> <li>Fixed a deferred tool call's result being emitted with internal keys such as <code>toolUseResult</code> instead of <code>tool_use_result</code> when the tool re-runs at the start of a resumed turn</li> <li>Fixed <code>getSessionMessages()</code> and <code>forkSession()</code> sometimes missing a turn's assistant message when called right after the turn's <code>result</code> message</li> <li>Fixed <code>forkSession({ upToMessageId })</code> rejecting a client-supplied <code>SDKUserMessage.uuid</code> that is not in UUID format</li> <li>Fixed <code>forkSession</code> rejecting the id that <code>getSessionMessages</code> returns for a message sent while Claude was working, and a fork showing a re-run prompt twice</li> <li>Fixed <code>getSessionMessages()</code> omitting a task notification or other queued message that Claude read while running a tool; it now comes back where Claude read it</li> <li>Updated to parity with Claude Code v2.1.275</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="v0.79.1-preview.2 |
||
|
|
c6f9668c12 |
fix: prefer terminal output deltas (#1150)
When a client advertises terminal_output_delta, send Bash output through that channel. Keep the completion update free of duplicate raw output while preserving the existing terminal_output fallback.\n\nTracks IJAI-2376.v0.79.1-preview.1 |
||
|
|
d421f56a6c |
chore(main): release 0.79.0 (#1142)
🤖 I have created a release *beep* *boop* --- ## [0.79.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.78.0...v0.79.0) (2026-09-17) ### Features * Update to claude agent sdk 0.3.274 ([#1143](https://github.com/agentclientprotocol/claude-agent-acp/issues/1143)) ([v0.79.0 |
||
|
|
d0fa8e0385 |
feat: Update to claude agent sdk 0.3.274 (#1143)
- **Update deps** - **fix: Hold through placeholder task results**v0.78.1-preview.2 |
||
|
|
bbae5c2c09 |
fix: show shell commands in permission prompts (#1070)
## Summary - use the canonical tool-call title for permission prompts, so shell approvals show the exact command instead of the model-authored description - map `PowerShell` through the same shell presentation path as `Bash` - complete the PowerShell terminal lifecycle with matching `terminal_info`, `terminal_output`, and `terminal_exit` metadata, including failed commands - add focused regression coverage without changing the existing Bash lifecycle tests Fixes #1068 ## PowerShell input and result contract `PowerShell` is a distinct tool name, but its documented input fields match `Bash`: the executable command is in `command`, while `description` is an optional human-readable summary. The Claude Code hooks reference documents the shared `command`, `description`, `timeout`, and `run_in_background` fields, and the tools reference likewise states that PowerShell hooks receive the command in `tool_input.command`. Anthropic closed [claude-code#83647](https://github.com/anthropics/claude-code/issues/83647#issuecomment-5310033500) after documenting this equivalence. Reusing the SDK's exported `BashInput` shape for the common input fields is therefore intentional; the SDK currently does not export a separate `PowerShellInput` type. PowerShell results do not need a PowerShell-specific output assumption here. The result mapper first shape-checks structured stdout/stderr and otherwise falls back to the standard raw `tool_result` string or content-block array. Routing PowerShell through that existing mapper preserves this fallback while completing the adapter's capability-gated terminal sequence: 1. initial `tool_call` with `terminal_info` 2. `tool_call_update` with `terminal_output` 3. final `tool_call_update` with `terminal_exit` All three events use the original tool-use ID, so the client can reconcile and close the terminal. Failed PowerShell results also bypass the generic error renderer and finish the terminal with a non-zero display exit code. The permission presentation introduced in #1004 already handled `Bash` and `PowerShell` together when choosing a description-based permission title, but the canonical tool presentation and terminal result paths only handled `Bash`. This PR completes both paths. References: - [Claude Code hooks: PowerShell input](https://code.claude.com/docs/en/hooks#powershell) - [Claude Code tools reference: PowerShell tool](https://code.claude.com/docs/en/tools-reference#powershell-tool) - [Anthropic schema confirmation](https://github.com/anthropics/claude-code/issues/83647#issuecomment-5310033500) ## Verification - `npm run check` - `npm run build` - `npm run test:run -- src/tests/tools.test.ts -t "PowerShell terminal output"` (1 passed) - full suite with an empty temporary Claude config: `CLAUDE_CONFIG_DIR=<empty temporary directory> npm run test:run` (1070 passed, 27 skipped) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>v0.78.1-preview.1 |
||
|
|
becd854dd8 |
chore(main): release 0.78.0 (#1130)
🤖 I have created a release *beep* *boop* --- ## [0.78.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.77.0...v0.78.0) (2026-09-15) ### Features * Add experimental ACP compaction update support ([#1134](https://github.com/agentclientprotocol/claude-agent-acp/issues/1134)) ([v0.78.0 |
||
|
|
91f1699366 |
perf: report file changes from Claude checkpoints (#1138)
## Summary - replace the hidden model-authored file audit turn with Claude native file checkpointing - preview changed paths with rewindFiles at the terminal turn boundary while preserving the existing AIR metadata contract - enable checkpointing only for clients that negotiate agentFileChangeReport and fail open after two seconds - retain legacy audit filtering so persisted sessions do not replay old hidden audit turns This follows Claude Code checkpoint semantics. It tracks changes made through supported Claude file tools; Bash and most subagent changes may not be included. Reference: https://code.claude.com/docs/en/checkpointing ## Validation - npm run build - npm run check - env -u ANTHROPIC_BASE_URL npm run test:run (1368 passed, 28 skipped)v0.77.1-preview.4 |
||
|
|
735950a83e |
perf: supply AIR diff counts from Claude structured patches (#1122)
Claude supplies structured patches for Edit and Write, but ACP diff blocks previously carried only the reconstructed texts. AIR had to compare those texts again to display added and removed counts. Count patch operations in the existing conversion loop and publish `_meta.jetbrains.air.diffStats` on each diff block. This uses the same contract as https://github.com/agentclientprotocol/codex-acp/pull/501. Each block has its own counts. No extra traversal, full file comparison, or navigation calculation is needed. Omit statistics when patches are absent or inconsistent, so clients retain their existing fallback. Exclude EOF markers from the displayed texts. Document the extension and cover per-block counts, Edit and Write hooks, EOF changes, and fallback behavior. Validation: - `npm run build` - `npm run check` - `env -u ANTHROPIC_BASE_URL npm run test:run` (the local endpoint override affects unrelated provider tests)v0.77.1-preview.3 |
||
|
|
543a9a2f97 | feat: Add experimental ACP compaction update support (#1134) v0.77.1-preview.2 | ||
|
|
8823ea6fcb |
fix: keep the picked option when AskUserQuestion custom text is also supplied (#1131)
## Summary For a single-select `AskUserQuestion`, a non-empty custom-answer field (`question_<n>_custom`) replaced the selected option. A client that renders that box as a notes step (as in #1050, seen via Devin/Windsurf) therefore returned only the typed text and the selection never reached the model. - The pick now stays in `answers`, and the typed text travels beside it as the tool's own per-question `annotations[question].notes`. That is the slot the CLI itself uses for free text attached to a selection and renders to the model as `"Q"="A" notes: ...`, so no new answer format is invented. - Custom text with no pick is still the answer on its own (the CLI's "Other"). - Multi-select folding from #1031 is unchanged: the text still joins the checked options with CLI-style quoting. - `annotations` is only added to `updatedInput` when non-empty. - The single-select field description now says the box can also add a note to the chosen option. Supersedes #1054, which conflicted with #1031 and glued label and text into one string. The "empty notes field won't submit" part of #1050 is client-side: nothing in the requested schema is marked required. Closes #1050 ## Test plan - `npm run check` - `npm run build` - `npm run test:run` (1325 passed, 27 skipped) - New test: pick + custom text yields `answers: { Q: "A" }` and `annotations: { Q: { notes } }` - New test: custom text alone on a single-select stays the answer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>v0.77.1-preview.1 |
||
|
|
dfe823b958 |
chore(main): release 0.77.0 (#1118)
🤖 I have created a release *beep* *boop* --- ## [0.77.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.76.0...v0.77.0) (2026-09-14) ### ⚠ BREAKING CHANGES * claudeCode.options.agent is no longer forwarded to Claude Code, and the agent-picker exports DEFAULT_AGENT_ID, AGENT_CONFIG_ID, BUILTIN_AGENT_NAMES, and discoverCustomAgents are removed. Consumers relying on main-thread agent selection must stop passing that option. ### Features * Add tool names to tool calls ([#1128](https://github.com/agentclientprotocol/claude-agent-acp/issues/1128)) ([v0.77.0 |
||
|
|
3d99cafe4a |
fix: honor host opt-out for allowDangerouslySkipPermissions (#1129)
## Summary Closes #1119. Supersedes #1120 by @amansk (their commits are included on this branch; the fork does not allow maintainer edits, so review fixes landed here instead). Hosts that never use `bypassPermissions` can opt a session out by sending `_meta.claudeCode.options.allowDangerouslySkipPermissions: false` on `session/new` (and again on `session/load`). When omitted or `true`, behavior is unchanged: bypass is available on non-root sessions. ## Design Bypass availability is decided once per session in `createSession`: ```ts const allowBypass = ALLOW_BYPASS && sessionMeta?.claudeCode?.options?.allowDangerouslySkipPermissions !== false; ``` and threaded to the three places that must agree: - the SDK `allowDangerouslySkipPermissions` flag (the actual enforcement; the CLI refuses bypass without it) - the spawn-time mode clamp in `resolvePermissionMode`, so a `permissions.defaultMode` of `bypassPermissions` (or a mode carried across a clear-context restart) becomes `default` before `query()` rather than failing at spawn - the session mode catalog in `SessionModeManager.initialize`, so the client is never offered a mode the CLI would reject ## Changes from #1120 - Fold the host opt-out into `resolvePermissionMode` via an `allowBypass` parameter instead of a second inline clamp; drop the separate `resolveAllowDangerouslySkipPermissions` helper - Make `allowBypass` a required `initialize` parameter and remove the module-global `ALLOW_BYPASS` fallback from `session-mode.ts` - Fix `tsc` errors in the new tests (`modes` is optional on `NewSessionResponse`), which broke the CI build job - Move the settings-driven clamp test onto the shared `acp-agent-settings` fixture (isolated cwd, no double module reload, passes as root) - Document the opt-out in `docs/permission-extension.md` ## Testing - `npm run check`, `npm run build` — pass - `npm run test:run` — pass (the branch is based before #1123, so the SDK version guard in `model-presentation.test.ts` only passes with the pinned 0.3.257; it clears on rebase) Co-authored-by: Cursor Agent <cursoragent@cursor.com> 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Amandeep Khurana <amansk@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>v0.76.1-preview.8 |
||
|
|
1a4512c711 |
fix: keep multi-select answers when a custom answer is typed (#1031)
## Summary
`applyAskElicitationResponse` drops a multi-select question's checked
options as soon as
that question's custom-answer field is non-empty: the typed text
replaces the selection
instead of joining it, so the checked options never reach the model.
Versions: reproduced on v0.69.0, code unchanged on v0.70.0 and current
`main` (
v0.76.1-preview.7
|
||
|
|
b274923ef8 |
fix: parse TaskList output without ambiguous regex (#1006)
## Summary - Replace the ambiguous regex used to parse textual `TaskList` output with linear string parsing. - Preserve support for owners, multiple dependencies, and malformed suffixes treated as subject text. - Add a regression test covering adversarial input. This addresses a potential ReDoS reported by CodeQL without changing the structured JSON path. Closes #1005. ## Testing - `npm run test:run` - `npm run build` - `npm run check`v0.76.1-preview.6 |
||
|
|
15ba608a79 |
fix: strip injected system reminders from replayed prompts (#1040)
## Summary - strip `<system-reminder>` blocks from replayed user messages, through the marker scanner that already handles the local-command tags - what the user actually typed is preserved; a reminder-only message strips to nothing and is skipped - regression coverage for the string shape, the content-array shape, and `replaySessionHistory` end to end ## Why `stripLocalCommandMetadata` exists for a stated reason: *"The live prompt loop drops them; replay must strip them too or they leak into the UI on session/load."* Injected reminders are the same class of leak and are not covered by it. The CLI appends `<system-reminder>` blocks to a user turn to steer the model — a worktree that was deleted, a background task that started elsewhere. They are persisted in the same text block as the prose the user typed, and they are not `isMeta`, so `getSessionMessages` returns them. Live, nothing reaches the client: the prompt loop's user-message skip covers the whole message. On `session/load` the block is replayed verbatim, so a client renders a paragraph of instructions the user never wrote, followed by their one-line prompt. Reproduced against `main` with a real transcript: a reminder about a deleted worktree, followed by a five-word prompt, arrives as a single `user_message_chunk` containing both. With this change the chunk is the five words. ## Not included, deliberately - **`<task-notification>` envelopes.** They still replay as user messages, but #1028 is already doing that properly, keyed on the SDK-provided `origin.kind` rather than the text — the better trust boundary, since a user can type the tag themselves. - **`[Request interrupted by user]`.** Also still replayed as a user message. It is untagged prose and it is the only trace a cancelled turn leaves, so whether it should be dropped, typed, or marked in `_meta` reads as your product call rather than a bug fix. Happy to open a follow-up if you want it handled. The exported name `stripLocalCommandMetadata` is left alone — it is part of `lib.ts` — so only the shared marker list and the doc comment grew. ## The one false positive A user who literally types `<system-reminder>…</system-reminder>` in a prompt loses that span on replay, while seeing it live. It is the same trade already accepted for `<command-name>`, the surrounding prose still survives, and text is the only signal available here — unlike task notifications, reminders carry no `origin` to key on. Flagging it rather than leaving it for review to find. ## Verification - `npm run build` - `npm run check` - `env -u ANTHROPIC_BASE_URL npm run test:run` — 974 passed, 27 skipped - the three new tests fail on `main` and pass with the change 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>v0.76.1-preview.5 |
||
|
|
d3205ab11f |
feat(deps): Bump @anthropic-ai/claude-agent-sdk to 0.3.270 (#1123)
Bumps the minor group with 8 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@anthropic-ai/claude-agent-sdk](https://github.com/anthropics/claude-agent-sdk-typescript) | `0.3.257` | `0.3.263` | | [@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript) | `0.122.0` | `0.124.0` | | [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `26.4.0` | `26.5.0` | | [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) | `8.69.0` | `8.70.0` | | [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) | `8.69.0` | `8.70.0` | | [eslint](https://github.com/eslint/eslint) | `10.9.1` | `10.10.0` | | [hono](https://github.com/honojs/hono) | `4.13.5` | `4.13.7` | | [jose](https://github.com/panva/jose) | `6.2.10` | `6.2.12` | Updates `@anthropic-ai/claude-agent-sdk` from 0.3.257 to 0.3.263 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/anthropics/claude-agent-sdk-typescript/releases">@anthropic-ai/claude-agent-sdk's releases</a>.</em></p> <blockquote> <h2>v0.3.263</h2> <h2>What's changed</h2> <ul> <li>Updated to parity with Claude Code v2.1.263</li> </ul> <h2>Update</h2> <pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.263 # or yarn add @anthropic-ai/claude-agent-sdk@0.3.263 # or pnpm add @anthropic-ai/claude-agent-sdk@0.3.263 # or bun add @anthropic-ai/claude-agent-sdk@0.3.263 </code></pre> <h2>v0.3.261</h2> <h2>What's changed</h2> <ul> <li>Added <code>pluginDelivery: 'initialize'</code> to send <code>plugins</code> over stdin so the launch command line no longer grows with the plugin count (fixes Windows start failures with many plugins)</li> <li>Fixed <code>query()</code> throwing "Object not disposable" in runtimes without a native <code>Symbol.dispose</code>, such as Node ≤22 <code>vm</code> contexts (Jest's <code>node</code> environment, vitest <code>vmThreads</code>/<code>vmForks</code>) and Node <18.18</li> <li>Updated to parity with Claude Code v2.1.261</li> </ul> <h2>Update</h2> <pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.261 # or yarn add @anthropic-ai/claude-agent-sdk@0.3.261 # or pnpm add @anthropic-ai/claude-agent-sdk@0.3.261 # or bun add @anthropic-ai/claude-agent-sdk@0.3.261 </code></pre> <h2>v0.3.260</h2> <h2>What's changed</h2> <ul> <li>Added optional <code>user_message_uuid</code> to <code>thinking_tokens</code> system messages, linking thinking progress to the user message that triggered the turn</li> <li>Added optional <code>first_content_frame_ms</code>, <code>first_stream_post_ms</code>, <code>first_stream_post_ack_ms</code> and <code>first_stream_post_wall_ms</code> fields to the success result message for remote-session latency breakdowns</li> <li>Fixed <code>managedSettings</code> <code>disableAutoMode: "disable"</code> (either spelling) being dropped by the restrictive-only filter instead of turning auto mode off for the spawned session</li> <li>Fixed <code>rewindFiles()</code> reporting success when no files could be restored (for example when checkpoint backups are missing); it now fails</li> <li>Changed <code>error_max_structured_output_retries</code> results to append the last StructuredOutput tool error; validation errors now name the offending key, allowed values, and actual length or count</li> <li>Changed <code>rate_limit_event</code> to also re-emit during an exceeded window on repeat 429s (about once per 30 seconds per limit window), so stream consumers can refresh stale rate-limit state</li> <li>Updated to parity with Claude Code v2.1.260</li> </ul> <h2>Update</h2> <pre lang="sh"><code></tr></table> </code></pre> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/anthropics/claude-agent-sdk-typescript/blob/main/CHANGELOG.md">@anthropic-ai/claude-agent-sdk's changelog</a>.</em></p> <blockquote> <h2>0.3.263</h2> <ul> <li>Updated to parity with Claude Code v2.1.263</li> </ul> <h2>0.3.262</h2> <ul> <li>Updated to parity with Claude Code v2.1.262</li> </ul> <h2>0.3.261</h2> <ul> <li>Added <code>pluginDelivery: 'initialize'</code> to send <code>plugins</code> over stdin so the launch command line no longer grows with the plugin count (fixes Windows start failures with many plugins)</li> <li>Fixed <code>query()</code> throwing "Object not disposable" in runtimes without a native <code>Symbol.dispose</code>, such as Node ≤22 <code>vm</code> contexts (Jest's <code>node</code> environment, vitest <code>vmThreads</code>/<code>vmForks</code>) and Node <18.18</li> <li>Updated to parity with Claude Code v2.1.261</li> </ul> <h2>0.3.260</h2> <ul> <li>Added optional <code>user_message_uuid</code> to <code>thinking_tokens</code> system messages, linking thinking progress to the user message that triggered the turn</li> <li>Added optional <code>first_content_frame_ms</code>, <code>first_stream_post_ms</code>, <code>first_stream_post_ack_ms</code> and <code>first_stream_post_wall_ms</code> fields to the success result message for remote-session latency breakdowns</li> <li>Fixed <code>managedSettings</code> <code>disableAutoMode: "disable"</code> (either spelling) being dropped by the restrictive-only filter instead of turning auto mode off for the spawned session</li> <li>Fixed <code>rewindFiles()</code> reporting success when no files could be restored (for example when checkpoint backups are missing); it now fails</li> <li>Changed <code>error_max_structured_output_retries</code> results to append the last StructuredOutput tool error; validation errors now name the offending key, allowed values, and actual length or count</li> <li>Changed <code>rate_limit_event</code> to also re-emit during an exceeded window on repeat 429s (about once per 30 seconds per limit window), so stream consumers can refresh stale rate-limit state</li> <li>Updated to parity with Claude Code v2.1.260</li> </ul> <h2>0.3.259</h2> <ul> <li>Added <code>user_message_uuids</code> beside <code>user_message_uuid</code> on a turn's first reply frame and result: every user message the turn answered, so a reply to several merged messages can be matched to each</li> <li>Added <code>permissionPrompts: 'none'</code> option to auto-deny permission prompts in sessions with nobody to answer them, without disabling auto mode's classifier</li> <li>Updated to parity with Claude Code v2.1.259</li> </ul> <h2>0.3.258</h2> <ul> <li>Updated to parity with Claude Code v2.1.258</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="v0.76.1-preview.4 |
||
|
|
67c7c9b117 |
feat: Add tool names to tool calls (#1128)
Supports the new tool call name RFDv0.76.1-preview.3 |
||
|
|
4deace4037 | ci: poll for package availability after publish before triggering registry update (#1121) v0.76.1-preview.2 | ||
|
|
6b7473b1af |
refactor!: remove agent config option (#1112)
## Why The main-thread agent option is a rarely used, provider-specific parameter. It is not used by ACP clients or their settings, and maintaining a public picker for it adds config state, discovery calls, restart propagation, and live-switch handling for functionality that clients do not need. Removing it keeps the session configuration contract focused on settings that ACP clients actually use. This does not remove ACP subagent sessions or the Agent/Task tool behavior; it only removes the unused main-thread agent selector and parameter plumbing. ## Summary - remove the main-thread Agent session config picker and custom-agent discovery - remove live agent switching and session state used only by that picker - ignore claudeCode.options.agent and stop restoring it during context resets - document agent as ignored in the exported NewSessionMeta contract - preserve ACP subagent sessions and Agent/Task tool behavior ## Breaking change BREAKING CHANGE: claudeCode.options.agent is no longer forwarded to Claude Code, and the agent-picker exports DEFAULT_AGENT_ID, AGENT_CONFIG_ID, BUILTIN_AGENT_NAMES, and discoverCustomAgents are removed. Consumers relying on main-thread agent selection must stop passing that option. ## Testing - npm run check - npm run build - npx vitest run src/tests/create-session-options.test.ts (62 passed)v0.76.1-preview.1 |
||
|
|
c2e4815029 |
chore(main): release 0.76.0 (#1101)
🤖 I have created a release *beep* *boop* --- ## [0.76.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.75.1...v0.76.0) (2026-09-09) ### Features * advertise recommended config values ([#1111](https://github.com/agentclientprotocol/claude-agent-acp/issues/1111)) ([v0.76.0 |
||
|
|
2b666c3d35 |
feat: advertise recommended config values (#1111)
Clients that negotiate the AIR `recommendedValue` capability receive concrete model and effort choices instead of ambiguous default rows. The SDK's default model is mapped only to an exact selectable model (including equivalent context suffix spellings); unavailable recommendations retain the legacy default. Recommendations remain independent of explicit selections. The adapter applies the displayed effort to the SDK at startup and on model switches, preserving supported user pins and re-reading per-model settings for automatic choices. Permission modes and clients without the capability retain their existing configuration behavior. Model and effort configuration logic is extracted into dedicated modules. Terse SDK model labels are enriched with concrete versions from model metadata: for example, `Fable` becomes `Fable 5.1`, `Sonnet` becomes `Sonnet 5`, and `Opus (1M context)` becomes `Opus 5`. Custom names are preserved, and collisions fall back to the original labels. An SDK version guard requires review on upgrades, and an opt-in live initialization test verifies the upstream model contract without sending a prompt. Validation: - `npm run check` - `npm run build` - `env -u ANTHROPIC_BASE_URL npm run test:run` — 1253 passed, 28 skipped - `RUN_INTEGRATION_TESTS=true npx vitest run src/tests/model-presentation.test.ts` — 4 passed - Regression coverage for unavailable model generations/context windows, startup effort, per-model settings, unsupported effort pins, and duplicate Opus labelsv0.75.2-preview.2 |
||
|
|
45f8b34020 | ci: don't wait for CI workflow when publishing preview releases, replace --dry-run with real publication (#1113) v0.75.2-preview.1 | ||
|
|
cc528fb5e9 | ci: testing preview publication (#1105) | ||
|
|
0dd58685b1 |
ci: set up preview publishing (#1084)
Today nothing reaches npm between two release-please releases, so trying a merged but unreleased change means building from source. This adds a continuously published preview channel. Every CI-green push to `main` that is not a release merge publishes `<package.json version, patch bumped>-preview.N` under the `preview` dist-tag, tags the commit `v<version>`, and dispatches the same agent registry update a stable release does. With `main` at 0.73.0 that gives `0.73.1-preview.1`, `0.73.1-preview.2`, and so on; `N` restarts at 1 whenever a release moves the base. `latest` is untouched. ## Approach - **Added to `publish.yml` rather than a new workflow.** npm binds a trusted publisher to one repo + workflow filename, and a package gets only one. A separate file would fail OIDC and cost the stable path its publisher. - **Gated on the `CI` workflow succeeding** (`workflow_run`), so a red commit is never published. release-please's release merge is excluded by the head commit's author and subject — its `releases_created` output is not reachable from a different workflow run. - **`N` is the max of the npm registry and local git tags.** npm reserves versions forever, even after `unpublish`, so a reused `N` is a hard failure; but the registry is CDN-served and lags, which the tags cover. A registry read failure aborts rather than guessing. - **Base is patch+1, not release-please's prediction**, which moves mid-flight and would reset `N` under already-published previews. - **The version is applied to the CI working tree only**, never committed — `package.json` and the release-please manifest stay release-please's to own. - **`--tag preview` is mandatory:** `npm publish` defaults to `latest` even for a semver prerelease. - **Three jobs.** `publish-npm-preview` mirrors `publish-npm` and only publishes (no repo write access); `publish-tag-preview` only tags, so a failed tag is retryable with _Re-run failed jobs_ without re-publishing an immutable version; `trigger-registry-update` is shared with the stable path. Both downstream jobs gate on a `published` output the publish step sets, not on job status — the tag push happens after the publish, so a red job can still mean npm has the version. ## Next step The publish is `npm publish --dry-run` for now. The `workflow_run` trigger and the `release` environment's protected-branch policy mean this job cannot run off the default branch at all, so merging this is the only way to exercise the trigger, the gate and the version calculation — and with `published` unset, the rehearsal neither tags nor touches the registry. Once one run looks right, a follow-up drops `--dry-run` and adds `echo "published=true" >> "$GITHUB_OUTPUT"` to that step. Nothing else changes. |
||
|
|
d870ebd2fd |
feat(deps): Bump fast-uri from 3.1.6 to 3.1.7 (#1100)
Bumps [fast-uri](https://github.com/fastify/fast-uri) from 3.1.6 to 3.1.7. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/fastify/fast-uri/releases">fast-uri's releases</a>.</em></p> <blockquote> <h2>v3.1.7</h2> <h2>⚠️ Security Warning</h2> <p>This is a security release that fixes the following high-severity security advisories:</p> <ul> <li><a href="https://github.com/fastify/fast-uri/security/advisories/GHSA-qw65-cvwx-89v3">GHSA-qw65-cvwx-89v3</a> — authority injection via an unvalidated port in <code>serialize()</code></li> <li><a href="https://github.com/fastify/fast-uri/security/advisories/GHSA-58mr-gqgx-xq4g">GHSA-58mr-gqgx-xq4g</a> — host confusion via unbalanced or misplaced IP-literal brackets</li> </ul> <p>Users of the v3.x release line should upgrade to v3.1.7.</p> <p><strong>Full Changelog</strong>: <a href="https://github.com/fastify/fast-uri/compare/v3.1.6...v3.1.7">https://github.com/fastify/fast-uri/compare/v3.1.6...v3.1.7</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
194e195b05 |
feat(deps-dev): Bump vitest from 4.1.11 to 5.0.0 (#1099)
Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.1.11 to 5.0.0. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/vitest-dev/vitest/releases">vitest's releases</a>.</em></p> <blockquote> <h2>v5.0.0</h2> <p>Vitest 5 is officially out! This release focuses on performance and brings a lot of new features while fixing long-standing bugs. See our <a href="https://vitest.dev/blog/vitest-5.html">blog post</a> for the official announcement.</p> <h3> 🚨 Breaking Changes</h3> <ul> <li>Replace <code>loupe.inspect</code> with pretty-format - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a>, <strong>Claude Opus 5 (1M context)</strong> and <strong>OpenAI Codex</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/9609">vitest-dev/vitest#9609</a> <a href="https://github.com/vitest-dev/vitest/commit/3f802da4b"><!-- raw HTML omitted -->(3f802)<!-- raw HTML omitted --></a></li> <li>Remove quotes from string values in <code>test.for/each</code> title <code>$</code> variable (take 2) - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10170">vitest-dev/vitest#10170</a> <a href="https://github.com/vitest-dev/vitest/commit/04d37e9d7"><!-- raw HTML omitted -->(04d37)<!-- raw HTML omitted --></a></li> <li>Default <code>attachmentsDir</code> from <code>.vitest-attachements/</code> to <code>.vitest/attachments/</code> - by <a href="https://github.com/MdSadiqMd"><code>@MdSadiqMd</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10186">vitest-dev/vitest#10186</a> <a href="https://github.com/vitest-dev/vitest/commit/1ba7338c3"><!-- raw HTML omitted -->(1ba73)<!-- raw HTML omitted --></a></li> <li>Remove <code>sequential</code> test/suite options in favor of <code>concurrent</code> - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a> and <strong>OpenAI Codex</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10198">vitest-dev/vitest#10198</a> <a href="https://github.com/vitest-dev/vitest/commit/9229f2edc"><!-- raw HTML omitted -->(9229f)<!-- raw HTML omitted --></a></li> <li>Represent locator as an object instead of a string - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10212">vitest-dev/vitest#10212</a> <a href="https://github.com/vitest-dev/vitest/commit/80f07edf6"><!-- raw HTML omitted -->(80f07)<!-- raw HTML omitted --></a></li> <li>Inline <code>expect</code> package - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10221">vitest-dev/vitest#10221</a> <a href="https://github.com/vitest-dev/vitest/commit/ad16223e7"><!-- raw HTML omitted -->(ad162)<!-- raw HTML omitted --></a></li> <li>Remove deprecated entry points - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10222">vitest-dev/vitest#10222</a> <a href="https://github.com/vitest-dev/vitest/commit/994c6ddb9"><!-- raw HTML omitted -->(994c6)<!-- raw HTML omitted --></a></li> <li>Require Node.js 22 and Vite 6.4 - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10178">vitest-dev/vitest#10178</a> <a href="https://github.com/vitest-dev/vitest/commit/3876283e8"><!-- raw HTML omitted -->(38762)<!-- raw HTML omitted --></a></li> <li>Fail <code>expect.poll</code> when function didn't resolve in time - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a> and <strong>OpenAI Codex</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10233">vitest-dev/vitest#10233</a> <a href="https://github.com/vitest-dev/vitest/commit/4df048c11"><!-- raw HTML omitted -->(4df04)<!-- raw HTML omitted --></a></li> <li>Throw an error if hoistable methods are outside the top level scope - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10460">vitest-dev/vitest#10460</a> <a href="https://github.com/vitest-dev/vitest/commit/d0b4fddcb"><!-- raw HTML omitted -->(d0b4f)<!-- raw HTML omitted --></a></li> <li><code>toHaveTextContent</code> is strict, add <code>toMatchTextContent</code> as alternative - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10473">vitest-dev/vitest#10473</a> <a href="https://github.com/vitest-dev/vitest/commit/18f303079"><!-- raw HTML omitted -->(18f30)<!-- raw HTML omitted --></a></li> <li>Don't lookup config file from ancestor directories - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a>, <strong>OpenAI Codex</strong> and <strong>Hiroshi Ogawa</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10428">vitest-dev/vitest#10428</a> <a href="https://github.com/vitest-dev/vitest/commit/945d9090e"><!-- raw HTML omitted -->(945d9)<!-- raw HTML omitted --></a></li> <li>Inline <code>@vitest/runner</code> package, do not publish it anymore - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10511">vitest-dev/vitest#10511</a> <a href="https://github.com/vitest-dev/vitest/commit/6d6e46b1e"><!-- raw HTML omitted -->(6d6e4)<!-- raw HTML omitted --></a></li> <li>Allow mutating happy-dom/jsdom window object - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a>, <strong>Hiroshi Ogawa</strong> and <strong>OpenAI Codex</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10373">vitest-dev/vitest#10373</a> <a href="https://github.com/vitest-dev/vitest/commit/206e8cff8"><!-- raw HTML omitted -->(206e8)<!-- raw HTML omitted --></a></li> <li>Expose <code>concurrencyId</code>/<code>workerId</code> on TestModule's diagnostics, make id 1-based - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10516">vitest-dev/vitest#10516</a> <a href="https://github.com/vitest-dev/vitest/commit/bdd985433"><!-- raw HTML omitted -->(bdd98)<!-- raw HTML omitted --></a></li> <li>Add <code>screenshotDirectory</code> config to <code>browser.expect.toMatchScreenshot</code> - by <a href="https://github.com/macarie"><code>@macarie</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10592">vitest-dev/vitest#10592</a> <a href="https://github.com/vitest-dev/vitest/commit/a60ded0fb"><!-- raw HTML omitted -->(a60de)<!-- raw HTML omitted --></a></li> <li>Update <code>@sinonjs/fake-timers</code> and support mocking <code>Temporal</code> - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a>, <strong>Hiroshi Ogawa</strong> and <strong>OpenCode (gpt-5.6-sol)</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10654">vitest-dev/vitest#10654</a> <a href="https://github.com/vitest-dev/vitest/commit/f8b1532fe"><!-- raw HTML omitted -->(f8b15)<!-- raw HTML omitted --></a></li> <li>Remove webdriverio package - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10675">vitest-dev/vitest#10675</a> <a href="https://github.com/vitest-dev/vitest/commit/5fed68f72"><!-- raw HTML omitted -->(5fed6)<!-- raw HTML omitted --></a></li> <li>Clear mocks by default before each test - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10613">vitest-dev/vitest#10613</a> <a href="https://github.com/vitest-dev/vitest/commit/0f6463bf2"><!-- raw HTML omitted -->(0f646)<!-- raw HTML omitted --></a></li> <li>Don't emit localStorage warnings on Node 26, fail gracefully when worker fails to start - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10293">vitest-dev/vitest#10293</a> <a href="https://github.com/vitest-dev/vitest/commit/334edef92"><!-- raw HTML omitted -->(334ed)<!-- raw HTML omitted --></a></li> <li>Separate config resolution from the server creation - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10554">vitest-dev/vitest#10554</a> <a href="https://github.com/vitest-dev/vitest/commit/1c0ec3444"><!-- raw HTML omitted -->(1c0ec)<!-- raw HTML omitted --></a></li> <li>Inline projects extend the root config by default - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10750">vitest-dev/vitest#10750</a> <a href="https://github.com/vitest-dev/vitest/commit/fec001ad3"><!-- raw HTML omitted -->(fec00)<!-- raw HTML omitted --></a></li> <li>Enable mocking Temporal without fake timers - by <a href="https://github.com/fabon-f"><code>@fabon-f</code></a>, <strong>Hiroshi Ogawa</strong> and <strong>OpenCode (gpt-5.6-sol)</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10757">vitest-dev/vitest#10757</a> <a href="https://github.com/vitest-dev/vitest/commit/ac2d46b42"><!-- raw HTML omitted -->(ac2d4)<!-- raw HTML omitted --></a></li> <li>Support nested projects - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10846">vitest-dev/vitest#10846</a> <a href="https://github.com/vitest-dev/vitest/commit/ec367cf2a"><!-- raw HTML omitted -->(ec367)<!-- raw HTML omitted --></a></li> <li>Use <code>></code> as separator in <code>-t</code>, calculate <code>only</code> once - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10686">vitest-dev/vitest#10686</a> <a href="https://github.com/vitest-dev/vitest/commit/a0b20bc86"><!-- raw HTML omitted -->(a0b20)<!-- raw HTML omitted --></a></li> <li>Fail the test when an asynchronous assertion is not awaited - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10868">vitest-dev/vitest#10868</a> <a href="https://github.com/vitest-dev/vitest/commit/86d4a9da9"><!-- raw HTML omitted -->(86d4a)<!-- raw HTML omitted --></a></li> <li>Share the Vite server between inline projects - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10848">vitest-dev/vitest#10848</a> <a href="https://github.com/vitest-dev/vitest/commit/d87c96ee4"><!-- raw HTML omitted -->(d87c9)<!-- raw HTML omitted --></a></li> <li>Parse files statically in vitest list by default - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/11088">vitest-dev/vitest#11088</a> <a href="https://github.com/vitest-dev/vitest/commit/51e949416"><!-- raw HTML omitted -->(51e94)<!-- raw HTML omitted --></a></li> <li><strong>benchmark</strong>: <ul> <li>Rewrite the public API - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10113">vitest-dev/vitest#10113</a> <a href="https://github.com/vitest-dev/vitest/commit/19f6e8947"><!-- raw HTML omitted -->(19f6e)<!-- raw HTML omitted --></a></li> </ul> </li> <li><strong>browser</strong>: <ul> <li>Iframe scale - by <a href="https://github.com/macarie"><code>@macarie</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/9745">vitest-dev/vitest#9745</a> <a href="https://github.com/vitest-dev/vitest/commit/b639852cc"><!-- raw HTML omitted -->(b6398)<!-- raw HTML omitted --></a></li> <li>Enable <code>locators.exact</code> by default - by <a href="https://github.com/sheremet-va"><code>@sheremet-va</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10430">vitest-dev/vitest#10430</a> <a href="https://github.com/vitest-dev/vitest/commit/e203202f9"><!-- raw HTML omitted -->(e2032)<!-- raw HTML omitted --></a></li> <li>Require <code>sessionId</code> for orchestrator html request - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a>, <strong>Hiroshi Ogawa</strong> and <strong>OpenAI Codex</strong> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10522">vitest-dev/vitest#10522</a> <a href="https://github.com/vitest-dev/vitest/commit/79b7d8fcc"><!-- raw HTML omitted -->(79b7d)<!-- raw HTML omitted --></a></li> <li>Save failure screenshots in <code>attachmentsDir</code> - by <a href="https://github.com/macarie"><code>@macarie</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10917">vitest-dev/vitest#10917</a> <a href="https://github.com/vitest-dev/vitest/commit/3b5bbd8b4"><!-- raw HTML omitted -->(3b5bb)<!-- raw HTML omitted --></a></li> </ul> </li> <li><strong>coverage</strong>: <ul> <li><code>include/exclude</code> globs too eager - by <a href="https://github.com/AriPerkkio"><code>@AriPerkkio</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/9818">vitest-dev/vitest#9818</a> <a href="https://github.com/vitest-dev/vitest/commit/edacb0fd4"><!-- raw HTML omitted -->(edacb)<!-- raw HTML omitted --></a></li> <li>Allow <code>thresholds.perFile</code> to accept an object - by <a href="https://github.com/vladlenskiy"><code>@vladlenskiy</code></a> and <a href="https://github.com/AriPerkkio"><code>@AriPerkkio</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10190">vitest-dev/vitest#10190</a> <a href="https://github.com/vitest-dev/vitest/commit/13b78d98b"><!-- raw HTML omitted -->(13b78)<!-- raw HTML omitted --></a></li> </ul> </li> <li><strong>expect</strong>: <ul> <li>Fix <code>toThrow("")</code> behavior by reverting <a href="https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest/issues/6710">#6710</a> - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/9643">vitest-dev/vitest#9643</a> and <a href="https://redirect.github.com/vitest-dev/vitest/issues/6710">vitest-dev/vitest#6710</a> <a href="https://github.com/vitest-dev/vitest/commit/6c3e4bdbf"><!-- raw HTML omitted -->(6c3e4)<!-- raw HTML omitted --></a></li> </ul> </li> <li><strong>mocker</strong>: <ul> <li>Deserialize automock as automock - by <a href="https://github.com/nami8824"><code>@nami8824</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10192">vitest-dev/vitest#10192</a> <a href="https://github.com/vitest-dev/vitest/commit/2f892712d"><!-- raw HTML omitted -->(2f892)<!-- raw HTML omitted --></a></li> </ul> </li> <li><strong>reporters</strong>: <ul> <li><code>blob</code> reporter and <code>--merge-reports</code> default to <code>.vitest/blob/</code> - by <a href="https://github.com/AriPerkkio"><code>@AriPerkkio</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10232">vitest-dev/vitest#10232</a> <a href="https://github.com/vitest-dev/vitest/commit/d22b029ae"><!-- raw HTML omitted -->(d22b0)<!-- raw HTML omitted --></a></li> <li>Write json and junit reporter output files to <code>.vitest</code> by default - by <a href="https://github.com/hi-ogawa"><code>@hi-ogawa</code></a>, <strong>Hiroshi Ogawa</strong>, <strong>OpenCode (gpt-5.6-sol)</strong> and <a href="https://github.com/AriPerkkio"><code>@AriPerkkio</code></a> in <a href="https://redirect.github.com/vitest-dev/vitest/issues/10621">vitest-dev/vitest#10621</a> <a href="https://github.com/vitest-dev/vitest/commit/58577290a"><!-- raw HTML omitted -->(58577)<!-- raw HTML omitted --></a></li> </ul> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
3e23c5b960 |
chore(main): release 0.75.1 (#1091)
🤖 I have created a release *beep* *boop* --- ## [0.75.1](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.75.0...v0.75.1) (2026-09-05) ### Bug Fixes * restore session forks and speed up loading ([#1089](https://github.com/agentclientprotocol/claude-agent-acp/issues/1089)) ([v0.75.1 |
||
|
|
f5e79f55f8 |
fix: restore session forks and speed up loading (#1089)
## Summary - resolve AIR fork points from the complete persisted transcript when the target is outside the active parent chain - support message fingerprints and repeated assistant content when resolving persisted fork points - restore resumed models from the same local assistant transcript record Claude Code uses - remove all automatic `getContextUsage` control requests; use `compact_metadata.post_tokens` after compaction - add structured timing logs for fork, load, replay, and session creation phases ## Performance Cold-loading the reproduced 69-message forked session dropped from 20–29 seconds to 1.9 seconds. Transcript model lookup took 5 ms and replay took 14 ms; the remaining time was SDK initialization. ## Tests - `env -u ANTHROPIC_BASE_URL npm run test:run` (1230 passed, 27 skipped) - `npm run build` - `npm run lint` - Prettier check for all changed files - real ACP cold-load probe against the reproduced forked session |
||
|
|
a0122dae4c |
chore(main): release 0.75.0 (#1083)
🤖 I have created a release *beep* *boop* --- ## [0.75.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.74.0...v0.75.0) (2026-09-05) ### Features * **auth:** report the agent's auth identity over ACP (authStatus extension) ([#1080](https://github.com/agentclientprotocol/claude-agent-acp/issues/1080)) ([v0.75.0 |
||
|
|
20817678f6 |
feat: render usage statistics as Markdown (#1085)
## Summary - recognize Claude Code local /usage output - render subscription limits and MCP contributions as structured Markdown with progress bars - keep usage parsing and rendering in a dedicated module with unit coverage - preserve existing handling for other local commands and unknown future usage formats ## Testing - npm run check - npm run build - env -u ANTHROPIC_BASE_URL npm run test:run (1210 passed, 27 skipped) |
||
|
|
f74a51758d |
feat: surface context compaction as an ACP tool lifecycle (#991)
## Summary - surface Claude context compaction as a synthetic ACP tool lifecycle instead of assistant text - emit provider-neutral `_meta.contextCompaction` metadata with schema version 1 - handle status, stream heartbeat, compact-boundary, terminal-only, failure, and duplicate terminal event shapes - keep the generated compaction summary internal to the agent ## Protocol Compaction tool calls use `kind: "think"`, title `Compact conversation`, standard ACP lifecycle statuses, and optional metadata fields `trigger`, `preTokens`, `postTokens`, `durationMs`, and `error`. ## Testing - `npm run test:run` (769 passed, 26 skipped) - `npm run build` - `npm run check` |
||
|
|
eb5ca9fd17 | feat(auth): report the agent's auth identity over ACP (authStatus extension) (#1080) | ||
|
|
847a3b6429 | chore(main): release 0.74.0 (#1082) v0.74.0 | ||
|
|
da9f7e5695 |
feat(auth): refuse claude.ai subscriptions under --hide-claude-auth (#1079)
Stacked on #1071. The first three commits are that PR; review the last commit here. ## What `--hide-claude-auth` hid the claude.ai login method from `initialize`, but nothing stopped a session from billing a subscription that was already stored. This moves the decision into `src/hide-claude-auth.ts` with two layers: 1. Session creation refuses an account that holds no credential this integration accepts, so a logged-out session never exists. 2. A sign-out during the session ends the query. The next turn recreates it, so the next `initialize` reports the real account. A per-turn guard repeats the check on the account the SDK cached at `initialize`. It reads no process and costs microseconds. It covers a session created under a provider override that `providers/disable` later removed. "Bills a subscription" is an allowlist of `apiKeySource` values that outrank a stored subscription, so an unknown SDK value keeps the guard on. The guard fails open when the account cannot be read at all, and warns once per session. ## Client-visible additions (all additive) - The `authRequired` JSON-RPC error carries `data.reason: "claude_subscription_not_supported"` when the guard blocks a turn. Same error code and same message string as before. A plain sign-out still carries no `data`. - `PublishedSessionFailure` gains an optional `reason`, emitted in the failure `_meta` only when set. `hasActiveSessionError` matches on it, so the subscription refusal and a plain sign-out cannot suppress each other. ## Behavior changes not behind the flag - `providers/set` and `providers/disable` no longer reject the whole call when one session cannot be recreated. The session gets a per-session failure row, the switch goes on to the next session. The affected session is the one signal for that case; AIR never reaches it, because it sends `providers/set` only while a pooled client is created, before any session exists. - `authenticate` validates a gateway payload that is present. A call with no `_meta.gateway` keeps its historical meaning: no override, success. - A failed session creation closes the query it spawned instead of leaking the CLI process. ## Compatibility Checked against Zed and the JetBrains clients (`plugins/llm`, AIR main and stable). No consumer sends a gateway `authenticate` without a payload, none passes `--hide-claude-auth` by default, every one already handles the `auth_required` JSON-RPC rejection, and every `_meta` / error `data` parser ignores unknown fields. ## Test plan - `npm run build`, `npm run check`: clean. - `npm run test:run`: 1153 passed, 27 skipped. - New tests in `src/tests/authorization.test.ts` cover the guard end to end: creation refusal, per-turn refusal, sign-out respawn, provider override on/off, gateway payload validation, degraded guard. ## Follow-up commit in this PR - `fix(auth): start a fresh query when a signed-out session cannot be resumed` — when the CLI never persisted the session, `resume` answers `resourceNotFound`; the respawn now starts a fresh query under the same ACP session id instead of failing every later prompt. Tests after it: 1156 passed, 27 skipped. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> |
||
|
|
ea7076c0bc |
chore(main): release 0.73.0 (#1067)
🤖 I have created a release *beep* *boop* --- ## [0.73.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.72.0...v0.73.0) (2026-09-01) ### Features * **deps:** update Claude SDK ([#1066](https://github.com/agentclientprotocol/claude-agent-acp/issues/1066)) ([v0.73.0 |
||
|
|
b4e3aaa727 | feat(deps): update Claude SDK (#1066) | ||
|
|
d3eff19157 |
chore(main): release 0.72.0 (#1064)
🤖 I have created a release *beep* *boop* --- ## [0.72.0](https://github.com/agentclientprotocol/claude-agent-acp/compare/v0.71.0...v0.72.0) (2026-09-01) ### Features * **deps:** Update to @anthropic-ai/claude-agent-sdk 0.3.252 ([#1062](https://github.com/agentclientprotocol/claude-agent-acp/issues/1062)) ([v0.72.0 |