### Summary
Fixes#1158.
When a native subagent session is resumed for subsequent turn execution
(`task_started`), `this.parentByToolUse.get(task.toolUseId)` returns
`undefined` because `finishTask` deletes the mapping at the completion
of earlier generations. Because `knownParentSessionId` evaluated to
`undefined`, `if (knownParentSessionId || !task.toolUseId)` evaluated to
`false`, postponing the subagent announcement until `finishTask`.
### Changes
- In `src/native-subagents.ts`: Added fallback `const
knownParentSessionId = this.parentByToolUse.get(task.toolUseId) ??
previous?.parentSessionId;` so resumed subagents recognize their
existing session parent at `task_started`.
- In `src/tests/native-subagents.test.ts`: Added unit test confirming
`subagent_spawned` is emitted immediately upon `taskStarted` for resumed
sessions.
### Verification
- `npm test src/tests/native-subagents.test.ts` (all 8 tests passing).
- `npx tsc --noEmit` (clean, 0 type errors).
---------
Co-authored-by: shobhitagnihotri69 <shobhitagnihotri69@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>
Fixes#1167.
## Problem
In plan mode the model often runs Explore agents in the background. The
user turn's result then comes back while those agents are still running,
so `session/prompt` is held open (#864/#866). When an agent finishes,
the model writes the plan and calls `ExitPlanMode` in the
**task-notification followup**. The user accepts it with a clear-context
option.
The interrupted cycle's `[ede_diagnostic] … stop_reason=tool_use` result
carries that cycle's `task-notification` origin. That sends it into the
autonomous-result branch, which:
1. sends the `usage_update` with `_claude/origin: task-notification`.
This is the "background task finished at the same time" update from the
report; it's actually the same cycle.
2. settles the held turn with `end_turn` and returns early, before the
ExitPlanMode restart check runs.
The plan is never continued, the mode stays `plan`, and nothing tells
the client.
## Fix
- The diagnostic match now lives in one shared function,
`isExitPlanInterruptionResult()` in `exit-plan.ts`. Both the user-result
path and the new check call it; the user path behaves as before.
- In the autonomous branch, when the active turn is held and the result
is the recorded ExitPlanMode interruption:
- **Clear-context option:** drop the held turn's stored outcome, then
run the usual fresh-context restart. The fresh query doesn't have the
old background tasks, so the stale hold would otherwise settle the moved
turn with `end_turn` before the plan runs. The continuation's own result
settles the turn.
- **"No, keep planning":** settle `cancelled` with the user turn's own
usage, through `settleOrDefer`, so the turn stays open while other
spawned subagents are still running.
## Tests
There are two new tests in the deferred-settlement block. Each runs a
held turn whose task-notification followup calls `ExitPlanMode`: one for
the clear-context restart, one for keep-planning. The restart test also
fails if the held outcome isn't dropped.
## Known limitations (unchanged by this PR)
- **Background agents are killed by the restart.** Upstream `/clear`
keeps background agent tasks running (`hasAgentTaskSurvivingClear`). The
adapter's restart closes the old query, so any other running subagents
are killed, just as on the existing user-turn restart path.
- **Plans approved after the turn has ended are still dropped.** If
`ExitPlanMode` runs after the turn has already settled, there's no open
turn to continue, and the plan is dropped as before. A client-visible
notice for that case would be a follow-up.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
## Summary
- include the current assistant model id on `usage_update` notifications
as `model`
- mirror the same value in `_meta["_claude/model"]` so clients that
prefer extension metadata can consume it
- preserve existing `_meta` entries such as `_claude/origin` and
rate-limit metadata
Fixes#1021
## Verification
- `npm run build`
- `npm run check`
- `npm run test:run -- src/tests/acp-agent.test.ts -t
'usage_update|effective model|origin handling'`
- `npm run test:run` *(fails only in existing root-environment
`resolve-permission-mode` expectations: `bypassPermissions` falls back
to `default` when run as root; unrelated to usage updates)*
---------
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>
A warm `session/resume` or `session/load` currently ignores changed
`maxTurns` and `maxBudgetUsd`: the session fingerprint compares only cwd
and MCP servers, so the SDK query retains its old options. A client can
request a tighter limit and receive success while the old limit remains
active.
Include these two SDK execution limits in the session fingerprint.
Adding, changing or removing a limit recreates the query with the
supplied options and the same session ID. Identical limits reuse the
existing query; object key order does not trigger recreation. Budget
accounting across recreated SDK processes remains the client's
responsibility.
Validation:
- Four regression cases failed before the fix; six new cases cover both
methods, both limits, tightening/removal, and unchanged reuse.
- `npm run check` and `npm run build` passed.
- Focused suites: 551 passed, 9 skipped.
- Full suite with `--maxWorkers=2`: 1,240 passed, 27 skipped. An initial
unrestricted run hit one existing provider-switch test's 5s timeout and
macOS `EMFILE` watcher errors; bounding workers passed without changing
tests or timeouts.
Prepared while integrating typed runtime limits in
BinaryBourbon/fountain#1732. No live SDK budget-enforcement claim is
made by these adapter tests.
---------
Signed-off-by: Jake Gaylor <jhgaylor@gmail.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Synthetic usage-limit frames from the Claude SDK carry an all-zero usage
object. When one follows a real assistant response, the ACP bridge
currently overwrites the latest context measurement and emits a final
`usage_update` with `used: 0`.
Keep the previous measurement for a synthetic usage-limit frame when one
exists. A fresh quota-limited turn remains zero.
Includes a regression test covering a 170,910-token context followed by
a synthetic spend-limit frame.
Verified with:
- `npx vitest run src/tests/acp-agent.test.ts`
- `npm run check`
- `npm run build`
---------
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
## Summary
- keep `ANTHROPIC_VERTEX_BASE_URL` unset when `providers/set` selects
Vertex's native default endpoint
- retain explicit `ANTHROPIC_VERTEX_BASE_URL` only for custom Vertex
gateways/endpoints
- add a regression test for the default Vertex endpoint env mapping
Closes#1087
## Test Plan
- `npm run test:run -- src/tests/providers.test.ts` — passed (21 tests)
- `npm run check` — passed (`eslint src --ext .ts` + `prettier --check
.`)
- `npm run build` — passed (`tsc`)
- `git diff --check origin/main..HEAD` — passed
Note: `claude -p` delegation was attempted for candidate discovery but
this cron shell's Claude Code auth is not logged in (`Not logged in ·
Please run /login`), so the implementation/validation above was done
directly with local tests.
Signed-off-by: Emre K <110906681+kocaemre@users.noreply.github.com>
## Summary
- Fixes#1092 by treating `Please run /login` in a `success` result as
auth-required only when the result is actually error-shaped.
- Applies the same error-state guard to goal-command failure detection
so quoted login text in a normal answer does not roll back the active
goal.
- Adds a regression test for a successful model answer that mentions
`/login` without publishing a session failure.
## Test Plan
- [x] `npm run test:run -- src/tests/acp-agent.test.ts -t
'login|auth_required'`
- [x] `npm run build`
- [x] `npm run check`
- [ ] `npm run test:run` (blocked locally by pre-existing root
permission-mode assertions: `resolvePermissionMode("bypassPermissions")`
and `resolvePermissionMode("bypass")` resolve to `default` when running
as root)
Signed-off-by: Emre K <110906681+kocaemre@users.noreply.github.com>
## Summary
- allow the scheduled-wakeup live audit to wait through the full
minute-alignment window
- keep a small buffer for the autonomous model turn to complete
- raise the Vitest case timeout accordingly
`ScheduleWakeup(delaySeconds=60)` is persisted as a minute-aligned cron
entry. Depending on where scheduling lands within a minute, delivery can
take close to two minutes. The previous 75-second predicate timeout can
therefore fail even though the idle ACP stream delivers the wakeup
correctly. I reproduced both outcomes against current `main`: one run
timed out at 75 seconds, while a second run delivered `LIVE_WAKE_OK`
through the idle ACP stream.
Related: #838
## Verification
- `npm run check`
- `npm run build`
- `npm run test:run` (971 passed, 27 skipped)
- live SDK/ACP probe on Agent SDK 0.3.238 observed `SCHEDULED` followed
by autonomous `LIVE_WAKE_OK` while idle
## Summary
- reconstructs marker-only model-bound slash skill prompts during
history replay
- keeps client/local command metadata hidden when local stdout/stderr is
present
- adds regression coverage for both string and content-array transcript
shapes
Closes#998.
## Verification
- `npm run test:run -- src/tests/acp-agent.test.ts -t
'stripLocalCommandMetadata'`
- `npm run test:run -- src/tests/acp-agent.test.ts`
- `npm run build`
- `npm run check`
- `git diff --check`
I also ran `npm run test:run`. It completed with 965 passing tests, 27
skipped, and the same two root-environment `resolve-permission-mode`
failures seen when running as root: `bypassPermissions` is intentionally
downgraded to `default` in that environment. The changed replay/metadata
tests passed.
Signed-off-by: Emre Koca <1328630750+kocaemre@users.noreply.github.com>
Co-authored-by: Emre Koca <1328630750+kocaemre@users.noreply.github.com>
## 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#955
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>
## 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>
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>
## 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>
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.
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>
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>
## 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.
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="4919e0693e"><code>4919e06</code></a>
chore: Update CHANGELOG.md</li>
<li><a
href="e51cd0b1ba"><code>e51cd0b</code></a>
chore: Update CHANGELOG.md</li>
<li>See full diff in <a
href="https://github.com/anthropics/claude-agent-sdk-typescript/compare/v0.3.274...v0.3.276">compare
view</a></li>
</ul>
</details>
<br />
Updates `@types/node` from 26.5.1 to 26.6.1
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare
view</a></li>
</ul>
</details>
<br />
Updates `prettier` from 3.9.7 to 3.9.8
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.9.8</h2>
<ul>
<li>Markdown: Don't let Liquid objects interrupt paragraphs (<a
href="https://redirect.github.com/prettier/prettier/pull/20087">#20087</a>
by <a href="https://github.com/seiyab"><code>@seiyab</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.8/CHANGELOG.md#398">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.9.8</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.9.7...3.9.8">diff</a></p>
<h4>Markdown: Don't let Liquid objects interrupt paragraphs (<a
href="https://redirect.github.com/prettier/prettier/pull/20087">#20087</a>
by <a href="https://github.com/seiyab"><code>@seiyab</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="markdown"><code><!-- Input -->
If `module` is not a
[`WebAssembly.Module`](https://github.com/prettier/prettier/blob/main/en-US/docs/WebAssembly/Reference/JavaScript_interface/Module)
object instance, a
{{jsxref("TypeError")}} is thrown.
<p><!-- Prettier 3.9.7 -->
If <code>module</code> is not a <a
href="https://github.com/prettier/prettier/blob/main/en-US/docs/WebAssembly/Reference/JavaScript_interface/Module"><code>WebAssembly.Module</code></a>
object instance, a</p>
<p>{{jsxref("TypeError")}} is thrown.</p>
<p><!-- Prettier 3.9.8 -->
If <code>module</code> is not a <a
href="https://github.com/prettier/prettier/blob/main/en-US/docs/WebAssembly/Reference/JavaScript_interface/Module"><code>WebAssembly.Module</code></a>
object instance, a
{{jsxref("TypeError")}} is thrown.
</code></pre></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4f2ab6765d"><code>4f2ab67</code></a>
Release 3.9.8</li>
<li><a
href="3d82af8b15"><code>3d82af8</code></a>
Update Regex related dependencies (<a
href="https://redirect.github.com/prettier/prettier/issues/20082">#20082</a>)</li>
<li><a
href="5ec8db1745"><code>5ec8db1</code></a>
[3.9.x] Markdown: Don't let Liquid objects interrupt paragraphs (<a
href="https://redirect.github.com/prettier/prettier/issues/20087">#20087</a>)</li>
<li><a
href="5b142ed2bc"><code>5b142ed</code></a>
Release Release <code>@prettier/plugin-hermes</code><a
href="https://github.com/0"><code>@0</code></a>.2.3,
<code>@prettier/plugin-oxc</code><a
href="https://github.com/0"><code>@0</code></a>.2.3, an...</li>
<li><a
href="0df8eb86b5"><code>0df8eb8</code></a>
Bump Prettier dependency to 3.9.7</li>
<li><a
href="3cf6c8c058"><code>3cf6c8c</code></a>
Clean changelog_unreleased</li>
<li>See full diff in <a
href="https://github.com/prettier/prettier/compare/3.9.7...3.9.8">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/claude-agent-sdk-darwin-arm64` from 0.3.274 to
0.3.276
Updates `@anthropic-ai/claude-agent-sdk-darwin-x64` from 0.3.274 to
0.3.276
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64` from 0.3.274 to
0.3.276
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64-musl` from 0.3.274
to 0.3.276
Updates `@anthropic-ai/claude-agent-sdk-linux-x64` from 0.3.274 to
0.3.276
Updates `@anthropic-ai/claude-agent-sdk-linux-x64-musl` from 0.3.274 to
0.3.276
Updates `@anthropic-ai/claude-agent-sdk-win32-arm64` from 0.3.274 to
0.3.276
Updates `@anthropic-ai/claude-agent-sdk-win32-x64` from 0.3.274 to
0.3.276
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
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.
## 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>
## 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)
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)
## 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>
## 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>
## 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` (996d488);
`@agentclientprotocol/sdk` 1.3.0; Node 22. Noticed through Zed 1.16.1,
which does return
both fields, but the repro below is adapter-local and needs no client.
## Where the two fields diverge
`askUserQuestionsToCreateRequest` publishes, per question, two
**independent optional**
fields: `question_<n>` and `question_<n>_custom`. Neither is `required`,
and nothing in
the schema makes them exclusive. The
`_meta._askUserQuestionCustomAnswer` marker from #929
identifies the companion field's role (`{ questionId, isCustomAnswer }`)
— it doesn't ask a
client to clear the selection when the box is filled. So a client that
returns both is
doing nothing wrong, and the fold has no ground to keep only one of
them.
Before #774 the two coexisted: selections in `answers`, the custom text
in a separate
top-level `response` field. Scoping the custom answer per question
(fixing #770) turned
that coexistence into an overwrite:
```js
const custom = content[questionCustomFieldKey(index)];
if (typeof custom === "string" && custom.trim() !== "") {
answers[question.question] = custom.trim();
return; // <- selections discarded
}
```
For a **single-select** question replacing is right — the user typed an
answer instead of
picking one — and that stays. For a **multi-select** question the
options were never
mutually exclusive, so the typed answer should join them.
Restoring `response` isn't the alternative: it is a single form-level
field, so using it
for per-question custom answers would reintroduce exactly the collapse
#770 reported.
## Reproduction (no client, no model, no network)
```js
import { applyAskElicitationResponse } from "@agentclientprotocol/claude-agent-acp/dist/elicitation.js";
const q = [{ question: "Which features?", header: "F", multiSelect: true,
options: [{ label: "Alpha" }, { label: "Bravo" }] }];
const fold = (content) =>
applyAskElicitationResponse({ action: "accept", content }, { questions: q }, q)
.updatedInput.answers;
fold({ question_0: ["Alpha", "Bravo"] }); // { "Which features?": "Alpha, Bravo" } (control)
fold({ question_0: ["Alpha", "Bravo"], question_0_custom: "Charlie" });
// actual: { "Which features?": "Charlie" }
// expected: { "Which features?": "Alpha, Bravo, Charlie" }
```
## Change
Multi-select questions join the custom answer onto their selections;
single-select keeps
replacing. The selection normalization is deliberately untouched, so a
multi-select
question with a non-empty custom answer is the only input that folds
differently than
before. Comma-joining follows the documented shape of `answers`
("multi-select answers are
comma-separated"), which also means a label containing a comma stays
exactly as ambiguous
as it already was.
The `"Other"` box described itself as *"Type your own answer instead of
choosing an option
above"*; it now describes both roles, since for a multi-select question
it is no longer an
either/or.
---------
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
## 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`
## 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>
## 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)
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 labels
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.
## 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
## 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)
## 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`
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>
- Seed the Effort picker from the CLI's persisted per-model effort
(settings.modelSettings) with the legacy top-level effortLevel as
fallback, and stop pinning settings-derived seeds at the flag layer —
only explicit ACP picker choices pin effort now, so the CLI's own
per-model restore survives model switches.
- Re-seed effort from the new model's persisted entry on unpinned model
switches instead of dragging the old model's value along.
- Use the result's user_message_uuid (SDK 0.3.246+) as an exact join
key:
the empty-interruption diagnostic handler consumes exactly the token it
names (and no longer swallows a live turn's stamped failure), and
ensureActiveTurn consumes the named orphan / skips the dup-over-loss
one-skip when the stamp refutes it. Older producers keep the heuristics.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Currently, `package.json` allows zod version `3.x`. But
`agentclientprotocol/sdk` and our code use explicit `zod/v4` imports.
But `v4` became a proper ES module only in `4.x`. Before that, it was
just a directory. So if a user has zod 3.x, running this ACP server will
fail with `ERR_UNSUPPORTED_DIR_IMPORT`.
## Summary
- keep the standard latest-turn ACP fork behavior
- accept an optional AIR fork point at `_meta.jetbrains.air.fork`
- translate the ACP `messageId` to the Claude transcript UUID
- use the current Agent SDK `forkSession(..., { upToMessageId })` API
- resume the new SDK session with the same working directory and
additional directories
No Agent SDK dependency update is required. Version `0.3.238` already
provides the required API.
## Tests
- `npm run build`
- `npm run lint`
- `env -u ANTHROPIC_BASE_URL npm run test:run` — 981 passed, 27 skipped
## Summary
- negotiate native ACP subagent sessions and AIR async task support
- map Claude Agent/Task lifecycle to independent child session streams
- publish background workflow, monitor, MCP, and backgrounded shell work
as async tasks
- attach background shell tasks to their originating tool calls so
clients can update one command card and open its output log
- stream task progress and preserve running, paused, completed, failed,
and stopped states
- keep synchronous shell work, generic tools, and task notifications out
of user message chunks
- preserve typed session failures and root permission/elicitation
requests
- preserve the legacy generic Agent/Task representation and flattened
transcript opt-ins for clients without native subagent capability
## Compatibility
The published ACP SDK does not yet contain PR #1992 types, so the change
isolates the temporary structural cast in `src/acp-subagents.ts`.
Clients that do not negotiate native subagent sessions retain the
existing generic tool-call fallback, including the historical
`_meta["subagent-transcript"]` capability and `forwardSubagentText`
session option. Async tasks use the negotiated `asyncTasks` AIR
capability and remain invisible to clients that do not advertise it.
Claude does not expose a safe targeted child-cancel primitive, therefore
child `cancel` and `close` capabilities remain disabled.
## Validation
- `npm run check`
- `npm run build`
- `env -u ANTHROPIC_BASE_URL npm run test:run` (830 passed, 20 skipped)
- `npm run test:run -- src/tests/async-tasks.test.ts` (5 passed)
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
## Problem
The ACP steering extension injects follow-up user messages into a
running Claude SDK turn. Until now, every injected message used priority
`now`. That is normally desirable because it makes Claude react
immediately, but `now` is interrupting delivery: the SDK aborts the
currently running cycle before processing the new message.
This becomes unsafe while the SDK is blocked in a user-input callback,
such as a permission request or elicitation. Interrupting that cycle
makes the SDK send `$/cancel_request` for the pending ACP request. The
client then removes the permission/elicitation card before the user can
answer it. Depending on timing, the original ACP prompt can remain
pending because the callback and interrupted cycle no longer complete
through their normal lifecycle.
The failure sequence was:
1. Claude requests permission or opens an elicitation.
2. The ACP client displays a user-input card and waits for an answer.
3. The user sends a steering message while that card is still open.
4. The adapter injects the message with priority `now`.
5. The Claude SDK interrupts the cycle and emits `$/cancel_request` for
the open card.
6. The card disappears, and the original prompt may be left waiting
indefinitely.
## Fix
Track the number of permission/elicitation requests currently awaiting
user input for each session. Steering now selects its internal SDK
delivery priority as follows:
- `later` while at least one user-input request is pending, so the
steering message is queued without interrupting or cancelling the open
request;
- `now` at all other times, preserving the existing immediate steering
behavior.
The state is a counter rather than a boolean because multiple background
subagents can have concurrent permission requests. The `finally` cleanup
keeps the count correct for accepted, declined, cancelled, aborted, and
failed requests.
All ACP-backed user-input paths are covered:
- regular tool permission requests;
- the built-in `AskUserQuestion` form elicitation;
- MCP form/URL elicitations;
- refusal-fallback user dialogs.
## Regression coverage
Added parameterized tests that hold each user-input path open, inject a
steering message, and verify that the SDK message uses priority `later`.
The existing steering regression test continues to verify priority `now`
when no user input is pending. The tests also verify that the
pending-user-input state is cleared after the request settles.
Fixes IJAI-1191.
## Validation
- `npm run check`
- `npm run build`
- `env -u ANTHROPIC_BASE_URL npm run test:run` — 975 passed, 27 skipped
`ANTHROPIC_BASE_URL` was removed only for the test command because the
Codex environment injects a local proxy URL, while four provider tests
intentionally assert the native `https://api.anthropic.com` default.
## Summary
- translate Claude SDK permission suggestions and tool-specific
decisions into ACP v1 presentation and editable option metadata
- align Claude session permission modes and clear-context plan handling
- split permission effects, modes, normalization, option construction,
presentation, and response handling into focused modules
- document the permission extension and add unit plus live-audit
coverage for native edge cases
## Tests
- `npm run check`
- `npm run build`
- `env -u ANTHROPIC_BASE_URL npm run test:run` (931 passed, 27 skipped)
Bumps the minor group with 6 updates in the / directory:
| Package | From | To |
| --- | --- | --- |
|
[@anthropic-ai/claude-agent-sdk](https://github.com/anthropics/claude-agent-sdk-typescript)
| `0.3.232` | `0.3.233` |
| [@tsconfig/node22](https://github.com/tsconfig/bases/tree/HEAD/bases)
| `22.0.5` | `22.0.6` |
| [@hono/node-server](https://github.com/honojs/node-server) | `2.1.0` |
`2.1.1` |
| [@tsconfig/node10](https://github.com/tsconfig/bases/tree/HEAD/bases)
| `1.0.12` | `1.0.13` |
| [es-module-lexer](https://github.com/guybedford/es-module-lexer) |
`2.3.1` | `2.3.2` |
| [jose](https://github.com/panva/jose) | `6.2.8` | `6.2.9` |
Updates `@anthropic-ai/claude-agent-sdk` from 0.3.232 to 0.3.233
<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.233</h2>
<h2>What's changed</h2>
<ul>
<li>Notification hooks now fire for pending permission prompts on the
SDK path, matching the interactive REPL behavior</li>
<li>Todo/task-tracking tools
(<code>TaskCreate</code>/<code>TaskGet</code>/<code>TaskUpdate</code>/<code>TaskList</code>,
<code>TodoWrite</code>) are no longer in the default tool surface on
Opus 4.8, Sonnet 5, Fable 5, Mythos 5, and newer models; name them in
the <code>tools</code> option or reference them in
<code>allowedTools</code> (or set
<code>CLAUDE_CODE_ENABLE_TODO_TOOLS=1</code>) to keep them</li>
</ul>
<h2>Update</h2>
<pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.233
# or
yarn add @anthropic-ai/claude-agent-sdk@0.3.233
# or
pnpm add @anthropic-ai/claude-agent-sdk@0.3.233
# or
bun add @anthropic-ai/claude-agent-sdk@0.3.233
</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.233</h2>
<ul>
<li>Notification hooks now fire for pending permission prompts on the
SDK path, matching the interactive REPL behavior</li>
<li>Todo/task-tracking tools
(<code>TaskCreate</code>/<code>TaskGet</code>/<code>TaskUpdate</code>/<code>TaskList</code>,
<code>TodoWrite</code>) are no longer in the default tool surface on
Opus 4.8, Sonnet 5, Fable 5, Mythos 5, and newer models; name them in
the <code>tools</code> option or reference them in
<code>allowedTools</code> (or set
<code>CLAUDE_CODE_ENABLE_TODO_TOOLS=1</code>) to keep them</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="73a28abad0"><code>73a28ab</code></a>
chore: Update CHANGELOG.md</li>
<li>See full diff in <a
href="https://github.com/anthropics/claude-agent-sdk-typescript/compare/v0.3.232...v0.3.233">compare
view</a></li>
</ul>
</details>
<br />
Updates `@tsconfig/node22` from 22.0.5 to 22.0.6
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/tsconfig/bases/commits/HEAD/bases">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/claude-agent-sdk-darwin-arm64` from 0.3.232 to
0.3.233
Updates `@anthropic-ai/claude-agent-sdk-darwin-x64` from 0.3.232 to
0.3.233
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64` from 0.3.232 to
0.3.233
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64-musl` from 0.3.232
to 0.3.233
Updates `@anthropic-ai/claude-agent-sdk-linux-x64` from 0.3.232 to
0.3.233
Updates `@anthropic-ai/claude-agent-sdk-linux-x64-musl` from 0.3.232 to
0.3.233
Updates `@anthropic-ai/claude-agent-sdk-win32-arm64` from 0.3.232 to
0.3.233
Updates `@anthropic-ai/claude-agent-sdk-win32-x64` from 0.3.232 to
0.3.233
Updates `@hono/node-server` from 2.1.0 to 2.1.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/node-server/releases">@hono/node-server's
releases</a>.</em></p>
<blockquote>
<h2>v2.1.1</h2>
<h2>What's Changed</h2>
<ul>
<li>perf: lazily materialize request headers by <a
href="https://github.com/BlankParticle"><code>@BlankParticle</code></a>
in <a
href="https://redirect.github.com/honojs/node-server/pull/389">honojs/node-server#389</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/node-server/compare/v2.1.0...v2.1.1">https://github.com/honojs/node-server/compare/v2.1.0...v2.1.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="73c03adfb0"><code>73c03ad</code></a>
2.1.1</li>
<li><a
href="5515aa0a37"><code>5515aa0</code></a>
perf: lazily materialize request headers (<a
href="https://redirect.github.com/honojs/node-server/issues/389">#389</a>)</li>
<li>See full diff in <a
href="https://github.com/honojs/node-server/compare/v2.1.0...v2.1.1">compare
view</a></li>
</ul>
</details>
<br />
Updates `@tsconfig/node10` from 1.0.12 to 1.0.13
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/tsconfig/bases/commits/HEAD/bases">compare
view</a></li>
</ul>
</details>
<br />
Updates `es-module-lexer` from 2.3.1 to 2.3.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/guybedford/es-module-lexer/releases">es-module-lexer's
releases</a>.</em></p>
<blockquote>
<h2>2.3.2</h2>
<h2>What's Changed</h2>
<ul>
<li>perf(lexer): skip identifier and number runs by <a
href="https://github.com/BridgeAR"><code>@BridgeAR</code></a> in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/227">guybedford/es-module-lexer#227</a></li>
<li>fix: annotate asm.js integer return type by <a
href="https://github.com/Justineo"><code>@Justineo</code></a> in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/230">guybedford/es-module-lexer#230</a></li>
<li>Add side effects to package.json by <a
href="https://github.com/denisx"><code>@denisx</code></a> in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/183">guybedford/es-module-lexer#183</a></li>
<li>fix: forward the sourcename through the pre-init parse path by <a
href="https://github.com/hdimer"><code>@hdimer</code></a> in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/236">guybedford/es-module-lexer#236</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Justineo"><code>@Justineo</code></a>
made their first contribution in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/230">guybedford/es-module-lexer#230</a></li>
<li><a href="https://github.com/denisx"><code>@denisx</code></a> made
their first contribution in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/183">guybedford/es-module-lexer#183</a></li>
<li><a href="https://github.com/hdimer"><code>@hdimer</code></a> made
their first contribution in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/236">guybedford/es-module-lexer#236</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/guybedford/es-module-lexer/compare/2.3.1...2.3.2">https://github.com/guybedford/es-module-lexer/compare/2.3.1...2.3.2</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="08ee1be867"><code>08ee1be</code></a>
fix: forward the sourcename through the pre-init parse path (<a
href="https://redirect.github.com/guybedford/es-module-lexer/issues/236">#236</a>)</li>
<li><a
href="5a824a13a6"><code>5a824a1</code></a>
Update package.json (<a
href="https://redirect.github.com/guybedford/es-module-lexer/issues/183">#183</a>)</li>
<li><a
href="8274d0331a"><code>8274d03</code></a>
fix: annotate asm.js integer return type (<a
href="https://redirect.github.com/guybedford/es-module-lexer/issues/230">#230</a>)</li>
<li><a
href="2abc49eafc"><code>2abc49e</code></a>
perf(lexer): skip identifier and number runs (<a
href="https://redirect.github.com/guybedford/es-module-lexer/issues/227">#227</a>)</li>
<li>See full diff in <a
href="https://github.com/guybedford/es-module-lexer/compare/2.3.1...2.3.2">compare
view</a></li>
</ul>
</details>
<br />
Updates `jose` from 6.2.8 to 6.2.9
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/panva/jose/releases">jose's
releases</a>.</em></p>
<blockquote>
<h2>v6.2.9</h2>
<h3>Fixes</h3>
<ul>
<li>reject a JWE whose generated Key Management Parameters collide (<a
href="6ed19a6a97">6ed19a6</a>)</li>
<li><strong>types:</strong> undeprecate PBES2 p2c parameter (<a
href="33bf832986">33bf832</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/panva/jose/blob/main/CHANGELOG.md">jose's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/panva/jose/compare/v6.2.8...v6.2.9">6.2.9</a>
(2026-08-15)</h2>
<h3>Fixes</h3>
<ul>
<li>reject a JWE whose generated Key Management Parameters collide (<a
href="6ed19a6a97">6ed19a6</a>)</li>
<li><strong>types:</strong> undeprecate PBES2 p2c parameter (<a
href="33bf832986">33bf832</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f3a3c780b9"><code>f3a3c78</code></a>
chore(release): 6.2.9</li>
<li><a
href="33bf832986"><code>33bf832</code></a>
fix(types): undeprecate PBES2 p2c parameter</li>
<li><a
href="6ed19a6a97"><code>6ed19a6</code></a>
fix: reject a JWE whose generated Key Management Parameters collide</li>
<li><a
href="944840d167"><code>944840d</code></a>
ci: use shared release workflows</li>
<li><a
href="05bccf2399"><code>05bccf2</code></a>
chore: bump packages</li>
<li><a
href="f7392d1217"><code>f7392d1</code></a>
test: account for workerd nodejs_compat flag default changes</li>
<li><a
href="4e944be71e"><code>4e944be</code></a>
ci: drop the wait-for-npm machinery</li>
<li><a
href="4285b6f411"><code>4285b6f</code></a>
chore(deps-dev): bump undici</li>
<li><a
href="cb114ecde7"><code>cb114ec</code></a>
chore: cleanup after release</li>
<li>See full diff in <a
href="https://github.com/panva/jose/compare/v6.2.8...v6.2.9">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Claude Code's automatic title generation never runs under the Agent SDK,
so `SDKSessionInfo.summary` degrades to the raw first prompt — meaning
we were publishing up to 256 characters of the user's opening message as
the session title.
This PR asks the SDK for a real title instead. On the first completed
turn we send the `generate_session_title` control request with the
trailing 1000 characters of the session's own user + assistant text,
fired in the background off the `idle` handler so turn-end never waits
on the ~2 s small-model call, and publish the result through the
existing `session_info_update`.
A title is generated once per session, and any title already in the
session file — a user `/rename` or one we generated earlier, which the
SDK folds into the same field — is adopted rather than
overwritten.`persist: true` writes it to the transcript, so
`session/list` and `session/load` show the same name.
The SDK method is undeclared in `sdk.d.ts`, so it's called behind a
`typeof` check and a `try/catch` that degrades to the previous
behaviour.
### Problem
Provider routing is captured when the Claude SDK `Query` is created. As
a result, `providers/set` and `providers/disable` updated newly created
sessions but an already loaded ACP session continued using its previous
backend.
User and project Claude settings could also override the ACP-selected
URL or credentials after the subprocess environment was assembled,
making the configured proxy ineffective.
### Solution
- Serialize provider changes and wait for submitted turns to settle.
- Close and recreate every loaded SDK query with the same Claude session
ID, cwd, MCP configuration, and ACP creation parameters.
- Block new/load/resume/prompt requests only while a provider update is
in progress.
- Apply the active ACP route in both the subprocess environment and
programmatic settings tier.
- Clear competing Anthropic, Bedrock, Vertex, OAuth, API-key, and
`apiKeyHelper` routing while an ACP override is active; preserve
unrelated settings.
- Restore native/environment routing when the provider is disabled.
- Add opt-in routing diagnostics through `CLAUDE_AGENT_LOGS` without
logging request content or secret headers.
### Tests
Added coverage for:
- native behavior when Providers API is unused;
- live recreation of loaded sessions;
- waiting for active turns;
- multiple loaded sessions across native → proxy A → proxy B → native;
- user settings precedence and preservation of unrelated settings;
- Anthropic, Bedrock, Vertex, legacy gateway auth, and logout behavior.
Verification:
- `npm test`: 789 passed, 20 skipped
- `npm run build`
- `npm run check`
- `git diff --check`
---------
Co-authored-by: Junie <junie@jetbrains.com>
## Summary
- negotiate the opt-in AIR `_meta.jetbrains.air.agentFileChangeReport`
capability
- assign a unique `requestId` to each prompt and return canonical,
workspace-bounded changed paths in response metadata
- add a hidden Stop hook and an internal MCP reporting tool so Claude
can report files changed through shell commands, Git operations, and
generators
The audit is best-effort and is inactive unless the client advertises
the capability.
## Safety
- accept reports only for the active session and matching turn request
- canonicalize filesystem aliases, including `/tmp` to `/private/tmp` on
macOS
- reject paths outside the session working directory and deduplicate
valid paths
## Tests
- `npm run test:run`
- `npm run build`
- `npm run check`
## Summary
- align `_meta.jetbrains.air.sessionFailure` with AIR's
transcript-record protocol: `id`, `revision`, broad `category`, explicit
`severity`, `title`, optional `details`, and `actions`
- forward Claude's actual user-facing assistant/result text as `title`;
use adapter-authored fallback text only when Claude provides no message
(transport failure, worker EOF, or an internal invariant)
- reduce categories to `connection`, `access`, `limit`, `request`,
`service`, and `unknown`
- limit suggested actions to `retry`, `login`, and `new_session`
- update one transcript record through `id + revision`, keep resolved
entries in history, and remove clear/tombstone updates
- suppress duplicate assistant failure prose only for clients that
negotiated typed failures; preserve legacy ACP behavior otherwise
- restore synthetic usage-limit failures from session history with their
exact stored Claude text
- document negotiation, delivery carriers, identity/revision behavior,
mappings, recovery, and compatibility in the extension spec
## Validation
- `npm run check`
- `npm run build`
- `npm run test:run` — 777 passed, 26 skipped
- `git diff --check`
## Tracking
[IJAI-993](https://youtrack.jetbrains.com/issue/IJAI-993)
### Summary
- expose one `main` provider slot because Anthropic, Bedrock, and Vertex
routing are mutually exclusive
- advertise all three supported API types on that slot and replace the
active configuration on each `providers/set`
- restore native Claude routing when the slot is disabled
- keep provider headers out of list responses and preserve per-protocol
validation
### Testing
- `npm run test:run` (767 passed, 20 skipped)
- `npm run build`
- `npm run check`
Co-authored-by: Junie <junie@jetbrains.com>
## Problem
When the API refuses a turn, the SDK retries on the fallback model and
makes the swap persistent for the session. We flag that with a
transcript line:
```ts
text: `**Model fallback:** ${message.original_model} declined this request${category}; retried with ${message.fallback_model}. ${outcome}${explanation}`,
```
It goes out as an `agent_message_chunk`, so the client cannot tell a
session-level advisory from something the model actually said — the bold
label is the only severity signal available, and it is just characters
inside the assistant's own text.
The comment above that code already states the stakes: *"Without a
notice the user just sees regenerated output."* The notice matters; the
channel it uses does not fit it.
## Change
Routes it through the AIR typed session-failure extension instead, as a
new `advisory` category:
- `severity?: "error" | "warning"` on the record. **Optional, and absent
means `error`**, so a client that predates this keeps treating every
record it receives as a failure.
- The advisory carries its own wording (`safeMessage`) rather than the
canned per-category message, so the client renders the explanation
verbatim in a warning banner.
- **Clients that did not negotiate the `sessionFailure` capability keep
the exact transcript line they get today.**
### Advisories are not turn failures
Two existing behaviours would have mangled them, so both are now
guarded:
- `createSessionFailure` clears every other active record when a new one
is published. An advisory no longer does that, and is no longer cleared
by one — otherwise a model-fallback notice would erase an actionable
error, or vice versa.
- `clearFailuresFromEarlierTurns` clears everything whose `turnId` is
not the active turn. Advisories carry no `turnId`, so without the guard
every turn boundary would sweep them away.
They therefore live under their own `:notice:` id namespace,
session-scoped, one slot, newest wins.
## Scoped out
`**Fast mode turned off:**` (`syncFastMode…`) is the same pattern and
deserves the same treatment, but it sits in a class method while the
failure machinery is closure-scoped inside `prompt()`. Lifting that out
is a separate change rather than something to smuggle into this one.
## Tests
`npm run build`, `npm run check`, and `npm run test:run` (**766
passed**) are clean.
The existing `model_refusal_fallback` tests still assert the `**Model
fallback:**` transcript line and still pass — they never call
`initialize`, so they exercise the no-capability path, which is exactly
the backward-compatibility guarantee.
One test added for the typed path, asserting that the advisory is
published with `severity: "warning"`, that its `safeMessage` carries the
real model ids and refusal category, that it uses the `:notice:` id
namespace, that it contains no `**` markdown lead-in, and that the
transcript line is **not** also emitted.
Client side: IJAI-993.
## Summary
- Add `skill?: string` to `ToolUpdateMeta.claudeCode`, populated from
`toolUse.input.skill` in `claudeCodeMetaFromToolUse`. Lets ACP clients
detect skill invocations from structured metadata rather than parsing
the title string.
- Add `case "Skill":` to `toolInfoFromToolUse`: sets `title` to `"Load
skill: <name>"` and returns empty content — readable fallback for
clients that don't read `_meta`.
- Add `case "Skill":` to `toolUpdateFromToolResult`: returns `{}` to
suppress the raw `"Launching skill: <name>"` result text, matching the
pattern used for `Edit`/`Write`.
## Motivation
Without this, the Skill tool falls through to the `default` case and
renders as a generic `kind: "other"` block with title `"Skill"` and an
expand control showing the raw result text. With this change, clients
that read `_meta.claudeCode.skill` can render the block with the
appropriate icon, the skill name, and no expand control.
## Test plan
- [ ] Invoke a skill (e.g. `/commits`) and confirm
`_meta.claudeCode.skill` is present in the emitted `tool_call` update
- [ ] Confirm title is `"Load skill: commits"` in the ACP event stream
- [ ] Confirm no content is emitted for the skill tool result
## Summary
- When the SDK's `"default"` model entry carries a `resolvedModel` (e.g.
`"claude-sonnet-5"`), `buildConfigOptions` now sets the option's
`description` to the human-readable `displayName` of the matching named
model (e.g. `"Claude Sonnet 5"`)
- Falls back to the raw `resolvedModel` string if no named entry shares
that resolved ID
- No behaviour change when `resolvedModel` is absent
This lets ACP clients show the actual model behind "Default" — e.g.
"Default (Claude Sonnet 5)" — instead of just "Default (recommended)".
## Test plan
- [ ] `buildConfigOptions model option resolved description > sets
description to the named model's displayName when resolvedModel matches`
- [ ] `buildConfigOptions model option resolved description > falls back
to resolvedModel itself when no named model shares it`
- [ ] `buildConfigOptions model option resolved description > leaves
description undefined when default model has no resolvedModel`
- [ ] All 753 existing tests still pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
- Negotiate the JetBrains AIR `sessionFailure` extension when the client
advertises an integer version `>= 1` and the capability name.
- Return turn-terminal failures only on `PromptResponse._meta`; publish
idle and asynchronous session health failures through `session/update`.
- Preserve legacy ACP behavior for clients that do not negotiate the
extension.
- Emit bounded fixed safe messages without SDK/provider details, paths,
credentials, or stack traces.
## Recovery contract
Failures use `_meta.jetbrains.air.sessionFailure` with a stable id,
monotonic revision, phase, category, source, safe message, retryability,
and optional real turn attribution. Session-scoped ids include a
consumer epoch, so replayed tombstones from a dead consumer cannot
suppress failures after restart. Stale consumers cannot publish into a
replacement session.
AIR owns localized action presentation. Claude supplies typed category
and retryability facts. Billing maps to quota exhaustion, max-output
limits map to context exhaustion, and the irreversibly closed Claude
Query reports non-retryable `transport_lost` so AIR offers New Session.
A held-open turn keeps its already recorded successful `PromptResponse`,
while worker shutdown or transport death also emits a separate
session-scoped health failure without `turnId`; the next prompt is
proven to fail because the Query is closed. Worker-shutdown remains
armed through buffered trailing frames and is classified only when EOF
proves the live tail.
## Validation
- 750 passed, 25 skipped.
- Build passed.
- ESLint passed.
- Changed files pass Prettier; the repository-wide check is blocked only
by an unrelated untracked local proposal file.
- Tests cover negotiation, taxonomy, sanitization, terminal/asynchronous
carrier separation, stale consumers, worker replay/live-tail behavior,
held turns, process/transport failure, restart-safe ids, clear
revisions, and capability-off behavior.
## Summary
- show `Preparing file…` instead of the bare `Write` title while
streamed input has no `file_path`
- refine the same tool call to `Write <display path>` as soon as the
path is available
- cover both partial-field refinement and
complete-input/consolidated-message delivery
## Tests
- `npm run lint`
- `npx prettier --check src/tools.ts src/tests/acp-agent.test.ts`
- `npm run build`
- `npm run test:run` — 716 passed, 25 skipped
YouTrack: https://youtrack.jetbrains.com/issue/IJAI-841
## Summary
- republish unfinished Task* plan snapshots when a follow-up prompt
starts
- avoid resurfacing fully completed historical plans on unrelated
prompts
- clear stale task state when Claude starts a fresh conversation
- reconcile task state from authoritative TaskList results after resume
or history compaction
- consume structured Task* outputs during live sessions and parse Claude
Code textual output when replaying history
- reject logically failed TaskUpdate results instead of persisting the
requested mutation
- keep scanning structured tool output past unrelated JSON blocks
- use Claude activeForm for in-progress TodoWrite and Task* entries
This keeps ACP clients from losing an unfinished task list at prompt
boundaries, restores state when incremental history is unavailable, and
prevents plans from leaking across conversation resets.
## Tests
- npm run test:run (713 passed, 20 skipped)
- npm run check
- npm run build
- git diff --check
## Summary
- publish optimistic provider-neutral goal snapshots for submitted and
steered goal commands
- advertise and implement `set`, using steering for an active turn and
an ordinary prompt while idle
- suppress stale old-goal runtime updates while replacement/clear is
pending and roll back failed commands
- keep cancellation turn-scoped and orphan-account pending steers so
stale results cannot settle the next prompt
- reject unsupported pause/resume controls without host-side fallbacks
## Validation
- `npm test -- --run` (702 passed, 20 skipped)
- `npm run check`
- `npm run build`
- regression coverage for idle/active set and clear, stale runtime
updates, command failure rollback, cancellation, and stale steer
isolation
## Summary
- advertise a provider-neutral goal extension in
`InitializeResponse._meta.goal`
- map Claude SDK `active_goal` messages to
`session_info_update._meta.goal`
- expose the shared `_session/goal` control method with the truthfully
supported `clear` action
- document the extension as a candidate shape for a future first-class
ACP goal API
## Architecture
A goal is persistent **session state**, not the lifecycle of one
`session/prompt` request. `goal.status === "active"` says that the
objective may drive more work; it does not say that a prompt is
executing now.
This keeps two independent axes:
1. **Goal state** is published asynchronously as session metadata and
may survive multiple prompt turns.
2. **Prompt activity** follows the backend's actual running/quiescent
boundaries. While a turn runs, clients use advertised steering or prompt
queueing. Once the backend is quiescent, an ordinary `session/prompt` is
valid even if the goal remains active.
The metadata is deliberately provider-neutral:
```json
{
"_meta": {
"goal": {
"version": 1,
"controlMethod": "_session/goal",
"actions": ["clear"]
}
}
}
```
State is emitted as `session_info_update._meta.goal`; `null` clears it.
The common snapshot vocabulary supports `objective`, common statuses,
timestamps in Unix milliseconds, budgets/usage, iteration count, and a
continuation reason. Each implementation emits only fields it actually
knows. This shape is intentionally close to a future typed ACP
capability/update so promotion out of `_meta` would not require a
provider-specific migration.
Control actions are capability-negotiated. The shared vocabulary
reserves `set`, `pause`, `resume`, and `clear`, but an agent advertises
only the subset it can implement with correct semantics.
## Claude mapping
The Claude runtime already emits internal `active_goal` messages,
although that message is not currently included in the public
`SDKMessage` union. The adapter handles it before the exhaustive switch:
- `condition` → `objective`
- `iterations` → `iterations`
- `set_at` → `createdAt`
- `last_reason` → `lastReason`
- `value: null` → `goal: null`
Provider bookkeeping such as `tokens_at_start` is intentionally not
exposed. Goal updates do not settle, extend, or otherwise mutate ACP
prompt lifecycle. Claude's existing Stop hook remains authoritative for
whether the backend itself continues working.
Only `clear` is advertised for out-of-band control. It submits `/goal
clear` through the existing session prompt queue, preserving the
adapter's established ordering and turn ownership. Setting a goal
remains available through `/goal <condition>` but is not advertised as a
control action because it starts the long-running Stop-hook workflow.
The companion Codex implementation is agentclientprotocol/codex-acp#371.
## Verification
- `npm run test:run` — 692 passed, 20 skipped
- `npm run build`
- `npm run check`
Bumps the minor group with 1 update:
[globals](https://github.com/sindresorhus/globals).
Updates `globals` from 17.8.0 to 17.9.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/sindresorhus/globals/releases">globals's
releases</a>.</em></p>
<blockquote>
<h2>v17.9.0</h2>
<ul>
<li>Update globals (2026-08-01) (<a
href="https://redirect.github.com/sindresorhus/globals/issues/348">#348</a>)
5a958ed</li>
</ul>
<hr />
<p><a
href="https://github.com/sindresorhus/globals/compare/v17.8.0...v17.9.0">https://github.com/sindresorhus/globals/compare/v17.8.0...v17.9.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8e7b9358b1"><code>8e7b935</code></a>
17.9.0</li>
<li><a
href="5a958ed060"><code>5a958ed</code></a>
Update globals (2026-08-01) (<a
href="https://redirect.github.com/sindresorhus/globals/issues/348">#348</a>)</li>
<li>See full diff in <a
href="https://github.com/sindresorhus/globals/compare/v17.8.0...v17.9.0">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Steering is delivered at priority `now`, which makes the CLI **abort**
the running cycle instead of folding the message into it. The aborted
cycle ends with an ordinary human-origin `result`, so we answered
`session/prompt` with `end_turn` while the steered work was still going
— its remaining tool calls, its answer, and its file edits then streamed
with no turn in flight.
A steered turn's results now only record their outcome, and the turn
settles at the SDK's `idle` — the only signal spanning both the
interrupted and the steered cycle. The injected message's replay tells
them apart: an idle arriving before it means the steered cycle hasn't
started, so it is swallowed. `session/cancel` and the next prompt still
settle the turn early, with the recorded stop reason.
Four steering tests cover the interrupt, an early idle, the next-prompt
hand-off, and cancel.
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.16 to 3.3.17.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ai/nanoid/releases">nanoid's
releases</a>.</em></p>
<blockquote>
<h2>3.3.17</h2>
<ul>
<li>Fixed infinite loop on zero size.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ai/nanoid/blob/main/CHANGELOG.md">nanoid's
changelog</a>.</em></p>
<blockquote>
<h2>3.3.17</h2>
<ul>
<li>Fixed infinite loop on zero size.</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="73d6716813"><code>73d6716</code></a>
Release 3.3.17 version</li>
<li><a
href="f9d13f1508"><code>f9d13f1</code></a>
Sync 0 size behaviour with PostCSS 5</li>
<li>See full diff in <a
href="https://github.com/ai/nanoid/compare/3.3.16...3.3.17">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Description
Testing this agent means wiring it into an editor's ACP integration,
which is an overkill when you just want to watch the JSON and reply with
JSON. This adds a second example next to `examples/steering.ts`: a
minimal interactive ACP client that spawns the built agent, prints every
JSON-RPC message in both directions, and turns what you type into
prompts.
```
npm run build
npm run example:simple-client
```
All four ways a client can get a message to this agent are reachable
from the prompt"
| Input | Wire |
| --- | --- |
| `<text>` | `session/prompt`; buffered client-side if a turn is running
|
| `!steer <text>` | `_session/steering`, injected into the running turn
|
| `!queue <text>` | `session/prompt` sent mid-turn, so the agent queues
it |
| `!cancel`, Ctrl-C | `session/cancel` |
## Additional options
* `--debug-port=<port>` rebuilds with source maps and starts the agent
under
* `--inspect-brk`, paused, so a debugger can attach and step through
`src/*.ts` —
replacing a hand-written editor run configuration. Teardown cancels any
live
turn, closes the agent's stdin (its clean-exit path), waits, and only
then
closes the connection, so neither side dies of EPIPE and nothing is
orphaned.
npm may accept a package before the registry update stage can run, and
repeating the workflow would attempt to republish the same immutable
version.
Add an opt-out for npm publishing on manual dispatch so the repository
GitHub App can safely retry only the registry update. The default
remains `true`, preserving the normal manual release path.
Validation: Prettier workflow check.
A skipped `release-please` job propagates to downstream jobs during a
manual release, even when npm publishing succeeds through an `always()`
condition.
Explicitly evaluate the npm job result so successful manual publications
continue to update the agent registry.
Validation: Prettier workflow check.
Release-please cannot process the already-merged, untagged release PR
#943.
This adds an explicit workflow dispatch path for publishing a supplied
tag or commit while preserving the normal push-driven release flow, and
restores the 0.64.2 release metadata for the recovery tag.
After merge, I will create `v0.64.2` at this commit and dispatch the
publish workflow for that tag.
Validation:
- ESLint
- Prettier
- TypeScript build
- Vitest: 684 passed, 20 skipped
## Summary
- revert the ExitPlanMode plan_update integration from #938
- restore the previous single switch_mode tool-call representation
- keep plan Markdown and approval state on the same transcript item
## Why
Clients currently receive both a plan_update and the separate tool call
required by requestPermission. Without a protocol-level link between
those entries, clients can render the same final plan twice. Returning
to the legacy representation avoids the duplicate while preserving the
existing approval flow.
## Testing
- pnpm exec vitest run src/tests/tools.test.ts
src/tests/acp-agent.test.ts src/tests/session-config-options.test.ts
(482 passed, 9 skipped)
- pnpm run build
- pnpm run lint
- pnpm run format:check
## Summary
- publish `ExitPlanMode` Markdown through experimental ACP `plan_update`
when the client advertises `clientCapabilities.plan`
- keep `requestPermission` as the confirmation mechanism and retain
`rawInput.plan` on the `switch_mode` tool call
- fall back to the existing tool-call content for clients without plan
support
- serialize live plan publication through the permission path so
`plan_update` and the referenced `tool_call` are delivered before
`requestPermission`
- use stable per-scope plan IDs so main-agent and subagent plans cannot
overwrite each other
- replay capable-client plans through `plan_update` without duplicating
Markdown in tool content
## Testing
- permission-first and stream-first event ordering
- approve, reject, and cancel outcomes
- capable-client Markdown payload and legacy fallback
- empty plan suppression, replay, deduplication, and subagent plan IDs
- `vitest run` (697 passed, 20 skipped)
- `tsc --noEmit`
- ESLint and Prettier on changed files
## Summary
Expose Claude Code permission-update suggestions through the same
versioned option-level metadata contract used by other ACP agents:
```json
{
"_meta": {
"permission": {
"version": 1,
"changes": []
}
}
}
```
The approval actions are presented as `Deny`, `Allow Once`, and `Always
Allow`. Exact scope and policy details live in metadata instead of being
encoded into the button label.
## Why
ACP already transports button semantics via `PermissionOption.kind`,
display text via `name`, and the selected value via `optionId`. It does
not currently expose the exact persistent policy update.
Claude Code suggestions can do considerably more than add one allow
rule: they may add, remove, or replace allow/deny/ask rule sets, add or
remove directories, change permission mode, and target different storage
destinations. Flattening those suggestions into labels or a list of
scopes loses mutation semantics and can incorrectly describe a narrow or
restrictive update as permission for the whole tool.
## Contract
Every change carries a producer-supplied human-readable `description`.
Structured fields preserve:
- ordered `add`, `remove`, and atomic `replace` operations
- `allow`, `deny`, and `ask` rule sets through `ruleBehavior`
- whole-tool targets and provider-rule matchers
- filesystem directory targets
- permission-mode changes
- session, process, user, project, and project-local destinations as
lifetime/storage
Example scoped Bash rule:
```json
{
"type": "policy_rule",
"operation": "add",
"ruleBehavior": "allow",
"description": "Allow Bash calls matching npm test:*",
"lifetime": { "scope": "session" },
"targets": [
{
"type": "tool",
"toolName": "Bash",
"matcher": {
"type": "provider_rule",
"provider": "claudeCode",
"value": "npm test:*"
}
}
]
}
```
A tool target without a matcher means the whole tool. A provider rule is
intentionally opaque; clients should show `description` rather than
reverse-engineering Claude Code rule syntax.
When Claude Code supplies no suggestions, the adapter preserves its
existing fallback behavior by describing the exact session rule it
returns: allow the whole requested tool for the session.
## Compatibility
This remains on the current ACP protocol and uses only `_meta`. Clients
that do not understand `_meta.permission` continue rendering and
dispatching the standard options. Option IDs and permission outcomes are
unchanged.
## Tests
- full suite: 682 passed, 20 skipped
- lint passed
- Prettier check passed
- TypeScript build passed
- coverage includes whole-tool fallback, scoped rules, directories,
replace/remove, deny rules, destinations, and mode changes
## Why
AskUserQuestion emits a per-question free-text field that should be
rendered as the custom-answer companion for the preceding select
question. ACP clients need a stable metadata marker for that
relationship instead of guessing from field ids, titles, or
descriptions.
## What changed
- Mark each AskUserQuestion custom-answer companion field with
`_meta._askUserQuestionCustomAnswer`.
- Use the same non-agent-specific key that Codex and other bridges can
emit, so clients can parse one shared marker instead of maintaining
per-agent metadata names.
- Keep the existing response folding behavior unchanged.
## Tests
- Updated `includes a per-question optional free-text custom-answer
field` to assert the shared `_askUserQuestionCustomAnswer` marker on
each companion field.
```sh
npm test -- src/tests/elicitation.test.ts
```
`permission_denied` forwarded an SDK frame as a `tool_call_update`
without checking that the referenced `tool_call` was ever announced,
leaving it the last emitter without that check after #916.
The id is the executing call's own, and the frame is enqueued from
inside canUseTool, so it lands between the call's `tool_use` and the
`tool_result` carrying the rejection — verified against the bundled CLI,
where the deny short-circuit only emits for pre-ask decisions (rules,
mode, classifier, asyncAgent) and fires exactly once per denial. In that
flow the call is announced and in flight, so the guard changes nothing.
It changes the denials that arrive outside that window. The
cancelled-turn guard drops the assistant message carrying the tool_use,
so no `tool_call` is emitted, and a denial for it can still land
afterwards — the same premise the `tool_result` fallback in
`toAcpNotifications` gates on `wasEmitted` for. Ids leave
`emittedToolCalls` at `tool_result`, so the check also stops a denial
trailing its own result from flipping a call the client has seen finish
back to failed.
While here: a denial raised inside a subagent identifies it by
`agent_id`, never by the Agent/Task call that spawned it, so the update
went out unattributed while the `tool_call` it resolves sits in the
subagent's transcript. Resolve the parent through `liveBackgroundTasks`,
as the canUseTool path already does, and leave the update unattributed
rather than dropped when `task_started` was never seen for that agent
id.
`permission_denied` had no test coverage. Add cases for the in-flight
resolve, the reason fallback, the never-announced and already-resolved
drops, and subagent attribution with and without a recorded parent.
Fixes#918
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Heartbeat beats reach the bridge under a derived
`<tool_use_id>-heartbeat-<n>` id that no `tool_call` was ever emitted
for, and the handler forwarded it verbatim. Clients that expect a
`tool_call_update` to reference a tool call they have been told about
saw a reference they could not resolve, and since the counter makes
every beat a fresh id, nothing deduplicated them: a ten-minute Bash call
produced roughly twenty phantom entries. Zed renders each as a failed
"Tool call not found" card; compozy/compozy#257 and
agent-of-empires/agent-of-empires#3084 report the same shape.
Strip the derived suffix so the beat is reported against the call it
describes, and drop it when that call is not in `emittedToolCalls`. Ids
enter that set at `tool_use` and leave it at `tool_result`, so the guard
covers both an id that was never announced and a straggling beat that
races past completion, which would otherwise flip a call the client has
seen finish back to `in_progress`.
The SDK sets `heartbeat: true` on these messages, but that flag alone
cannot recover the original id, and `parent_tool_use_id` is the subagent
parent rather than the call being reported on, so the suffix still has
to be stripped.
`tool_progress` had no test coverage. Add cases for the retarget across
a climbing counter, the not-in-flight drop, meta pass-through, and an
unsuffixed id being left alone.
Fixes#913
---------
Signed-off-by: Daan De Meyer <daan@amutable.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
## Problem
The `Bash` branch of `toolUpdateFromToolResult` derives its terminal id
from the result block and falls back to the empty string:
```ts
const terminalId = "tool_use_id" in toolResult ? String(toolResult.tool_use_id) : "";
```
On that fallback it still emits the whole terminal payload — `content:
[{ type: "terminal", terminalId: "" }]` plus `terminal_info`,
`terminal_output` and `terminal_exit`, every one keyed on `""`.
No client has a terminal under that id. `toolInfoFromToolUse` announces
the terminal as `toolUse.id` (`src/tools.ts:161`), so the empty id
matches nothing that was created. A client that buffers output for
terminals it has not been told about then holds the data indefinitely
behind an id that never arrives — Zed keeps it in
`pending_terminal_output` / `pending_terminal_exit` and drains only on a
matching create — so the command's output is silently stranded and the
user is left looking at an empty terminal.
It fails quietly, which is what makes it worth fixing: nothing logs, and
the update looks well-formed on the wire.
## Change
Prefer `toolUse.id` — the id that was actually announced — and keep the
result block's `tool_use_id` as a fallback. The two agree whenever both
are present, since the caller looks the tool_use up by that id, so this
only changes behaviour when one is missing.
When neither yields an id, fall through to the code-block rendering that
already exists immediately below rather than emitting a terminal
reference the client cannot resolve.
## Tests
Three cases added to `src/tests/tools.test.ts`:
- metas are keyed off the tool_use id even when the result block
disagrees
- the result block's `tool_use_id` is still used when the tool_use is
unavailable
- no id at all degrades to the `console` code block, with no `_meta`
Two of the three fail on `main` and pass with the change; the third
guards the preserved fallback. `npm run build`, `npm run check` and
`vitest run src/tests/tools.test.ts` (112 passed) are clean.
Note: `src/tests/create-session-options.test.ts > session/load seeds the
window from the resumed session's getContextUsage report` fails on a
clean `main` checkout here too — pre-existing and unrelated.
## How I got here
Found while tracing the "Tool call not found" rows in #913 — unrelated
cause, same file. The `terminal_id: ""` path came up while ruling the
terminal-streaming path out as the source of those.
---------
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
## Motivation
ACP clients currently have two gaps when rendering Claude Code activity:
1. Bash tool calls expose the shell command as the standard ACP title,
but the concise human-readable `description` produced by Claude Code is
lost.
2. ACP 1.2 has no standard subagent tool kind or nested-message
relationship, so subagent prose and child tools are either flattened
into the main conversation or filtered out entirely.
This PR adds namespaced metadata and an explicit client capability so
richer clients can render both cases without changing the standard ACP
schema or regressing legacy clients.
## What changed
### Bash descriptions
- Keeps the shell command in the standard ACP `title`, preserving
command-oriented clients.
- Exposes the optional Claude Code Bash `description` as
`_meta.claudeCode.title`.
- Applies the metadata consistently to eager permission tool calls,
normal tool calls, and streamed input refinements.
- Falls back to the command title when no description is available.
### Nested subagent transcripts
- Adds the opt-in client capability
`clientCapabilities._meta["subagent-transcript"] = true`.
- Enables the Claude Agent SDK `forwardSubagentText` option when the
client advertises support.
- Preserves the pre-existing caller-provided `forwardSubagentText: true`
option for compatibility.
- Marks Agent and legacy Task launches with `_meta.claudeCode.subagent =
true`.
- Relates nested text, thinking, and child tool calls to the launching
Agent/Task call through `_meta.claudeCode.parentToolUseId`.
- Preserves parent attribution during session-history replay, not only
during live streaming.
- Handles nested Agent-to-Agent launches without inferring subagents
from the generic ACP `think` kind.
## Compatibility
Clients that do not advertise `subagent-transcript` retain the previous
behavior: subagent text and thinking remain filtered from the top-level
feed.
The normal Agent/Task tool result is still emitted in every mode as the
protocol-compatible fallback. No existing result or standard ACP field
is removed or redefined.
## Validation
- `npm run build`
- `npm run check`
- `npm run test:run`
- 623 tests passed, 20 skipped
Coverage includes live and replayed nested text/thinking, child tool
attribution, Agent/Task launch markers, nested Agent launches, legacy
filtering, and SDK-option compatibility.
Bumps [@hono/node-server](https://github.com/honojs/node-server) from
1.19.14 to 1.19.15.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/honojs/node-server/commits">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps the minor group with 2 updates:
[@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript)
and [hono](https://github.com/honojs/hono).
Updates `@anthropic-ai/sdk` from 0.113.0 to 0.114.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/anthropics/anthropic-sdk-typescript/releases">@anthropic-ai/sdk's
releases</a>.</em></p>
<blockquote>
<h2>sdk: v0.114.0</h2>
<h2>0.114.0 (2026-07-23)</h2>
<p>Full Changelog: <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.113.0...sdk-v0.114.0">sdk-v0.113.0...sdk-v0.114.0</a></p>
<h3>Features</h3>
<ul>
<li><strong>api:</strong> add new stop reason
'model_context_window_exceeded' (<a
href="1ec71c165d">1ec71c1</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/anthropics/anthropic-sdk-typescript/blob/main/CHANGELOG.md">@anthropic-ai/sdk's
changelog</a>.</em></p>
<blockquote>
<h2>0.114.0 (2026-07-23)</h2>
<p>Full Changelog: <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.113.0...sdk-v0.114.0">sdk-v0.113.0...sdk-v0.114.0</a></p>
<h3>Features</h3>
<ul>
<li><strong>api:</strong> add new stop reason
'model_context_window_exceeded' (<a
href="1ec71c165d">1ec71c1</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2d314b4127"><code>2d314b4</code></a>
chore: release main</li>
<li><a
href="3d051dfe49"><code>3d051df</code></a>
feat(api): add new stop reason 'model_context_window_exceeded'</li>
<li>See full diff in <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.113.0...sdk-v0.114.0">compare
view</a></li>
</ul>
</details>
<br />
Updates `hono` from 4.12.31 to 4.12.32
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/hono/releases">hono's
releases</a>.</em></p>
<blockquote>
<h2>v4.12.32</h2>
<h2>What's Changed</h2>
<ul>
<li>ci: enable reports for type & bundle size check in <a
href="https://redirect.github.com/honojs/hono/pull/5148">honojs/hono#5148</a></li>
<li>fix(aws-lambda): add jwt and lambda authorizer types for API Gateway
v2 in <a
href="https://redirect.github.com/honojs/hono/pull/5142">honojs/hono#5142</a></li>
<li>fix(sse): emit empty id field to reset Last-Event-ID in <a
href="https://redirect.github.com/honojs/hono/pull/5138">honojs/hono#5138</a></li>
<li>test(cloudflare-workers): add coverage for onClose, onError, send,
and close in Cloudflare Workers websocket adapter in <a
href="https://redirect.github.com/honojs/hono/pull/5145">honojs/hono#5145</a></li>
<li>fix: use <code>Object.create(null)</code> when parsing query,
headers, and params in <a
href="https://redirect.github.com/honojs/hono/pull/5161">honojs/hono#5161</a></li>
<li>fix(secure-headers): keep CSP callbacks scoped to their header in <a
href="https://redirect.github.com/honojs/hono/pull/5147">honojs/hono#5147</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.12.31...v4.12.32">https://github.com/honojs/hono/compare/v4.12.31...v4.12.32</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="26d8e42bff"><code>26d8e42</code></a>
4.12.32</li>
<li><a
href="402eb3abe5"><code>402eb3a</code></a>
fix(secure-headers): keep CSP callbacks scoped to their header (<a
href="https://redirect.github.com/honojs/hono/issues/5147">#5147</a>)</li>
<li><a
href="c85aead088"><code>c85aead</code></a>
fix: use <code>Object.create(null)</code> when parsing query, headers,
and params (<a
href="https://redirect.github.com/honojs/hono/issues/5161">#5161</a>)</li>
<li><a
href="a88c89dac6"><code>a88c89d</code></a>
test(cloudflare-workers): add coverage for onClose, onError, send, and
close ...</li>
<li><a
href="44f884321a"><code>44f8843</code></a>
fix(sse): emit empty id field to reset Last-Event-ID (<a
href="https://redirect.github.com/honojs/hono/issues/5138">#5138</a>)</li>
<li><a
href="e36f57dac0"><code>e36f57d</code></a>
fix(aws-lambda): add jwt and lambda authorizer types for API Gateway v2
(<a
href="https://redirect.github.com/honojs/hono/issues/5142">#5142</a>)</li>
<li><a
href="bf8608cb77"><code>bf8608c</code></a>
ci: enable reports for type & bundle size check (<a
href="https://redirect.github.com/honojs/hono/issues/5148">#5148</a>)</li>
<li>See full diff in <a
href="https://github.com/honojs/hono/compare/v4.12.31...v4.12.32">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
## Summary
`session/new` and switching models via `configOptions` regressed to ~15s
each in v0.59.0. This removes the blocking call responsible and seeds
the context window synchronously instead, restoring sub-second behavior
on both paths.
## Root cause
v0.59.0 added an inline `await query.getContextUsage()` on the
session-creation and model-switch paths. That SDK control request is not
serviced by the CLI until the session's first prompt turn has run —
before then it stalls ~15s. And because SDK control requests are
serialized over a single stdin/stdout channel, an awaited `setModel`
queued behind the wedged `getContextUsage` inherited the full stall. So
both paths blocked ~15s before returning.
Verified with the real CLI (setModel alone pre-prompt: ~1ms;
getContextUsage alone pre-prompt: ~16s; getContextUsage-then-setModel:
both resolve together at ~16s, confirming the serialization).
## Fix
Drop `getContextUsage` from both hot paths. The context window is seeded
synchronously by `immediateContextWindow(...)`:
1. an authoritative value from a per-(provider, model) cache, if
learned; else
2. a synchronous text heuristic (`\b1m\b` → 1,000,000); else
3. `DEFAULT_CONTEXT_WINDOW` (200,000).
The authoritative window is learned the moment it's actually available —
from each turn's `result.modelUsage` — and written into the cache, so
later sessions/switches to the same model seed the correct window
immediately with no IPC. A model that has never run a turn shows the
heuristic/default window until its first response, matching pre-0.59.0
behavior.
### Cache design
- **Keyed on `(provider, resolved model id)`.** The resolved id
(`ModelInfo.resolvedModel`, e.g. `claude-sonnet-5[1m]`) matches the
`result.modelUsage` keys, so the write key and the read keys line up.
Keying on the resolved id (not the picker value) dedups aliases that
resolve to the same model; keying on the provider keeps two providers
that reuse an id string for different windows from crossing wires
(per-session provider config, #853). The provider is captured at session
creation, since the effective provider can change process-wide over the
adapter's lifetime.
- **Non-positive/NaN windows are ignored** — they neither overwrite the
session's learned window nor enter the cache.
## Impact (measured, real CLI)
| Path | Before | After |
| --- | --- | --- |
| `session/new` | ~17.4s | ~0.9s |
| model switch (before first prompt) | ~15s | ~3ms |
| model switch (after a turn) | ~14.7s | <1ms |
## Tests
- New end-to-end cache test: a turn's authoritative window (learned
under the resolved id even when the assistant message reports the bare
id) is served on a later switch with no `getContextUsage`.
- New provider-isolation test: the same resolved id on a different
provider does not read another provider's cached window; the same
provider does.
- New non-positive-window test: a nonsensical `contextWindow` is ignored
and never poisons the cache.
- Rewrote the existing context-window tests to the new contract (assert
no `getContextUsage` on session/new and switch; window from
cache/inference/default).
Closes#886Closes#880🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
## Summary
Closes:
https://github.com/agentclientprotocol/claude-agent-acp/issues/878
Fixes the potential ReDoS warning reported by CodeQL in
`stripAgentTrailer()`.
- Replaces regex-based trailer stripping with bounded linear parsing
- Preserves valid `<usage>…</usage>` and `agentId: … (…)` trailer
handling
- Adds coverage for malformed trailers, which are left unchanged
## Testing
- `npm test -- --run src/tests/tools.test.ts`
---------
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bumps the minor group with 14 updates:
| Package | From | To |
| --- | --- | --- |
|
[@anthropic-ai/claude-agent-sdk](https://github.com/anthropics/claude-agent-sdk-typescript)
| `0.3.206` | `0.3.207` |
|
[@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript)
| `0.110.0` | `0.111.0` |
| [eslint](https://github.com/eslint/eslint) | `10.6.0` | `10.7.0` |
| @anthropic-ai/claude-agent-sdk-darwin-arm64 | `0.3.206` | `0.3.207` |
| @anthropic-ai/claude-agent-sdk-darwin-x64 | `0.3.206` | `0.3.207` |
| @anthropic-ai/claude-agent-sdk-linux-arm64 | `0.3.206` | `0.3.207` |
| @anthropic-ai/claude-agent-sdk-linux-arm64-musl | `0.3.206` |
`0.3.207` |
| @anthropic-ai/claude-agent-sdk-linux-x64 | `0.3.206` | `0.3.207` |
| @anthropic-ai/claude-agent-sdk-linux-x64-musl | `0.3.206` | `0.3.207`
|
| @anthropic-ai/claude-agent-sdk-win32-arm64 | `0.3.206` | `0.3.207` |
| @anthropic-ai/claude-agent-sdk-win32-x64 | `0.3.206` | `0.3.207` |
| [es-module-lexer](https://github.com/guybedford/es-module-lexer) |
`2.3.0` | `2.3.1` |
| [hono](https://github.com/honojs/hono) | `4.12.29` | `4.12.30` |
| [postcss](https://github.com/postcss/postcss) | `8.5.16` | `8.5.19` |
Updates `@anthropic-ai/claude-agent-sdk` from 0.3.206 to 0.3.207
<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.207</h2>
<h2>What's changed</h2>
<ul>
<li>Fixed <code>canUseTool</code> returning <code>{behavior:
'allow'}</code> without <code>updatedInput</code> being rejected as a
deny with a raw ZodError message; the tool now runs with the original
input per the documented contract</li>
<li>The Agent tool's structured result now has a published SDK type
(<code>AgentToolCompletedOutput</code>) that matches the emitted object
exactly</li>
</ul>
<h2>Update</h2>
<pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.207
# or
yarn add @anthropic-ai/claude-agent-sdk@0.3.207
# or
pnpm add @anthropic-ai/claude-agent-sdk@0.3.207
# or
bun add @anthropic-ai/claude-agent-sdk@0.3.207
</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.207</h2>
<ul>
<li>Fixed <code>canUseTool</code> returning <code>{behavior:
'allow'}</code> without <code>updatedInput</code> being rejected as a
deny with a raw ZodError message; the tool now runs with the original
input per the documented contract</li>
<li>The Agent tool's structured result now has a published SDK type
(<code>AgentToolCompletedOutput</code>) that matches the emitted object
exactly</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="79b6350e13"><code>79b6350</code></a>
chore: Update CHANGELOG.md</li>
<li>See full diff in <a
href="https://github.com/anthropics/claude-agent-sdk-typescript/compare/v0.3.206...v0.3.207">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/sdk` from 0.110.0 to 0.111.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/anthropics/anthropic-sdk-typescript/releases">@anthropic-ai/sdk's
releases</a>.</em></p>
<blockquote>
<h2>sdk: v0.111.0</h2>
<h2>0.111.0 (2026-07-10)</h2>
<p>Full Changelog: <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.110.0...sdk-v0.111.0">sdk-v0.110.0...sdk-v0.111.0</a></p>
<h3>Features</h3>
<ul>
<li><strong>api:</strong> add support for dreaming (<a
href="77b28a6472">77b28a6</a>)</li>
<li><strong>tools:</strong> gate session tool calls on
evaluated_permission; bound idle by server stop_reason (<a
href="68a6d7b92a">68a6d7b</a>)</li>
</ul>
<h3>Chores</h3>
<ul>
<li><strong>docs:</strong> small updates to field descriptions (<a
href="e25b885eac">e25b885</a>)</li>
<li><strong>docs:</strong> update model example (<a
href="a33f3f0b7c">a33f3f0</a>)</li>
<li><strong>docs:</strong> updates to descriptions and examples (<a
href="eac4bace32">eac4bac</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/anthropics/anthropic-sdk-typescript/blob/main/CHANGELOG.md">@anthropic-ai/sdk's
changelog</a>.</em></p>
<blockquote>
<h2>0.111.0 (2026-07-10)</h2>
<p>Full Changelog: <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.110.0...sdk-v0.111.0">sdk-v0.110.0...sdk-v0.111.0</a></p>
<h3>Features</h3>
<ul>
<li><strong>api:</strong> add support for dreaming (<a
href="77b28a6472">77b28a6</a>)</li>
<li><strong>tools:</strong> gate session tool calls on
evaluated_permission; bound idle by server stop_reason (<a
href="68a6d7b92a">68a6d7b</a>)</li>
</ul>
<h3>Chores</h3>
<ul>
<li><strong>docs:</strong> small updates to field descriptions (<a
href="e25b885eac">e25b885</a>)</li>
<li><strong>docs:</strong> update model example (<a
href="a33f3f0b7c">a33f3f0</a>)</li>
<li><strong>docs:</strong> updates to descriptions and examples (<a
href="eac4bace32">eac4bac</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9e46760688"><code>9e46760</code></a>
chore: release main</li>
<li><a
href="8d461ea962"><code>8d461ea</code></a>
feat(api): add support for dreaming</li>
<li><a
href="9436e29159"><code>9436e29</code></a>
codegen metadata</li>
<li><a
href="0aec1e748b"><code>0aec1e7</code></a>
feat(tools): gate session tool calls on evaluated_permission; bound idle
by s...</li>
<li><a
href="ac2fc6779d"><code>ac2fc67</code></a>
chore(docs): update model example</li>
<li><a
href="c8af65d6af"><code>c8af65d</code></a>
chore(docs): updates to descriptions and examples</li>
<li><a
href="2a3a9042ab"><code>2a3a904</code></a>
codegen metadata</li>
<li><a
href="57c56c9172"><code>57c56c9</code></a>
chore(docs): small updates to field descriptions</li>
<li>See full diff in <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.110.0...sdk-v0.111.0">compare
view</a></li>
</ul>
</details>
<br />
Updates `eslint` from 10.6.0 to 10.7.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/eslint/eslint/releases">eslint's
releases</a>.</em></p>
<blockquote>
<h2>v10.7.0</h2>
<h2>Features</h2>
<ul>
<li><a
href="cf2a9bf2d9"><code>cf2a9bf</code></a>
feat: add errorClassNames option to preserve-caught-error rule (<a
href="https://redirect.github.com/eslint/eslint/issues/21032">#21032</a>)
(sethamus)</li>
<li><a
href="f8b873aae5"><code>f8b873a</code></a>
feat: max-nested-callbacks option for constructor callbacks (<a
href="https://redirect.github.com/eslint/eslint/issues/21063">#21063</a>)
(fnx)</li>
<li><a
href="557fde8bc6"><code>557fde8</code></a>
feat: support computed <code>Number.parseInt</code> member access in
<code>radix</code> rule (<a
href="https://redirect.github.com/eslint/eslint/issues/21041">#21041</a>)
(Pixel)</li>
<li><a
href="0b4a73b658"><code>0b4a73b</code></a>
feat: add suggestions to no-compare-neg-zero (<a
href="https://redirect.github.com/eslint/eslint/issues/21034">#21034</a>)
(den$)</li>
<li><a
href="96cdd427db"><code>96cdd42</code></a>
feat: report invalid signed numeric radix values in <code>radix</code>
rule (<a
href="https://redirect.github.com/eslint/eslint/issues/21030">#21030</a>)
(Pixel)</li>
</ul>
<h2>Bug Fixes</h2>
<ul>
<li><a
href="3e7bf15e69"><code>3e7bf15</code></a>
fix: apply <code>ignoreClassesWithImplements</code> to class expressions
(<a
href="https://redirect.github.com/eslint/eslint/issues/21069">#21069</a>)
(Pixel)</li>
<li><a
href="0d7d70cf01"><code>0d7d70c</code></a>
fix: insert cause outside wrapping parens in preserve-caught-error (<a
href="https://redirect.github.com/eslint/eslint/issues/21062">#21062</a>)
(Mahin Anowar)</li>
<li><a
href="75ec753226"><code>75ec753</code></a>
fix: handle static template literals in <code>eqeqeq</code> rule (<a
href="https://redirect.github.com/eslint/eslint/issues/21058">#21058</a>)
(Pixel)</li>
<li><a
href="b717a22e24"><code>b717a22</code></a>
fix: prevent <code>eqeqeq</code> null option from reporting non-equality
operators (<a
href="https://redirect.github.com/eslint/eslint/issues/21057">#21057</a>)
(Pixel)</li>
<li><a
href="e35b05f196"><code>e35b05f</code></a>
fix: avoid <code>no-invalid-regexp</code> false positive for shadowed
RegExp (<a
href="https://redirect.github.com/eslint/eslint/issues/21051">#21051</a>)
(Pixel)</li>
<li><a
href="a3172b69c7"><code>a3172b6</code></a>
fix: avoid <code>no-control-regex</code> false positive for shadowed
RegExp (<a
href="https://redirect.github.com/eslint/eslint/issues/21050">#21050</a>)
(Pixel)</li>
<li><a
href="d1f637eca2"><code>d1f637e</code></a>
fix: parenthesize sequence expression operands in no-implicit-coercion
(<a
href="https://redirect.github.com/eslint/eslint/issues/21045">#21045</a>)
(spokodev)</li>
<li><a
href="8859bafb01"><code>8859baf</code></a>
fix: avoid prefer-numeric-literals false positive for shadowed globals
(<a
href="https://redirect.github.com/eslint/eslint/issues/21047">#21047</a>)
(한국)</li>
<li><a
href="a9e5961050"><code>a9e5961</code></a>
fix: use-isnan false positive on shadowed NaN/Number (<a
href="https://redirect.github.com/eslint/eslint/issues/20958">#20958</a>)
(sethamus)</li>
<li><a
href="8a240a7610"><code>8a240a7</code></a>
fix: avoid false positives in <code>radix</code> rule for spread
arguments (<a
href="https://redirect.github.com/eslint/eslint/issues/21044">#21044</a>)
(Pixel)</li>
</ul>
<h2>Documentation</h2>
<ul>
<li><a
href="c30d80801c"><code>c30d808</code></a>
docs: Update README (GitHub Actions Bot)</li>
<li><a
href="5139800b23"><code>5139800</code></a>
docs: document ESLint migration codemods in v9 and v10 guides (<a
href="https://redirect.github.com/eslint/eslint/issues/20980">#20980</a>)
(Alex Bit)</li>
<li><a
href="04174cbfaa"><code>04174cb</code></a>
docs: Update README (GitHub Actions Bot)</li>
<li><a
href="026e130408"><code>026e130</code></a>
docs: update semver policy for bug fixes (<a
href="https://redirect.github.com/eslint/eslint/issues/21048">#21048</a>)
(Milos Djermanovic)</li>
<li><a
href="9d42fefb0e"><code>9d42fef</code></a>
docs: Update README (GitHub Actions Bot)</li>
<li><a
href="b23015955c"><code>b230159</code></a>
docs: Update README (GitHub Actions Bot)</li>
<li><a
href="0129972ba1"><code>0129972</code></a>
docs: correct <code>**/.js</code> glob to <code>**/*.js</code> in config
files guide (<a
href="https://redirect.github.com/eslint/eslint/issues/21036">#21036</a>)
(EduardF1)</li>
</ul>
<h2>Chores</h2>
<ul>
<li><a
href="948937986f"><code>9489379</code></a>
chore: update dependency <code>@eslint/eslintrc</code> to ^3.3.6 (<a
href="https://redirect.github.com/eslint/eslint/issues/21076">#21076</a>)
(renovate[bot])</li>
<li><a
href="81a4774a92"><code>81a4774</code></a>
chore: updates for v9.39.5 release (Jenkins)</li>
<li><a
href="9835414913"><code>9835414</code></a>
chore: enable <code>$ExpectType</code> annotations in all TypeScript
files (<a
href="https://redirect.github.com/eslint/eslint/issues/21071">#21071</a>)
(Francesco Trotta)</li>
<li><a
href="72adf6bd21"><code>72adf6b</code></a>
chore: restrict <code>markdownlint-cli2</code> updates in renovate (<a
href="https://redirect.github.com/eslint/eslint/issues/21067">#21067</a>)
(lumir)</li>
<li><a
href="833ec10fd7"><code>833ec10</code></a>
chore: update dependency prettier to v3.9.4 (<a
href="https://redirect.github.com/eslint/eslint/issues/21061">#21061</a>)
(renovate[bot])</li>
<li><a
href="7ea106ddcb"><code>7ea106d</code></a>
chore: update ecosystem plugins (<a
href="https://redirect.github.com/eslint/eslint/issues/21059">#21059</a>)
(ESLint Bot)</li>
<li><a
href="8fb550e7c2"><code>8fb550e</code></a>
chore: add prettier update commit to <code>.git-blame-ignore-revs</code>
(<a
href="https://redirect.github.com/eslint/eslint/issues/21056">#21056</a>)
(lumir)</li>
<li><a
href="e4e11668ea"><code>e4e1166</code></a>
chore: update dependency prettier to v3.9.1 (<a
href="https://redirect.github.com/eslint/eslint/issues/21055">#21055</a>)
(renovate[bot])</li>
<li><a
href="0493f53f3f"><code>0493f53</code></a>
chore: update prettier to v3.9.0 (<a
href="https://redirect.github.com/eslint/eslint/issues/21054">#21054</a>)
(Pixel)</li>
<li><a
href="1056a996c6"><code>1056a99</code></a>
chore: update dependency prettier to v3.8.5 (<a
href="https://redirect.github.com/eslint/eslint/issues/21049">#21049</a>)
(renovate[bot])</li>
<li><a
href="4d4155df4a"><code>4d4155d</code></a>
ci: run ecosystem tests on pull requests (<a
href="https://redirect.github.com/eslint/eslint/issues/21027">#21027</a>)
(sethamus)</li>
<li><a
href="993539fd45"><code>993539f</code></a>
chore: update dependency <code>@eslint/json</code> to ^2.0.1 (<a
href="https://redirect.github.com/eslint/eslint/issues/21042">#21042</a>)
(renovate[bot])</li>
<li><a
href="53f8b69c15"><code>53f8b69</code></a>
test: add error locations to <code>no-constant-binary-expression</code>
(<a
href="https://redirect.github.com/eslint/eslint/issues/21039">#21039</a>)
(lumir)</li>
<li><a
href="5ab71d52f9"><code>5ab71d5</code></a>
refactor: clean up radix rule internals (<a
href="https://redirect.github.com/eslint/eslint/issues/21015">#21015</a>)
(Pixel)</li>
<li><a
href="a80a9a4614"><code>a80a9a4</code></a>
chore: update ecosystem plugins (<a
href="https://redirect.github.com/eslint/eslint/issues/21035">#21035</a>)
(ESLint Bot)</li>
<li><a
href="7c9a02933c"><code>7c9a029</code></a>
ci: add Node.js 26 to CI (<a
href="https://redirect.github.com/eslint/eslint/issues/20847">#20847</a>)
(lumir)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="fabd99bb74"><code>fabd99b</code></a>
10.7.0</li>
<li><a
href="37c5e75949"><code>37c5e75</code></a>
Build: changelog update for 10.7.0</li>
<li><a
href="948937986f"><code>9489379</code></a>
chore: update dependency <code>@eslint/eslintrc</code> to ^3.3.6 (<a
href="https://redirect.github.com/eslint/eslint/issues/21076">#21076</a>)</li>
<li><a
href="81a4774a92"><code>81a4774</code></a>
chore: updates for v9.39.5 release</li>
<li><a
href="3e7bf15e69"><code>3e7bf15</code></a>
fix: apply <code>ignoreClassesWithImplements</code> to class expressions
(<a
href="https://redirect.github.com/eslint/eslint/issues/21069">#21069</a>)</li>
<li><a
href="9835414913"><code>9835414</code></a>
chore: enable <code>$ExpectType</code> annotations in all TypeScript
files (<a
href="https://redirect.github.com/eslint/eslint/issues/21071">#21071</a>)</li>
<li><a
href="cf2a9bf2d9"><code>cf2a9bf</code></a>
feat: add errorClassNames option to preserve-caught-error rule (<a
href="https://redirect.github.com/eslint/eslint/issues/21032">#21032</a>)</li>
<li><a
href="c30d80801c"><code>c30d808</code></a>
docs: Update README</li>
<li><a
href="f8b873aae5"><code>f8b873a</code></a>
feat: max-nested-callbacks option for constructor callbacks (<a
href="https://redirect.github.com/eslint/eslint/issues/21063">#21063</a>)</li>
<li><a
href="72adf6bd21"><code>72adf6b</code></a>
chore: restrict <code>markdownlint-cli2</code> updates in renovate (<a
href="https://redirect.github.com/eslint/eslint/issues/21067">#21067</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/eslint/eslint/compare/v10.6.0...v10.7.0">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/claude-agent-sdk-darwin-arm64` from 0.3.206 to
0.3.207
Updates `@anthropic-ai/claude-agent-sdk-darwin-x64` from 0.3.206 to
0.3.207
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64` from 0.3.206 to
0.3.207
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64-musl` from 0.3.206
to 0.3.207
Updates `@anthropic-ai/claude-agent-sdk-linux-x64` from 0.3.206 to
0.3.207
Updates `@anthropic-ai/claude-agent-sdk-linux-x64-musl` from 0.3.206 to
0.3.207
Updates `@anthropic-ai/claude-agent-sdk-win32-arm64` from 0.3.206 to
0.3.207
Updates `@anthropic-ai/claude-agent-sdk-win32-x64` from 0.3.206 to
0.3.207
Updates `es-module-lexer` from 2.3.0 to 2.3.1
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/guybedford/es-module-lexer/releases">es-module-lexer's
releases</a>.</em></p>
<blockquote>
<h2>2.3.1</h2>
<h2>What's Changed</h2>
<ul>
<li>perf: fast native UTF-16 source copy into Wasm memory on Node by <a
href="https://github.com/guybedford"><code>@guybedford</code></a> in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/224">guybedford/es-module-lexer#224</a></li>
<li>perf(lexer): gate keywordStart on the next byte for i/c tokens by <a
href="https://github.com/BridgeAR"><code>@BridgeAR</code></a> in <a
href="https://redirect.github.com/guybedford/es-module-lexer/pull/223">guybedford/es-module-lexer#223</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/guybedford/es-module-lexer/compare/2.3.0...2.3.1">https://github.com/guybedford/es-module-lexer/compare/2.3.0...2.3.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2b2e6209ba"><code>2b2e620</code></a>
2.3.1</li>
<li><a
href="8c21b74b1f"><code>8c21b74</code></a>
perf(lexer): gate keywordStart on the next byte for i/c tokens (<a
href="https://redirect.github.com/guybedford/es-module-lexer/issues/223">#223</a>)</li>
<li><a
href="b8f9d89f9d"><code>b8f9d89</code></a>
perf: fast native UTF-16 source copy into Wasm memory on Node (<a
href="https://redirect.github.com/guybedford/es-module-lexer/issues/224">#224</a>)</li>
<li>See full diff in <a
href="https://github.com/guybedford/es-module-lexer/compare/2.3.0...2.3.1">compare
view</a></li>
</ul>
</details>
<br />
Updates `hono` from 4.12.29 to 4.12.30
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/hono/releases">hono's
releases</a>.</em></p>
<blockquote>
<h2>v4.12.30</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(benchmark/routers): bump deps in <a
href="https://redirect.github.com/honojs/hono/pull/5107">honojs/hono#5107</a></li>
<li>chore(benchmark): remove not used benchmarks in <a
href="https://redirect.github.com/honojs/hono/pull/5108">honojs/hono#5108</a></li>
<li>chore: update to ts6 in prep for ts7 in <a
href="https://redirect.github.com/honojs/hono/pull/5104">honojs/hono#5104</a></li>
<li>fix(cache): deduplicate Cache-Control directives case-insensitively
in <a
href="https://redirect.github.com/honojs/hono/pull/5025">honojs/hono#5025</a></li>
<li>fix(compress): do not compress 206 Partial Content responses in <a
href="https://redirect.github.com/honojs/hono/pull/5020">honojs/hono#5020</a></li>
<li>fix(client): replaceUrlParam should not match a param that prefixes
another in <a
href="https://redirect.github.com/honojs/hono/pull/5096">honojs/hono#5096</a></li>
<li>fix(method-override): set duplex when forwarding a stream body in
query mode in <a
href="https://redirect.github.com/honojs/hono/pull/5110">honojs/hono#5110</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.12.29...v4.12.30">https://github.com/honojs/hono/compare/v4.12.29...v4.12.30</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b2ae3a2204"><code>b2ae3a2</code></a>
4.12.30</li>
<li><a
href="e0cdeb0a89"><code>e0cdeb0</code></a>
fix(method-override): set duplex when forwarding a stream body in query
mode ...</li>
<li><a
href="653025e5c3"><code>653025e</code></a>
fix(client): replaceUrlParam should not match a param that prefixes
another (...</li>
<li><a
href="67efb27f7b"><code>67efb27</code></a>
fix(compress): do not compress 206 Partial Content responses (<a
href="https://redirect.github.com/honojs/hono/issues/5020">#5020</a>)</li>
<li><a
href="a48c8bf248"><code>a48c8bf</code></a>
fix(cache): deduplicate Cache-Control directives case-insensitively (<a
href="https://redirect.github.com/honojs/hono/issues/5025">#5025</a>)</li>
<li><a
href="3bb9a0e3a7"><code>3bb9a0e</code></a>
chore: update to ts6 in prep for ts7 (<a
href="https://redirect.github.com/honojs/hono/issues/5104">#5104</a>)</li>
<li><a
href="d3f97caa29"><code>d3f97ca</code></a>
chore(benchmark): remove not used benchmarks (<a
href="https://redirect.github.com/honojs/hono/issues/5108">#5108</a>)</li>
<li><a
href="29a3f73fd5"><code>29a3f73</code></a>
chore(benchmark/routers): bump deps (<a
href="https://redirect.github.com/honojs/hono/issues/5107">#5107</a>)</li>
<li>See full diff in <a
href="https://github.com/honojs/hono/compare/v4.12.29...v4.12.30">compare
view</a></li>
</ul>
</details>
<br />
Updates `postcss` from 8.5.16 to 8.5.19
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/postcss/postcss/releases">postcss's
releases</a>.</em></p>
<blockquote>
<h2>8.5.19</h2>
<ul>
<li>Fixed cleaning <code>before</code> for new nodes inserted to
<code>Root</code> (by <a
href="https://github.com/MahinAnowar"><code>@MahinAnowar</code></a>).</li>
</ul>
<h2>8.5.18</h2>
<ul>
<li>Restricted loading previous source maps file to the
<code>opts.from</code> folder for security reasons (use <code>unsafeMap:
true</code> to disable the check).</li>
</ul>
<h2>8.5.17</h2>
<ul>
<li>Fixed <code>Maximum call stack size exceeded</code> error.</li>
<li>Fixed Prototype hijacking for <code>postcss.fromJSON()</code>.</li>
<li>Fixed <code>Input#origin()</code> for unmapped end position (by <a
href="https://github.com/chatman-media"><code>@chatman-media</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/postcss/postcss/blob/main/CHANGELOG.md">postcss's
changelog</a>.</em></p>
<blockquote>
<h2>8.5.19</h2>
<ul>
<li>Fixed cleaning <code>before</code> for new nodes inserted to
<code>Root</code> (by <a
href="https://github.com/MahinAnowar"><code>@MahinAnowar</code></a>).</li>
</ul>
<h2>8.5.18</h2>
<ul>
<li>Restricted loading previous source maps file to the
<code>opts.from</code> folder for security reasons (use <code>unsafeMap:
true</code> to disable the check).</li>
</ul>
<h2>8.5.17</h2>
<ul>
<li>Fixed <code>Maximum call stack size exceeded</code> error.</li>
<li>Fixed Prototype hijacking for <code>postcss.fromJSON()</code>.</li>
<li>Fixed <code>Input#origin()</code> for unmapped end position (by <a
href="https://github.com/chatman-media"><code>@chatman-media</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9543b22769"><code>9543b22</code></a>
Release 8.5.19 version</li>
<li><a
href="3d13bf9360"><code>3d13bf9</code></a>
Fix CI on Windows too</li>
<li><a
href="00d0dd2322"><code>00d0dd2</code></a>
Keep explicitly set raws.before when inserting nodes into root (<a
href="https://redirect.github.com/postcss/postcss/issues/2111">#2111</a>)</li>
<li><a
href="7a05b33e7a"><code>7a05b33</code></a>
Temporary fix CI</li>
<li><a
href="4c0d194c13"><code>4c0d194</code></a>
Release 8.5.18 version</li>
<li><a
href="92b4e7891e"><code>92b4e78</code></a>
Update dependencies</li>
<li><a
href="95663d3eb7"><code>95663d3</code></a>
Limit where source map can be loaded for security reasons</li>
<li><a
href="74e25ae9f4"><code>74e25ae</code></a>
Release 8.5.17 version</li>
<li><a
href="d1518afd5a"><code>d1518af</code></a>
Fix Maximum call stack size exceeded error</li>
<li><a
href="2421312ffe"><code>2421312</code></a>
Fix linter</li>
<li>Additional commits viewable in <a
href="https://github.com/postcss/postcss/compare/8.5.16...8.5.19">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
## Problem
`session/prompt` settled at the turn's terminal `result`, but a turn
that launched an **async subagent** is not done at that point.
Everything after settlement — the subagent's streamed tool calls, the
model's promised task-notification followup summary, and any
`session/request_permission` the subagent raises — landed **outside any
turn**. Some clients stops consuming updates at the prompt response, so
the output was silently lost and the permission request deadlocked on an
RPC nobody answers.
Reported as #864 (no signal for the post-turn activity), #865
(background tasks not trackable), and #866 (end-to-end field report
incl. the permission deadlock).
## What I verified before designing this
Driving the adapter over real ACP stdio against the bundled CLI
(2.1.206) with `emitRawSDKMessages` on showed that the SDK's trailing
`session_state_changed: idle` **does not wait for background agents** —
it follows the user result immediately, while the subagent is still
running, and the session then cycles:
```
user result → idle → (subagent works) → task_notification → followup turn → result(origin: task-notification) → idle
```
So the old #463-era "settle at idle" design would **not** fix this on
current CLIs (and plain re-adopting it would still trade away #773). The
hold has to be keyed on the live-subagent set and span those idle
cycles.
## Fix
A user turn whose terminal result arrives while subagents **it spawned**
are still live stores its outcome on `Turn.deferredSettle` instead of
settling. The prompt stays pending, so all of the subagent's output and
permission requests arrive inside a live turn. It settles with the
stored stop reason/usage:
- at the **task-notification followup's terminal result** — the promised
summary has fully streamed by then (the common case), or
- at an **idle with none of its subagents left**, when no followup
comes, or
- earlier, via `session/cancel` or the next prompt's echo hand-off — a
long-running subagent never holds the prompt hostage, and the hand-off
reports the recorded stop reason instead of rewriting it to `end_turn`.
Tracking: `Turn.spawnedTaskIds` ∩ `session.liveSubagentTasks`, fed by
`task_started` (only entries with `subagent_type`; background shells are
deliberately excluded — a dev server outlives every turn), pruned at
`task_notification`/terminal `task_updated`, and reconciled against
`background_tasks_changed`'s replace-semantics payload so a lost bookend
can't wedge the hold. A spawn during the held-open window (an agent
chain) extends the hold naturally.
Turns that spawned nothing (or whose subagents finished in-turn) still
settle at their result — the #773 responsiveness is untouched.
## Live verification (adapter on real stdio, CLI 2.1.206, temp cwd)
Prompt: *"launch a background agent to read the two files and create
summary.txt, then end your turn saying you'll report back"*:
```
[ 15.72] raw: result success ← user result; subagent live → HELD
[ 15.72] raw: session_state_changed idle ← immediate idle survives the hold
[ 17.50] update: tool_call Read hello.txt ← subagent work, in-turn
[ 21.39] update: tool_call Write summary.txt ← in-turn
[ 24.17] raw: task_notification completed
[ 34.35] update: agent_message_chunk "The background agent finished. It created summary.txt…" ← promised summary, in-turn
[ 35.70] raw: result success (origin task-notification)
[ 35.70] PROMPT RESOLVED end_turn, usage = user turn's own tokens
```
No-regression check: a plain `"say hello"` prompt resolves the instant
its result lands (2.09s, zero added latency).
## Hardening from the adversarial review pass
A high-effort review (8 finder angles) of the change surfaced three
confirmed defects, each fixed with a regression test that fails pre-fix:
- **cancel() of a held turn stalled ~30s**: the session is already idle
during the hold, so the interrupt may never emit the trailing idle the
cancelled-settle path waited on. cancel() now settles a deferred turn
immediately (its result is already in hand); this also prevents the
force-cancel backstop from seeding a phantom orphan for a result that
already passed.
- **A followup's `is_error` / "Please run /login" could reject a held
user turn** whose own result was a success (reachable with parallel
subagents). Followup results now never touch the user-turn lifecycle.
- **The followup's own trailing idle was un-owed**: settling at the
followup result unblocks the client at exactly the moment that idle can
lag past the next prompt's echo — which would have been read as the
fresh turn ending without a result (#825 false-fail). All results now
record their trailer debt.
A second review round on the post-merge state (after resolving conflicts
with #858) found and fixed five more: an echo-less command (`/context`)
during a hold overwrote the held turn's outcome and hung
(ensureActiveTurn now hands the held turn off and promotes the head);
the refusal lane bypassed the deferral gate (result-time settles now
route through a shared `settleOrDefer`); cancel()'s inline settle
couldn't record the interrupt trailer's owed-idle debt (the counter
moved onto the Session) and skipped the backstop disarm; `failAllTurns`
rejected a held turn whose answer had already streamed (now resolves the
stored outcome, like stream-done); and a followup result inside a cancel
window skipped the trailer count. Settling at a followup result also now
closes the #453 delivery stretch so a following replayed turn's fallback
isn't suppressed.
Known residuals, deliberately accepted: a subagent whose settle bookends
are all lost parks the held turn until `session/cancel` or the next
prompt (same rescue contract as the adapter's other wedge classes); a
wake whose origin can't be attributed (the SDK's `origin` carries no
task id) can settle the turn one followup early, degrading to today's
behavior, never worse.
## Verification
Unit: 530 tests green; the deferral/cancel/false-fail tests were each
run against the pre-fix adapter and fail there. Live (real ACP stdio,
CLI 2.1.206): held turn with in-turn subagent output + followup summary,
resolution at the followup's result; plain prompts resolve instantly at
their result.
## Out of scope (follow-ups)
- A background **shell**'s exit waking the model between turns remains
an out-of-turn episode — there is no turn to hold for it without
blocking every prompt behind a dev server. Same for clients that want a
session-level active/idle or background-task level signal (#864/#865's
additive asks): both raw signals are already available today via
`_meta.claudeCode.emitRawSDKMessages` → `_claude/sdkMessage` ext
notifications.
- Flipping the spawning `Task` tool call's status at terminal
`task_updated` (#865's optional ask).
A third review round on the consolidated state fixed: the reconciliation
deleting live sync-subagent attribution entries (the level's universe is
background-only — absent subagent entries are now kept but marked
`endedPerLevel` so holds stop waiting on them);
peer/coordinator/observer-origin results being treated as the user's
turn (now gated via `AUTONOMOUS_RESULT_ORIGINS`, preserving
channel-origin behavior); `emittedAssistantText` moving onto the Session
so every held-turn settle lane closes the #453 delivery stretch (with
the snapshot taken after the held-turn hand-off); the interrupt-trailer
pre-count gated on a running cycle so idle-cancels can't mask future
#825 detections; and `turnAwaitingSubagents` now reading `isSubagent` as
defense in depth for the shells-never-defer contract. Plus
`isHeldOpen()`/`disarmForceCancel()` deduplicating the hold predicate
and backstop disarm.
(An earlier follow-up — folding the attribution map and the
live-subagent set into one task registry — is now done in this PR:
`liveBackgroundTasks` keyed by task id, so the
`background_tasks_changed` reconciliation heals both concerns and future
terminal paths can't prune one but not the other.)
Fixes#866. Addresses the settlement half of #864 / #865.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Bumps [nanoid](https://github.com/ai/nanoid) from 3.3.15 to 3.3.16.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/ai/nanoid/releases">nanoid's
releases</a>.</em></p>
<blockquote>
<h2>3.3.16</h2>
<ul>
<li>Fixed infinite loop on negative size (by <a
href="https://github.com/greymoth-jp"><code>@greymoth-jp</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/ai/nanoid/blob/main/CHANGELOG.md">nanoid's
changelog</a>.</em></p>
<blockquote>
<h2>3.3.16</h2>
<ul>
<li>Fixed infinite loop on negative size (by <a
href="https://github.com/greymoth-jp"><code>@greymoth-jp</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9760e11275"><code>9760e11</code></a>
Release 3.3.16 version</li>
<li><a
href="e835c9b71e"><code>e835c9b</code></a>
fix(non-secure): clamp negative size to prevent infinite loop (<a
href="https://redirect.github.com/ai/nanoid/issues/601">#601</a>)</li>
<li><a
href="96dd086eb2"><code>96dd086</code></a>
Update CI action</li>
<li><a
href="ba0bc3b6b9"><code>ba0bc3b</code></a>
Do not create latest release for v3</li>
<li>See full diff in <a
href="https://github.com/ai/nanoid/compare/3.3.15...3.3.16">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Fixes#453.
On a cache-replayed turn the CLI can answer on the `result` alone:
output_tokens is 0, no `stream_event` deltas, and no consolidated
`assistant` message. The result handler never forwarded that text, so
the client rendered an empty turn.
The check suggested in the issue (output_tokens === 0 and a non-empty
result) isn't enough by itself. I tried it: it emits the answer twice
when the consolidated `assistant` message already delivered it,
including the case where the echo lands mid-message and the consolidated
message dedupes to nothing, and it forwards a background
task-notification followup's output into the user's turn.
So this tracks whether any top-level assistant text already reached the
client since the last user-turn result, and forwards `message.result`
only when none did and the turn isn't a task-notification followup. The
direct emitters in the `status` handler (compaction notices, local
command output) set the flag too, since they bypass the forwarding
loops. `compact_boundary` doesn't, because it only sends a usage update.
Tests: six added to the "assembled assistant text fallback" block.
Reverting the source change fails "forwards the result text when nothing
else carried it"; the other five pin the guards, and they catch the
naive version, which double-emits and leaks task-notification output.
Full suite: 501 passed, 2 failed, and both failures reproduce on a clean
main (Windows path separator assertions in the tool-conversion tests).
eslint, tsc --noEmit, and prettier --check are clean.
---------
Co-authored-by: Josh Kappler <boffytv@gmail.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
## Why
Tool-use `content_block_start` events arrive before their JSON input.
This leaves pending calls with generic labels such as `Read File` or
`Terminal`; long-running and concurrent calls can remain
indistinguishable in clients while they execute.
Anthropic specifies `input_json_delta.partial_json` as arbitrary string
fragments, so delta boundaries cannot be assumed to align with fields or
JSON values.
## What changed
- Buffer `input_json_delta` fragments per parent message and
content-block index.
- Recover completed top-level fields while the overall JSON is still
incomplete.
- Refine the existing ACP tool call immediately when distinguishing
fields such as `file_path`, `command`, `query`, `pattern`, `url`, or
`description` become available.
- Continue refining as later fields arrive, while keeping the early
pending lifecycle and cleaning incomplete buffers at block/message
boundaries.
- Avoid publishing ambiguous numeric suffixes (`10` may still become
`100` or `10.5`) until a delimiter arrives.
## Test coverage
Parameterized coverage now includes Agent/Task, Bash, Read/Write/Edit,
Glob/Grep, WebFetch/WebSearch, ReportFindings, ExitPlanMode,
AskUserQuestion, Other, custom MCP calls, TodoWrite plan updates, and
intentionally suppressed TaskCreate/Update/List/Get calls. Edge cases
cover arbitrary field splits, unfinished strings, escaped quotes and
commas, numbers, booleans, null, arrays, nested objects, and all three
tool block types (`tool_use`, `server_tool_use`, `mcp_tool_use`).
## Validation
- `npm run build`
- `npm run test:run` (535 passed, 20 skipped)
- `npm run check`
---------
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.205` | `0.3.206` |
| [prettier](https://github.com/prettier/prettier) | `3.9.4` | `3.9.5` |
| @anthropic-ai/claude-agent-sdk-darwin-arm64 | `0.3.205` | `0.3.206` |
| @anthropic-ai/claude-agent-sdk-darwin-x64 | `0.3.205` | `0.3.206` |
| @anthropic-ai/claude-agent-sdk-linux-arm64 | `0.3.205` | `0.3.206` |
| @anthropic-ai/claude-agent-sdk-linux-arm64-musl | `0.3.205` |
`0.3.206` |
| @anthropic-ai/claude-agent-sdk-linux-x64 | `0.3.205` | `0.3.206` |
| @anthropic-ai/claude-agent-sdk-linux-x64-musl | `0.3.205` | `0.3.206`
|
| @anthropic-ai/claude-agent-sdk-win32-arm64 | `0.3.205` | `0.3.206` |
| @anthropic-ai/claude-agent-sdk-win32-x64 | `0.3.205` | `0.3.206` |
| [hono](https://github.com/honojs/hono) | `4.12.28` | `4.12.29` |
Updates `@anthropic-ai/claude-agent-sdk` from 0.3.205 to 0.3.206
<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.206</h2>
<h2>What's changed</h2>
<ul>
<li>Added <code>command_lifecycle</code> frames to stream-json and SDK
sessions, reporting each uuid-stamped message's terminal state
(<code>queued</code>/<code>started</code>/<code>completed</code>/<code>cancelled</code>/<code>discarded</code>);
zero-API results no longer report stale
<code>duration_api_ms</code></li>
</ul>
<h2>Update</h2>
<pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.206
# or
yarn add @anthropic-ai/claude-agent-sdk@0.3.206
# or
pnpm add @anthropic-ai/claude-agent-sdk@0.3.206
# or
bun add @anthropic-ai/claude-agent-sdk@0.3.206
</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.206</h2>
<ul>
<li>Added <code>command_lifecycle</code> frames to stream-json and SDK
sessions, reporting each uuid-stamped message's terminal state
(<code>queued</code>/<code>started</code>/<code>completed</code>/<code>cancelled</code>/<code>discarded</code>);
zero-API results no longer report stale
<code>duration_api_ms</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9fc7ea5ff6"><code>9fc7ea5</code></a>
chore: Update CHANGELOG.md</li>
<li>See full diff in <a
href="https://github.com/anthropics/claude-agent-sdk-typescript/compare/v0.3.205...v0.3.206">compare
view</a></li>
</ul>
</details>
<br />
Updates `prettier` from 3.9.4 to 3.9.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.9.5</h2>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.5/CHANGELOG.md#395">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.9.5</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.9.4...3.9.5">diff</a></p>
<h4>Markdown: Cap ordered list mark at 999,999,999 (<a
href="https://redirect.github.com/prettier/prettier/pull/19351">#19351</a>
by <a href="https://github.com/tats-u"><code>@tats-u</code></a>)</h4>
<p>CommonMark parsers only support ordered list item numbers up to
999,999,999.</p>
<p>With this change, Prettier now caps the ordered list item number at
999,999,999 to ensure that the output is correctly parsed as an ordered
list by CommonMark parsers. Numbers larger than 999,999,999 are not
parsed as list item numbers and are left unchanged in the output:</p>
<!-- raw HTML omitted -->
<pre lang="markdown"><code><!-- Input -->
999999998. text
999999998. text
999999998. text
999999998. text
<p>1234567890123456789012) text</p>
<p><!-- Prettier 3.9.4 -->
999999998. text
999999999. text
1000000000. text
1000000001. text</p>
<p>1234567890123456789012) text</p>
<p><!-- Prettier 3.9.5 -->
999999998. text
999999999. text
999999999. text
999999999. text</p>
<p>1234567890123456789012) text
</code></pre></p>
<h4>Markdown: Avoid corrupting empty link with title (<a
href="https://redirect.github.com/prettier/prettier/pull/19487">#19487</a>
by <a href="https://github.com/andersk"><code>@andersk</code></a>)</h4>
<p>Do not remove <code><></code> from an inline link or image with
an empty URL and a title, as this removal would change its
interpretation.</p>
<!-- raw HTML omitted -->
<pre lang="md"><code><!-- Input -->
[link](https://github.com/prettier/prettier/blob/main/<>
"title")
<p><!-- Prettier 3.9.4 -->
[link](<a
href="https://github.com/prettier/prettier/blob/main/">https://github.com/prettier/prettier/blob/main/</a>
"title")</p>
<p><!-- Prettier 3.9.5 -->
</tr></table>
</code></pre></p>
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b6c7d18068"><code>b6c7d18</code></a>
Release 3.9.5</li>
<li><a
href="cd54ccc728"><code>cd54ccc</code></a>
Avoid corrupting empty Markdown link with title (<a
href="https://redirect.github.com/prettier/prettier/issues/19487">#19487</a>)</li>
<li><a
href="2bb67ce8cd"><code>2bb67ce</code></a>
Preserving comments' <code>placement</code> property (<a
href="https://redirect.github.com/prettier/prettier/issues/19567">#19567</a>)</li>
<li><a
href="91bcac88ec"><code>91bcac8</code></a>
Add more tests for comment-only object type (<a
href="https://redirect.github.com/prettier/prettier/issues/19587">#19587</a>)</li>
<li><a
href="cbee7377a1"><code>cbee737</code></a>
Remove space in empty object type (<a
href="https://redirect.github.com/prettier/prettier/issues/19583">#19583</a>)</li>
<li><a
href="6394c73209"><code>6394c73</code></a>
Align empty module declaration with TS (<a
href="https://redirect.github.com/prettier/prettier/issues/19568">#19568</a>)</li>
<li><a
href="a4e6f7a026"><code>a4e6f7a</code></a>
Prevent the addition of space in <code>type()</code> with <code>+</code>
(<a
href="https://redirect.github.com/prettier/prettier/issues/19516">#19516</a>)</li>
<li><a
href="3d063b57b1"><code>3d063b5</code></a>
Ignore dangling comments when checking type parameter comments (<a
href="https://redirect.github.com/prettier/prettier/issues/19572">#19572</a>)</li>
<li><a
href="908503e9ee"><code>908503e</code></a>
Handle dangling comments in <code>SwitchStatement</code> (<a
href="https://redirect.github.com/prettier/prettier/issues/19581">#19581</a>)</li>
<li><a
href="943a475c35"><code>943a475</code></a>
Angular: Support expression for exhaustive typechecking (<a
href="https://redirect.github.com/prettier/prettier/issues/19571">#19571</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/prettier/prettier/compare/3.9.4...3.9.5">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/claude-agent-sdk-darwin-arm64` from 0.3.205 to
0.3.206
Updates `@anthropic-ai/claude-agent-sdk-darwin-x64` from 0.3.205 to
0.3.206
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64` from 0.3.205 to
0.3.206
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64-musl` from 0.3.205
to 0.3.206
Updates `@anthropic-ai/claude-agent-sdk-linux-x64` from 0.3.205 to
0.3.206
Updates `@anthropic-ai/claude-agent-sdk-linux-x64-musl` from 0.3.205 to
0.3.206
Updates `@anthropic-ai/claude-agent-sdk-win32-arm64` from 0.3.205 to
0.3.206
Updates `@anthropic-ai/claude-agent-sdk-win32-x64` from 0.3.205 to
0.3.206
Updates `hono` from 4.12.28 to 4.12.29
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/honojs/hono/releases">hono's
releases</a>.</em></p>
<blockquote>
<h2>v4.12.29</h2>
<h2>What's Changed</h2>
<ul>
<li>fix(client): merge function headers with per-request headers by <a
href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/5092">honojs/hono#5092</a></li>
<li>chore: fix no-op tsc in test script by <a
href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/5093">honojs/hono#5093</a></li>
<li>fix(lambda-edge): resolve the handler with the value passed to the
callback by <a
href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/5094">honojs/hono#5094</a></li>
<li>docs(language): add JSDoc <a
href="https://github.com/example"><code>@example</code></a> to
languageDetector by <a
href="https://github.com/codebybilal18"><code>@codebybilal18</code></a>
in <a
href="https://redirect.github.com/honojs/hono/pull/5081">honojs/hono#5081</a></li>
<li>test(workerd): add <code>compatibilityDate</code> by <a
href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/5100">honojs/hono#5100</a></li>
<li>fix(lambda-edge): base64 encode content-encoded response bodies by
<a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/5099">honojs/hono#5099</a></li>
<li>fix(aws-lambda): treat any non-identity content-encoding as binary
by <a href="https://github.com/yusukebe"><code>@yusukebe</code></a> in
<a
href="https://redirect.github.com/honojs/hono/pull/5101">honojs/hono#5101</a></li>
<li>fix(types): strip extra properties from array types in JSONParsed by
<a
href="https://github.com/Arman-Luthra"><code>@Arman-Luthra</code></a>
in <a
href="https://redirect.github.com/honojs/hono/pull/5103">honojs/hono#5103</a></li>
<li>fix(trie-router): match empty wildcard remainder after regexp param
by <a href="https://github.com/usualoma"><code>@usualoma</code></a> in
<a
href="https://redirect.github.com/honojs/hono/pull/5102">honojs/hono#5102</a></li>
<li>fix(etag): treat If-None-Match: <code>*</code> as a match by <a
href="https://github.com/yusukebe"><code>@yusukebe</code></a> in <a
href="https://redirect.github.com/honojs/hono/pull/5084">honojs/hono#5084</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/codebybilal18"><code>@codebybilal18</code></a>
made their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/5081">honojs/hono#5081</a></li>
<li><a
href="https://github.com/Arman-Luthra"><code>@Arman-Luthra</code></a>
made their first contribution in <a
href="https://redirect.github.com/honojs/hono/pull/5103">honojs/hono#5103</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/honojs/hono/compare/v4.12.28...v4.12.29">https://github.com/honojs/hono/compare/v4.12.28...v4.12.29</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="cda1af2002"><code>cda1af2</code></a>
4.12.29</li>
<li><a
href="2126289c15"><code>2126289</code></a>
fix(etag): treat If-None-Match: <code>*</code> as a match (<a
href="https://redirect.github.com/honojs/hono/issues/5084">#5084</a>)</li>
<li><a
href="0fc7ffc949"><code>0fc7ffc</code></a>
fix(trie-router): match empty wildcard remainder after regexp param (<a
href="https://redirect.github.com/honojs/hono/issues/5102">#5102</a>)</li>
<li><a
href="ab590e4ec8"><code>ab590e4</code></a>
fix(types): strip extra properties from array types in JSONParsed (<a
href="https://redirect.github.com/honojs/hono/issues/5103">#5103</a>)</li>
<li><a
href="b93a2547a3"><code>b93a254</code></a>
fix(aws-lambda): treat any non-identity content-encoding as binary (<a
href="https://redirect.github.com/honojs/hono/issues/5101">#5101</a>)</li>
<li><a
href="6217f4b74c"><code>6217f4b</code></a>
fix(lambda-edge): base64 encode content-encoded response bodies (<a
href="https://redirect.github.com/honojs/hono/issues/5099">#5099</a>)</li>
<li><a
href="ba89e973c7"><code>ba89e97</code></a>
test(workerd): add <code>compatibilityDate</code> (<a
href="https://redirect.github.com/honojs/hono/issues/5100">#5100</a>)</li>
<li><a
href="46557ef820"><code>46557ef</code></a>
docs(language): add JSDoc <a
href="https://github.com/example"><code>@example</code></a> to
languageDetector (<a
href="https://redirect.github.com/honojs/hono/issues/5081">#5081</a>)</li>
<li><a
href="24547a6ed5"><code>24547a6</code></a>
fix(lambda-edge): resolve the handler with the value passed to the
callback (...</li>
<li><a
href="9c6ccd76f1"><code>9c6ccd7</code></a>
chore: fix no-op tsc in test script (<a
href="https://redirect.github.com/honojs/hono/issues/5093">#5093</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/honojs/hono/compare/v4.12.28...v4.12.29">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
## Summary
This makes streamed text/thinking chunk handling defensive when gateways
emit empty or malformed delta payloads.
- Guard `text_delta.text` and `thinking_delta.thinking` before reading
`.length`
- Skip missing/non-string text or thinking content the same way empty
chunks are already skipped
- Add regression coverage for a missing `thinking` delta before a real
text delta
- Add direct `toAcpNotifications` coverage for missing/non-string text
and thinking chunks
## Why
The adapter already skips empty thinking chunks, but some
Anthropic-compatible gateways can emit signature-only or omitted
thinking deltas where `thinking` is absent rather than an empty string.
In that case the adapter currently throws:
```text
Cannot read properties of undefined (reading 'length')
```
That aborts the ACP session even though the following text chunks are
valid.
This change keeps the existing behavior for valid chunks, while treating
missing/non-string chunk text as empty content.
## Test Plan
- `npm run check`
- `npm test -- --run`
- `npm run build`
Also verified manually through a VibeAround Web Chat flow using Claude
Code ACP with an Anthropic-compatible custom endpoint; the session
completed and returned a normal assistant response.
---------
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
## Why this is needed
`toAcpNotifications` can emit an `agent_message_chunk` whose content is
an empty string. This happens in two situations:
1. **Streamed text deltas** — the `text` / `text_delta` case builds the
update unconditionally from `chunk.text`, and the Claude Agent SDK can
stream zero-length text deltas (for example, an empty trailing assistant
block at the end of a turn).
2. **Full-string content** — the string-content path emits a chunk even
when the string is empty.
An empty message chunk carries no information, so at best it is noise.
At worst it breaks clients: the ACP spec does not forbid empty content,
so clients handle it inconsistently and some throw. In JetBrains Air the
frontend event consumer throws on an empty-content `agent_message_chunk`
(`Failed to handle agent event`); once that happens the transcript is
**frozen for the rest of the turn** — no further updates render and
queued prompts are never dispatched. In practice this reproduced
repeatedly around image reads and end-of-turn, and the only recovery was
restarting the IDE.
Because the adapter is client-agnostic, this affects any ACP client that
is strict about chunk content, not a single editor — so the correct
place to fix it is here, in the adapter, rather than working around it
in each client.
## Fix
Do not emit empty content. Both call sites are guarded, mirroring the
empty-`thinking` guard that already exists a few lines below in the same
function, so behavior is consistent across content types:
- `text` / `text_delta`: only build the update when `chunk.text.length >
0`;
- string content: return `[]` when the string is empty.
The change is intentionally minimal and conservative — no information is
lost, and non-empty chunks are entirely unaffected.
## Tests
Three unit tests added on `toAcpNotifications`:
- empty string content → no notifications emitted;
- non-empty string content → still emitted unchanged;
- a stream containing an empty text block followed by a non-empty one →
only the non-empty block is emitted.
Full suite green (476 passing); eslint and prettier clean.
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.198` | `0.3.199` |
|
[@anthropic-ai/sdk](https://github.com/anthropics/anthropic-sdk-typescript)
| `0.109.1` | `0.110.0` |
| @anthropic-ai/claude-agent-sdk-darwin-arm64 | `0.3.198` | `0.3.199` |
| @anthropic-ai/claude-agent-sdk-darwin-x64 | `0.3.198` | `0.3.199` |
| @anthropic-ai/claude-agent-sdk-linux-arm64 | `0.3.198` | `0.3.199` |
| @anthropic-ai/claude-agent-sdk-linux-arm64-musl | `0.3.198` |
`0.3.199` |
| @anthropic-ai/claude-agent-sdk-linux-x64 | `0.3.198` | `0.3.199` |
| @anthropic-ai/claude-agent-sdk-linux-x64-musl | `0.3.198` | `0.3.199`
|
| @anthropic-ai/claude-agent-sdk-win32-arm64 | `0.3.198` | `0.3.199` |
| @anthropic-ai/claude-agent-sdk-win32-x64 | `0.3.198` | `0.3.199` |
| [picomatch](https://github.com/micromatch/picomatch) | `4.0.4` |
`4.0.5` |
Updates `@anthropic-ai/claude-agent-sdk` from 0.3.198 to 0.3.199
<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.199</h2>
<h2>What's changed</h2>
<ul>
<li>Added <code>requestId</code> to <code>canUseTool</code> callback
options for correlating out-of-band permission responses, and support
for returning <code>null</code> to suppress the SDK's automatic control
response</li>
<li>Added <code>blocked</code> field to <code>workflow_agent</code>
progress events indicating when an agent was blocked by the auto-mode
safety classifier</li>
<li>Added <code>mode:"mask"</code> and per-credential
<code>injectHosts</code> to <code>sandbox.credentials</code> settings
types for injecting masked credentials into sandboxed commands</li>
</ul>
<h2>Update</h2>
<pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.199
# or
yarn add @anthropic-ai/claude-agent-sdk@0.3.199
# or
pnpm add @anthropic-ai/claude-agent-sdk@0.3.199
# or
bun add @anthropic-ai/claude-agent-sdk@0.3.199
</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.199</h2>
<ul>
<li>Added <code>requestId</code> to <code>canUseTool</code> callback
options for correlating out-of-band permission responses, and support
for returning <code>null</code> to suppress the SDK's automatic control
response</li>
<li>Added <code>blocked</code> field to <code>workflow_agent</code>
progress events indicating when an agent was blocked by the auto-mode
safety classifier</li>
<li>Added <code>mode:"mask"</code> and per-credential
<code>injectHosts</code> to <code>sandbox.credentials</code> settings
types for injecting masked credentials into sandboxed commands</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a0c02d6d99"><code>a0c02d6</code></a>
chore: Update CHANGELOG.md</li>
<li>See full diff in <a
href="https://github.com/anthropics/claude-agent-sdk-typescript/compare/v0.3.198...v0.3.199">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/sdk` from 0.109.1 to 0.110.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/anthropics/anthropic-sdk-typescript/releases">@anthropic-ai/sdk's
releases</a>.</em></p>
<blockquote>
<h2>sdk: v0.110.0</h2>
<h2>0.110.0 (2026-07-02)</h2>
<p>Full Changelog: <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.109.1...sdk-v0.110.0">sdk-v0.109.1...sdk-v0.110.0</a></p>
<h3>Features</h3>
<ul>
<li><strong>api:</strong> add agent-memory-2026-07-22 beta header (<a
href="a470e10aaa">a470e10</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/anthropics/anthropic-sdk-typescript/blob/main/CHANGELOG.md">@anthropic-ai/sdk's
changelog</a>.</em></p>
<blockquote>
<h2>0.110.0 (2026-07-02)</h2>
<p>Full Changelog: <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.109.1...sdk-v0.110.0">sdk-v0.109.1...sdk-v0.110.0</a></p>
<h3>Features</h3>
<ul>
<li><strong>api:</strong> add agent-memory-2026-07-22 beta header (<a
href="a470e10aaa">a470e10</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4f2eb80719"><code>4f2eb80</code></a>
chore: release main (<a
href="https://redirect.github.com/anthropics/anthropic-sdk-typescript/issues/1107">#1107</a>)</li>
<li>See full diff in <a
href="https://github.com/anthropics/anthropic-sdk-typescript/compare/sdk-v0.109.1...sdk-v0.110.0">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/claude-agent-sdk-darwin-arm64` from 0.3.198 to
0.3.199
Updates `@anthropic-ai/claude-agent-sdk-darwin-x64` from 0.3.198 to
0.3.199
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64` from 0.3.198 to
0.3.199
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64-musl` from 0.3.198
to 0.3.199
Updates `@anthropic-ai/claude-agent-sdk-linux-x64` from 0.3.198 to
0.3.199
Updates `@anthropic-ai/claude-agent-sdk-linux-x64-musl` from 0.3.198 to
0.3.199
Updates `@anthropic-ai/claude-agent-sdk-win32-arm64` from 0.3.198 to
0.3.199
Updates `@anthropic-ai/claude-agent-sdk-win32-x64` from 0.3.198 to
0.3.199
Updates `picomatch` from 4.0.4 to 4.0.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/micromatch/picomatch/releases">picomatch's
releases</a>.</em></p>
<blockquote>
<h2>4.0.5</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: preserve all branches when rewriting risky repeated extglobs by
<a href="https://github.com/MerlijnW70"><code>@MerlijnW70</code></a> in
<a
href="https://redirect.github.com/micromatch/picomatch/pull/182">micromatch/picomatch#182</a></li>
<li>fix: honor the windows option when matching basenames by <a
href="https://github.com/MerlijnW70"><code>@MerlijnW70</code></a> in <a
href="https://redirect.github.com/micromatch/picomatch/pull/183">micromatch/picomatch#183</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/MerlijnW70"><code>@MerlijnW70</code></a> made
their first contribution in <a
href="https://redirect.github.com/micromatch/picomatch/pull/182">micromatch/picomatch#182</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/micromatch/picomatch/compare/4.0.4...4.0.5">https://github.com/micromatch/picomatch/compare/4.0.4...4.0.5</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4f41a8edad"><code>4f41a8e</code></a>
4.0.5</li>
<li><a
href="02cfc1bf91"><code>02cfc1b</code></a>
Update .verb.md and run verb to generate README documentation</li>
<li><a
href="cc52ff6e86"><code>cc52ff6</code></a>
Only run the upload code coverage step for 1 matrix permutation</li>
<li><a
href="6d426d7fe9"><code>6d426d7</code></a>
Allow workflow to continue if the code coverage step to fails</li>
<li><a
href="a00b954c04"><code>a00b954</code></a>
Merge branch 'codeql-coverage'</li>
<li><a
href="96803818ca"><code>9680381</code></a>
Merge pull request <a
href="https://redirect.github.com/micromatch/picomatch/issues/183">#183</a>
from MerlijnW70/fix/matchbase-windows-basename</li>
<li><a
href="648b4f2f13"><code>648b4f2</code></a>
Merge pull request <a
href="https://redirect.github.com/micromatch/picomatch/issues/182">#182</a>
from MerlijnW70/fix/repeated-extglob-drops-branches</li>
<li><a
href="70e6485a54"><code>70e6485</code></a>
Configure code coverage upload for CodeQL</li>
<li><a
href="ab8bc4df81"><code>ab8bc4d</code></a>
fix: honor the windows option when matching basenames</li>
<li><a
href="628930764f"><code>6289307</code></a>
fix: preserve all branches when rewriting risky repeated extglobs</li>
<li>Additional commits viewable in <a
href="https://github.com/micromatch/picomatch/compare/4.0.4...4.0.5">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
## Problem
When `claude-agent-acp` runs against a Bedrock or Vertex deployment
where the
enterprise enforces **short model aliases** in `availableModels` (e.g.
`claude-opus-4-6`), session creation fails immediately with:
```
API Error (claude-opus-4-6): 400 The provided model identifier is invalid.
Try switching to us.anthropic.claude-opus-4-5-20251101-v1:0.
```
### Root cause
`applyAvailableModelsAllowlist` rewrites each allowlisted model's
`value` to the
user's literal entry (the short alias), and that value is what gets
passed to
`query.setModel()`. The provider API rejects short aliases — it requires
provider-specific IDs such as `global.anthropic.claude-opus-4-6-v1[1m]`.
The `modelOverrides` map — which exists precisely to translate aliases
to
provider IDs — was never consulted during allowlist resolution. So even
with a
correct `modelOverrides` configured (via `settings.json` or
`CLAUDE_MODEL_CONFIG`),
the alias still reached the API unchanged.
This is reproducible on the Amazon-internal Toolbox Claude distribution,
which
regenerates `~/.claude/settings.json` on every launch with
`availableModels`
pinned to short aliases — so editing `settings.json` cannot work around
it.
### Trace (with temporary debug logging)
```
settings.model = "global.anthropic.claude-opus-4-6-v1[1m]" (desired)
getAvailableModels currentModel.value = "claude-opus-4-6" (WRONG)
calling query.setModel("claude-opus-4-6") (rejected)
```
## Fix
`applyAvailableModelsAllowlist` now accepts `settings.modelOverrides`.
When an
allowlist alias has an override mapping, the **overridden provider ID**
becomes
the surfaced model value, so `setModel` passes an ID the provider
accepts.
After the fix:
```
getAvailableModels currentModel.value = "global.anthropic.claude-opus-4-6-v1[1m]"
calling query.setModel("global.anthropic.claude-opus-4-6-v1[1m]")
```
and `acpx claude exec "what model are you using?"` responds normally:
> I'm running on Claude Opus 4.6 with a 1M token context window.
## Testing
- Added a regression test (`maps allowlist aliases through
modelOverrides to
provider IDs`) under the existing `availableModels allowlist from
settings`
suite.
- Full suite: `411 passed | 17 skipped`.
- `npm run check` (eslint + prettier) clean.
- `tsc` build clean.
- Manually verified end-to-end via `acpx` against a Bedrock-routed
Toolbox
Claude binary.
---------
Co-authored-by: Hao Zhou <zhuha@amazon.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Bumps the minor group with 1 update:
[prettier](https://github.com/prettier/prettier).
Updates `prettier` from 3.9.1 to 3.9.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.9.3</h2>
<ul>
<li>Markdown: Fix unexpected removal of characters in liquid syntax (<a
href="https://redirect.github.com/prettier/prettier/pull/19489">prettier/prettier#19489</a>
by <a href="https://github.com/seiyab"><code>@seiyab</code></a>)</li>
<li>TypeScript: Allow decorators to be used with declare on class fields
(<a
href="https://redirect.github.com/prettier/prettier/pull/19492">prettier/prettier#19492</a>
by <a
href="https://github.com/evoactivity"><code>@evoactivity</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.9.3/CHANGELOG.md#393">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.9.3</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.9.1...3.9.3">diff</a></p>
<h4>Markdown: Fix unexpected removal of characters in liquid syntax (<a
href="https://redirect.github.com/prettier/prettier/pull/19489">#19489</a>
by <a href="https://github.com/seiyab"><code>@seiyab</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="md"><code>// Input
<!-- Input -->
{{ page.title
}} text
<p><!-- Prettier 3.9.1 --><br />
{{ page.title<br />
text</p>
<p><!-- Prettier 3.9.3 --><br />
{{ page.title<br />
}} text<br />
</code></pre></p>
<h4>TypeScript: Allow decorators to be used with declare on class fields
(<a
href="https://redirect.github.com/prettier/prettier/pull/19492">#19492</a>
by <a
href="https://github.com/evoactivity"><code>@evoactivity</code></a>)</h4>
<p>Extensively used within the Ember ecosystem, decorators with
<code>declare</code> on class fields will ignore the babel parser error
and allow Prettier to format the code without breaking it.</p>
<!-- raw HTML omitted -->
<pre lang="ts"><code>// Input
export default class ProjectStatusComponent extends
Component<ProjectStatusSig> {
@service declare server: ServerService;
}
<p>// Prettier 3.9.1<br />
// SyntaxError: Decorators can't be used with a declare field. (2:3)<br
/>
// 1 | export default class ProjectStatusComponent extends
Component<ProjectStatusSig> {<br />
//> 2 | <a
href="https://github.com/service"><code>@service</code></a> declare
server: ServerService;<br />
// | ^<br />
// 3 | }</p>
<p>// Prettier 3.9.3<br />
export default class ProjectStatusComponent extends
Component<ProjectStatusSig> {<br />
<a href="https://github.com/service"><code>@service</code></a> declare
server: ServerService;<br />
}<br />
</code></pre></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3732e1dee6"><code>3732e1d</code></a>
Release 3.9.3</li>
<li><a
href="a74a7b05de"><code>a74a7b0</code></a>
Allow decorators to be used with <code>declare</code> on class fields
(<a
href="https://redirect.github.com/prettier/prettier/issues/19492">#19492</a>)</li>
<li><a
href="bd9e11ab41"><code>bd9e11a</code></a>
Correct text identification in liquid syntax (<a
href="https://redirect.github.com/prettier/prettier/issues/19489">#19489</a>)</li>
<li><a
href="269eee3faa"><code>269eee3</code></a>
Bump Prettier dependency to 3.9.1</li>
<li><a
href="ec7ccd1ea4"><code>ec7ccd1</code></a>
Clean changelog_unreleased</li>
<li>See full diff in <a
href="https://github.com/prettier/prettier/compare/3.9.1...3.9.3">compare
view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
The Claude Agent SDK changed the timing of `canUseTool` — it now runs
*before* the assistant message's `tool_use` block streams to us. As a
result we sent a permission request (and `AskUserQuestion` elicitation)
referencing a `toolCallId` the client had not yet seen via a `tool_call`
update, so clients couldn't associate the prompt with a tool call.
This supersedes #815, which fixed the ordering by blocking `canUseTool`
until the stream emitted the `tool_call`. That approach could deadlock
on cancellation (the `await` had no signal/timeout) and woke the waiter
from only one branch, so suppressed tools never resolved it.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.191` | `0.3.193` |
| [prettier](https://github.com/prettier/prettier) | `3.8.4` | `3.8.5` |
| @anthropic-ai/claude-agent-sdk-darwin-arm64 | `0.3.191` | `0.3.193` |
| @anthropic-ai/claude-agent-sdk-darwin-x64 | `0.3.191` | `0.3.193` |
| @anthropic-ai/claude-agent-sdk-linux-arm64 | `0.3.191` | `0.3.193` |
| @anthropic-ai/claude-agent-sdk-linux-arm64-musl | `0.3.191` |
`0.3.193` |
| @anthropic-ai/claude-agent-sdk-linux-x64 | `0.3.191` | `0.3.193` |
| @anthropic-ai/claude-agent-sdk-linux-x64-musl | `0.3.191` | `0.3.193`
|
| @anthropic-ai/claude-agent-sdk-win32-arm64 | `0.3.191` | `0.3.193` |
| @anthropic-ai/claude-agent-sdk-win32-x64 | `0.3.191` | `0.3.193` |
| [range-parser](https://github.com/jshttp/range-parser) | `1.2.1` |
`1.3.0` |
Updates `@anthropic-ai/claude-agent-sdk` from 0.3.191 to 0.3.193
<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.193</h2>
<h2>What's changed</h2>
<ul>
<li>Added <code>promptSuggestions</code> option to Browser SDK
<code>query()</code> to opt the remote CLI into emitting follow-up
suggestions</li>
<li>Fixed brief console window flashes on Windows when spawning CLI
subprocesses</li>
</ul>
<h2>Update</h2>
<pre lang="sh"><code>npm install @anthropic-ai/claude-agent-sdk@0.3.193
# or
yarn add @anthropic-ai/claude-agent-sdk@0.3.193
# or
pnpm add @anthropic-ai/claude-agent-sdk@0.3.193
# or
bun add @anthropic-ai/claude-agent-sdk@0.3.193
</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.193</h2>
<ul>
<li>Added <code>promptSuggestions</code> option to Browser SDK
<code>query()</code> to opt the remote CLI into emitting follow-up
suggestions</li>
<li>Fixed brief console window flashes on Windows when spawning CLI
subprocesses</li>
</ul>
<h2>0.3.192</h2>
<ul>
<li>Updated to parity with Claude Code v2.1.192</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="761e2bec6f"><code>761e2be</code></a>
chore: Update CHANGELOG.md</li>
<li>See full diff in <a
href="https://github.com/anthropics/claude-agent-sdk-typescript/compare/v0.3.191...v0.3.193">compare
view</a></li>
</ul>
</details>
<br />
Updates `prettier` from 3.8.4 to 3.8.5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.8.5</h2>
<ul>
<li>Fix Flow variance annotation print (<a
href="https://redirect.github.com/prettier/prettier/pull/19022">#19022</a>
by <a
href="https://github.com/marcoww6"><code>@marcoww6</code></a>)</li>
</ul>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/3.8.5/CHANGELOG.md#385">Changelog</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.8.5</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.8.4...3.8.5">diff</a></p>
<h4>Flow: Support <code>readonly</code> as a variance annotation (<a
href="https://redirect.github.com/prettier/prettier/pull/19022">#19022</a>
by <a
href="https://github.com/marcoww6"><code>@marcoww6</code></a>)</h4>
<p>Flow now accepts <code>readonly</code> as a property variance
annotation, equivalent to <code>+</code> (covariant/read-only).</p>
<!-- raw HTML omitted -->
<pre lang="jsx"><code>// Input
type T = {
readonly foo: string,
};
<p>// Prettier 3.8.4<br />
SyntaxError</p>
<p>// Prettier 3.8.5<br />
type T = {<br />
readonly foo: string,<br />
};<br />
</code></pre></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1ce8c47015"><code>1ce8c47</code></a>
Release 3.8.5</li>
<li><a
href="74923fa831"><code>74923fa</code></a>
Fix variance annotation</li>
<li><a
href="8b4eb339d4"><code>8b4eb33</code></a>
Bump Prettier dependency to 3.8.4</li>
<li><a
href="e9cbdfa1b7"><code>e9cbdfa</code></a>
Clean changelog_unreleased</li>
<li>See full diff in <a
href="https://github.com/prettier/prettier/compare/3.8.4...3.8.5">compare
view</a></li>
</ul>
</details>
<br />
Updates `@anthropic-ai/claude-agent-sdk-darwin-arm64` from 0.3.191 to
0.3.193
Updates `@anthropic-ai/claude-agent-sdk-darwin-x64` from 0.3.191 to
0.3.193
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64` from 0.3.191 to
0.3.193
Updates `@anthropic-ai/claude-agent-sdk-linux-arm64-musl` from 0.3.191
to 0.3.193
Updates `@anthropic-ai/claude-agent-sdk-linux-x64` from 0.3.191 to
0.3.193
Updates `@anthropic-ai/claude-agent-sdk-linux-x64-musl` from 0.3.191 to
0.3.193
Updates `@anthropic-ai/claude-agent-sdk-win32-arm64` from 0.3.191 to
0.3.193
Updates `@anthropic-ai/claude-agent-sdk-win32-x64` from 0.3.191 to
0.3.193
Updates `range-parser` from 1.2.1 to 1.3.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jshttp/range-parser/releases">range-parser's
releases</a>.</em></p>
<blockquote>
<h2>v1.3.0</h2>
<p><strong>Fixed</strong></p>
<ul>
<li>Improve number parsing (<a
href="https://redirect.github.com/jshttp/range-parser/issues/58">#58</a>)
eba9c7a</li>
<li>Handle invalid start and end byte positions in range parsing (<a
href="https://redirect.github.com/jshttp/range-parser/issues/57">#57</a>)
269cb4e</li>
</ul>
<hr />
<p><a
href="https://github.com/jshttp/range-parser/compare/v1.2.1...v1.3.0">https://github.com/jshttp/range-parser/compare/v1.2.1...v1.3.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="f4bf1736f2"><code>f4bf173</code></a>
Clamp a suffix whose length exceeds the representation (<a
href="https://redirect.github.com/jshttp/range-parser/issues/66">#66</a>)</li>
<li><a
href="b49e00f6d3"><code>b49e00f</code></a>
fix: still show ranges if there are multiple ranges, even if some are
invalid...</li>
<li><a
href="4f3b09123c"><code>4f3b091</code></a>
Remove dependabot config (<a
href="https://redirect.github.com/jshttp/range-parser/issues/60">#60</a>)</li>
<li><a
href="eba9c7a9cb"><code>eba9c7a</code></a>
Improve number parsing (<a
href="https://redirect.github.com/jshttp/range-parser/issues/58">#58</a>)</li>
<li><a
href="269cb4eafa"><code>269cb4e</code></a>
fix: handle invalid start and end byte positions in range parsing (<a
href="https://redirect.github.com/jshttp/range-parser/issues/57">#57</a>)</li>
<li><a
href="098e332bfc"><code>098e332</code></a>
build(deps): bump github/codeql-action from 3.31.2 to 4.31.6 (<a
href="https://redirect.github.com/jshttp/range-parser/issues/50">#50</a>)</li>
<li><a
href="3599369124"><code>3599369</code></a>
build(deps): bump actions/checkout from 3.6.0 to 6.0.0 (<a
href="https://redirect.github.com/jshttp/range-parser/issues/51">#51</a>)</li>
<li><a
href="054ea57071"><code>054ea57</code></a>
build(deps): bump github/codeql-action from 2.23.2 to 4.31.2 (<a
href="https://redirect.github.com/jshttp/range-parser/issues/48">#48</a>)</li>
<li><a
href="d230b16695"><code>d230b16</code></a>
build(deps): bump actions/upload-artifact from 3.1.3 to 5.0.0 (<a
href="https://redirect.github.com/jshttp/range-parser/issues/49">#49</a>)</li>
<li><a
href="54f84f423b"><code>54f84f4</code></a>
chore: add funding to package.json (<a
href="https://redirect.github.com/jshttp/range-parser/issues/42">#42</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/jshttp/range-parser/compare/v1.2.1...v1.3.0">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~blakeembrey">blakeembrey</a>, a new
releaser for range-parser since your current version.</p>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
</details>
---------
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
* announce resumed subagent generations when they start ([#1173](https://github.com/agentclientprotocol/claude-agent-acp/issues/1173)) ([b495e55](https://github.com/agentclientprotocol/claude-agent-acp/commit/b495e55a2249f066dab76e56316080f151df99be))
* continue clear-context plans approved in a background followup ([#1170](https://github.com/agentclientprotocol/claude-agent-acp/issues/1170)) ([a2c362c](https://github.com/agentclientprotocol/claude-agent-acp/commit/a2c362c948511b203b43982f13ab068ba14741ea))
* gate login result text on error state ([#1103](https://github.com/agentclientprotocol/claude-agent-acp/issues/1103)) ([6e97e07](https://github.com/agentclientprotocol/claude-agent-acp/commit/6e97e071c581002b43d9556dbd1d1376ebf9516f))
* include model on usage updates ([#1032](https://github.com/agentclientprotocol/claude-agent-acp/issues/1032)) ([da11f1f](https://github.com/agentclientprotocol/claude-agent-acp/commit/da11f1feb269b93f13fde7470f2b5a1b070867a9))
* keep the agent starting when the managed-policy tier cannot be read ([#1146](https://github.com/agentclientprotocol/claude-agent-acp/issues/1146)) ([58c5db1](https://github.com/agentclientprotocol/claude-agent-acp/commit/58c5db1fdc1b6fbce27224523fddebd3c52a65dd))
* mark informational chunks with metadata ([#1055](https://github.com/agentclientprotocol/claude-agent-acp/issues/1055)) ([bd059c1](https://github.com/agentclientprotocol/claude-agent-acp/commit/bd059c10e042c126933f27abd33f5523f39fab72))
* offer bypass alongside auto in plan approval ([#1164](https://github.com/agentclientprotocol/claude-agent-acp/issues/1164)) ([43c27e9](https://github.com/agentclientprotocol/claude-agent-acp/commit/43c27e97aacd9b711aefcb4b84271bf872c2eea7))
* preserve context usage when quota is exhausted ([#1132](https://github.com/agentclientprotocol/claude-agent-acp/issues/1132)) ([39062b6](https://github.com/agentclientprotocol/claude-agent-acp/commit/39062b63ff3087fc7ce2655a9738450f5f61682c))
* publish effective mode after plan approval ([#1163](https://github.com/agentclientprotocol/claude-agent-acp/issues/1163)) ([a2f4239](https://github.com/agentclientprotocol/claude-agent-acp/commit/a2f4239543b22d0928fbdbef7a9c7a4854b3d61d))
* recreate resumed sessions when any session option changes ([#1097](https://github.com/agentclientprotocol/claude-agent-acp/issues/1097)) ([df38ccc](https://github.com/agentclientprotocol/claude-agent-acp/commit/df38cccae04ce4abb525447c5e8d9db78ffec61c))
* render Write tool calls that use path/file_text aliases ([#1161](https://github.com/agentclientprotocol/claude-agent-acp/issues/1161)) ([90cde4b](https://github.com/agentclientprotocol/claude-agent-acp/commit/90cde4b3974656794fbb274ac6ad8e57f701e618))
* settle steered turns on the result that answers the steer ([#1166](https://github.com/agentclientprotocol/claude-agent-acp/issues/1166)) ([9392c69](https://github.com/agentclientprotocol/claude-agent-acp/commit/9392c69cc66591ade56a08200d807577180aa682))
* **deps:** update Claude SDK ([#1157](https://github.com/agentclientprotocol/claude-agent-acp/issues/1157)) ([eb989e9](https://github.com/agentclientprotocol/claude-agent-acp/commit/eb989e93f4e20315a85405ef099f97eec899df13))
* Send experimental session notices for live advisories ([#1155](https://github.com/agentclientprotocol/claude-agent-acp/issues/1155)) ([79851b8](https://github.com/agentclientprotocol/claude-agent-acp/commit/79851b86685b8a0673dec54d85d6fa2a3b749cfb))
* Update to claude agent sdk 0.3.274 ([#1143](https://github.com/agentclientprotocol/claude-agent-acp/issues/1143)) ([d0fa8e0](https://github.com/agentclientprotocol/claude-agent-acp/commit/d0fa8e03853c4f5a9b074fc2af32931ffe6f588f))
### Bug Fixes
* show shell commands in permission prompts ([#1070](https://github.com/agentclientprotocol/claude-agent-acp/issues/1070)) ([bbae5c2](https://github.com/agentclientprotocol/claude-agent-acp/commit/bbae5c2c0936554104b07630b142fd71fe1d839e))
* Add experimental ACP compaction update support ([#1134](https://github.com/agentclientprotocol/claude-agent-acp/issues/1134)) ([543a9a2](https://github.com/agentclientprotocol/claude-agent-acp/commit/543a9a2f97429659bb28d09691a71e4c99e41ed5))
### Bug Fixes
* keep the picked option when AskUserQuestion custom text is also supplied ([#1131](https://github.com/agentclientprotocol/claude-agent-acp/issues/1131)) ([8823ea6](https://github.com/agentclientprotocol/claude-agent-acp/commit/8823ea6fcb6743d37c1aad91ccd44725164b8927))
### Performance Improvements
* report file changes from Claude checkpoints ([#1138](https://github.com/agentclientprotocol/claude-agent-acp/issues/1138)) ([91f1699](https://github.com/agentclientprotocol/claude-agent-acp/commit/91f1699366ee98f9b3e9a6b96f0662c40b6ee38e))
* supply AIR diff counts from Claude structured patches ([#1122](https://github.com/agentclientprotocol/claude-agent-acp/issues/1122)) ([735950a](https://github.com/agentclientprotocol/claude-agent-acp/commit/735950a83ee1fa25366515a3239482183a051dca))
* 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)) ([67c7c9b](https://github.com/agentclientprotocol/claude-agent-acp/commit/67c7c9b117af7464fd5d583f719bf6214a5508a8))
* **deps:** Bump @anthropic-ai/claude-agent-sdk to 0.3.270 ([#1123](https://github.com/agentclientprotocol/claude-agent-acp/issues/1123)) ([d3205ab](https://github.com/agentclientprotocol/claude-agent-acp/commit/d3205ab11f873f58e50dddbf13f6d7c555a9f478))
### Bug Fixes
* keep multi-select answers when a custom answer is typed ([#1031](https://github.com/agentclientprotocol/claude-agent-acp/issues/1031)) ([1a4512c](https://github.com/agentclientprotocol/claude-agent-acp/commit/1a4512c71199709f6c59bd56c2c67aba63fe243d))
* parse TaskList output without ambiguous regex ([#1006](https://github.com/agentclientprotocol/claude-agent-acp/issues/1006)) ([b274923](https://github.com/agentclientprotocol/claude-agent-acp/commit/b274923ef84a5a39b4ab3d12b3d10a8fa23f51f6))
* strip injected system reminders from replayed prompts ([#1040](https://github.com/agentclientprotocol/claude-agent-acp/issues/1040)) ([15ba608](https://github.com/agentclientprotocol/claude-agent-acp/commit/15ba608a79b2cdfdb94c04ce1ebe03cfdae2fb51))
* **deps-dev:** Bump vitest from 4.1.11 to 5.0.0 ([#1099](https://github.com/agentclientprotocol/claude-agent-acp/issues/1099)) ([194e195](https://github.com/agentclientprotocol/claude-agent-acp/commit/194e195b057497311558fea2a5fbd1b4953ea29d))
* **deps:** Bump fast-uri from 3.1.6 to 3.1.7 ([#1100](https://github.com/agentclientprotocol/claude-agent-acp/issues/1100)) ([d870ebd](https://github.com/agentclientprotocol/claude-agent-acp/commit/d870ebd2fd14bda95f81ec4b86d76ef4ae258005))
* restore session forks and speed up loading ([#1089](https://github.com/agentclientprotocol/claude-agent-acp/issues/1089)) ([f5e79f5](https://github.com/agentclientprotocol/claude-agent-acp/commit/f5e79f55f8ba8d1cd0a72cbc78bfea726bea2f00))
* add ai generated session title ([#984](https://github.com/agentclientprotocol/claude-agent-acp/issues/984)) ([d334766](https://github.com/agentclientprotocol/claude-agent-acp/commit/d334766ef95dd89201979d42252e3d2a5a259cb9))
* align Claude modes and clear-context planning ([#1004](https://github.com/agentclientprotocol/claude-agent-acp/issues/1004)) ([996d488](https://github.com/agentclientprotocol/claude-agent-acp/commit/996d488589b8db7a0f9af3dfc7b886d9d47ebae9))
* **deps:** Bump @anthropic-ai/claude-agent-sdk to 0.3.238 ([#1018](https://github.com/agentclientprotocol/claude-agent-acp/issues/1018)) ([ee9f300](https://github.com/agentclientprotocol/claude-agent-acp/commit/ee9f300db4562e8b7958cec9fa63dab05a5c2eb0))
* expose native subagents and async tasks ([#1017](https://github.com/agentclientprotocol/claude-agent-acp/issues/1017)) ([14d192d](https://github.com/agentclientprotocol/claude-agent-acp/commit/14d192d1087ea8662392b5c61c9fcdd496c5a179))
* report per-model token usage on prompt responses ([#1037](https://github.com/agentclientprotocol/claude-agent-acp/issues/1037)) ([fad4d10](https://github.com/agentclientprotocol/claude-agent-acp/commit/fad4d10e46c5e65fc6d426c98074bbb76067bf25))
* support message-specific ACP session forks ([#1046](https://github.com/agentclientprotocol/claude-agent-acp/issues/1046)) ([c3ff343](https://github.com/agentclientprotocol/claude-agent-acp/commit/c3ff3438844f5249d6a7f5c297906e2cd3d5fa7f))
### Bug Fixes
* change min zod version to 4.x to avoid failing directory imports on 'v4' ([#1057](https://github.com/agentclientprotocol/claude-agent-acp/issues/1057)) ([7c66108](https://github.com/agentclientprotocol/claude-agent-acp/commit/7c6610835f26f18cd162b78dff74a7b7cd74497a))
* defer steering while user input is pending ([#1045](https://github.com/agentclientprotocol/claude-agent-acp/issues/1045)) ([8710ce1](https://github.com/agentclientprotocol/claude-agent-acp/commit/8710ce1cbccf562cb04b4bcc30e053e960aee05f))
* switch providers for loaded Claude sessions ([#1002](https://github.com/agentclientprotocol/claude-agent-acp/issues/1002)) ([50a9543](https://github.com/agentclientprotocol/claude-agent-acp/commit/50a95434e94318456f2d07c3d21aaf3595c3407d))
* report changed files to AIR ([#1001](https://github.com/agentclientprotocol/claude-agent-acp/issues/1001)) ([450d6b1](https://github.com/agentclientprotocol/claude-agent-acp/commit/450d6b19dc46a041128356a6fa3cfa3ce6a5a382))
* align typed session failures with AIR protocol ([#992](https://github.com/agentclientprotocol/claude-agent-acp/issues/992)) ([0581b9c](https://github.com/agentclientprotocol/claude-agent-acp/commit/0581b9cf397ffd88f2830db721c2d8e3689045e4))
* **deps:** Update to @anthropic-ai/claude-agent-sdk v0.3.232 ([#993](https://github.com/agentclientprotocol/claude-agent-acp/issues/993)) ([de0d0e2](https://github.com/agentclientprotocol/claude-agent-acp/commit/de0d0e2b7d185c521c3d1ac7b86e4312c919abfe))
* expose typed session failures for AIR ([#979](https://github.com/agentclientprotocol/claude-agent-acp/issues/979)) ([8157ee1](https://github.com/agentclientprotocol/claude-agent-acp/commit/8157ee113e705750be4eb6cc787bdd12f1db84ff))
* publish the model fallback as a warning advisory ([#990](https://github.com/agentclientprotocol/claude-agent-acp/issues/990)) ([35aaddb](https://github.com/agentclientprotocol/claude-agent-acp/commit/35aaddb3d5b14eca316582ab285af8a660150dae))
* surface resolved model name in default model option description ([#982](https://github.com/agentclientprotocol/claude-agent-acp/issues/982)) ([ec73cd8](https://github.com/agentclientprotocol/claude-agent-acp/commit/ec73cd8560be7d5e8b9741e404d7d45e17336996))
* surface Skill tool calls with name and kind in _meta ([#986](https://github.com/agentclientprotocol/claude-agent-acp/issues/986)) ([1f09e9a](https://github.com/agentclientprotocol/claude-agent-acp/commit/1f09e9a3cae787b0effdfae0e7205ef7fe22b9dc))
### Bug Fixes
* preserve task plans across prompts ([#974](https://github.com/agentclientprotocol/claude-agent-acp/issues/974)) ([1afa940](https://github.com/agentclientprotocol/claude-agent-acp/commit/1afa940a2c8c0f4c610f4f64d30c0961642907b0))
* show a pending title while Claude prepares a file ([#978](https://github.com/agentclientprotocol/claude-agent-acp/issues/978)) ([3df1ede](https://github.com/agentclientprotocol/claude-agent-acp/commit/3df1ede89f217312bc237124dc1eccc10c860f99))
* **deps-dev:** Bump globals from 17.8.0 to 17.9.0 in the minor group ([#960](https://github.com/agentclientprotocol/claude-agent-acp/issues/960)) ([7f27c47](https://github.com/agentclientprotocol/claude-agent-acp/commit/7f27c47c5c7c49e65014e9f7dc55cba17352d33b))
* publish and replace Claude goals reliably ([#967](https://github.com/agentclientprotocol/claude-agent-acp/issues/967)) ([f8fd3ab](https://github.com/agentclientprotocol/claude-agent-acp/commit/f8fd3ab8224420f8ced570e974cde09612939d6b))
* **deps-dev:** Bump nanoid from 3.3.16 to 3.3.17 ([#951](https://github.com/agentclientprotocol/claude-agent-acp/issues/951)) ([b965dd2](https://github.com/agentclientprotocol/claude-agent-acp/commit/b965dd21917e822b56f5012c3572902f26c065c9))
* **deps-dev:** Bump tinyexec from 1.2.4 to 1.3.0 in the minor group ([#959](https://github.com/agentclientprotocol/claude-agent-acp/issues/959)) ([15b4eb4](https://github.com/agentclientprotocol/claude-agent-acp/commit/15b4eb46f329566837eae58f2ee4b05e3e81bf64))
* **deps:** Bump @hono/node-server from 1.19.17 to 2.1.0 ([#956](https://github.com/agentclientprotocol/claude-agent-acp/issues/956)) ([f9123f3](https://github.com/agentclientprotocol/claude-agent-acp/commit/f9123f3e18560b580398aabf49e2190f69746976))
* **deps:** Bump fast-uri from 3.1.4 to 3.1.5 ([#952](https://github.com/agentclientprotocol/claude-agent-acp/issues/952)) ([0988438](https://github.com/agentclientprotocol/claude-agent-acp/commit/098843842895dcb450746bd064dbb1509e3049d1))
* **steering:** settle a steered turn at idle, not at the interrupt ([#958](https://github.com/agentclientprotocol/claude-agent-acp/issues/958)) ([a84b810](https://github.com/agentclientprotocol/claude-agent-acp/commit/a84b81080a4127edf40bc448fc8bf2b15503304d))
* restore the single-tool representation for ExitPlanMode ([#942](https://github.com/agentclientprotocol/claude-agent-acp/issues/942)) ([4302a4b](https://github.com/agentclientprotocol/claude-agent-acp/commit/4302a4b0b6df821b164cbe4857f26cf5b44b532c))
* **deps:** Bump actions/checkout from 7.0.0 to 7.0.1 ([#925](https://github.com/agentclientprotocol/claude-agent-acp/issues/925)) ([8e099e8](https://github.com/agentclientprotocol/claude-agent-acp/commit/8e099e844254c3e91508c79a02e3e7dc2239fcbb))
* **deps:** Bump the minor group with 7 updates ([#928](https://github.com/agentclientprotocol/claude-agent-acp/issues/928)) ([3f60921](https://github.com/agentclientprotocol/claude-agent-acp/commit/3f609219592e63b947539f79c696b3cedb421060))
* Update to claude agent sdk v0.3.220 ([#921](https://github.com/agentclientprotocol/claude-agent-acp/issues/921)) ([4c7b897](https://github.com/agentclientprotocol/claude-agent-acp/commit/4c7b89718306229254879e5045a183233b5ed073))
### Bug Fixes
* Only resolve a denied tool call the client was told about ([#923](https://github.com/agentclientprotocol/claude-agent-acp/issues/923)) ([8f67b6a](https://github.com/agentclientprotocol/claude-agent-acp/commit/8f67b6a92bec24ae43b3dfbd087fe35df0531857)), closes [#918](https://github.com/agentclientprotocol/claude-agent-acp/issues/918)
* Report tool_progress heartbeats against the tool call they describe ([#916](https://github.com/agentclientprotocol/claude-agent-acp/issues/916)) ([5559ba8](https://github.com/agentclientprotocol/claude-agent-acp/commit/5559ba890ca614cdaa189500aba65d81cc4cd51a))
* **tools:** key Bash terminal metas off the announced tool_use id ([#917](https://github.com/agentclientprotocol/claude-agent-acp/issues/917)) ([d060414](https://github.com/agentclientprotocol/claude-agent-acp/commit/d0604140f907adbf9747f26a070690926e1de82d))
* **deps:** Bump @hono/node-server from 1.19.14 to 1.19.15 ([#908](https://github.com/agentclientprotocol/claude-agent-acp/issues/908)) ([5193604](https://github.com/agentclientprotocol/claude-agent-acp/commit/51936049e175274de8e0fd90bc1be2af988c3ca6))
* **deps:** Bump media-typer from 1.1.0 to 1.1.1 ([#909](https://github.com/agentclientprotocol/claude-agent-acp/issues/909)) ([5d35001](https://github.com/agentclientprotocol/claude-agent-acp/commit/5d35001563ffd702a29c3bac3b7ca134e40c77f8))
* **deps:** Bump the minor group with 2 updates ([#900](https://github.com/agentclientprotocol/claude-agent-acp/issues/900)) ([809d41c](https://github.com/agentclientprotocol/claude-agent-acp/commit/809d41c6b7c9e7ba3cb5b206d00793a70edba64a))
* **deps:** Bump the minor group with 2 updates ([#907](https://github.com/agentclientprotocol/claude-agent-acp/issues/907)) ([14d0627](https://github.com/agentclientprotocol/claude-agent-acp/commit/14d06273c01ad4ae944912e36700f6b5599c4c4d))
* Update to claude-agent-sdk 0.3.218 ([#904](https://github.com/agentclientprotocol/claude-agent-acp/issues/904)) ([8cbaf97](https://github.com/agentclientprotocol/claude-agent-acp/commit/8cbaf97254576089a3b5ee6ae222fb763003c01d))
* **deps:** Bump actions/setup-node from 6.4.0 to 7.0.0 ([#897](https://github.com/agentclientprotocol/claude-agent-acp/issues/897)) ([d9bd36d](https://github.com/agentclientprotocol/claude-agent-acp/commit/d9bd36d8b06764d63656d0387ad9430ec9fcb27d))
* **deps:** Update to @anthropic-ai/claude-agent-sdk 0.3.217 ([#899](https://github.com/agentclientprotocol/claude-agent-acp/issues/899)) ([edf3af0](https://github.com/agentclientprotocol/claude-agent-acp/commit/edf3af043b6d00e5caca2cc81a2285c477c8b2ab))
* parse Agent/Task trailers without regex ([#879](https://github.com/agentclientprotocol/claude-agent-acp/issues/879)) ([06c3d7b](https://github.com/agentclientprotocol/claude-agent-acp/commit/06c3d7bdbd8cc9415c8cabac060a50e0951c758b))
* remove ~15s stall on session/new and model switch by seeding the context window synchronously ([#894](https://github.com/agentclientprotocol/claude-agent-acp/issues/894)) ([ff9b96d](https://github.com/agentclientprotocol/claude-agent-acp/commit/ff9b96d462831b1c3b96722ea20215ff6e529cb1))
* **deps-dev:** bump nanoid from 3.3.15 to 3.3.16 ([#875](https://github.com/agentclientprotocol/claude-agent-acp/issues/875)) ([e67dacd](https://github.com/agentclientprotocol/claude-agent-acp/commit/e67dacdcac629b00e5bdcda94b3de57459696b1e))
* **deps:** bump @anthropic-ai/claude-agent-sdk to 0.3.207 ([#874](https://github.com/agentclientprotocol/claude-agent-acp/issues/874)) ([c7f5b8f](https://github.com/agentclientprotocol/claude-agent-acp/commit/c7f5b8fe768507afa28cdffe5cc3c054c56306ad))
### Bug Fixes
* Add subagent parent tool use attribution ([#859](https://github.com/agentclientprotocol/claude-agent-acp/issues/859)) ([9cd48c5](https://github.com/agentclientprotocol/claude-agent-acp/commit/9cd48c597af68f630774ec00bc3adc85f6b0fd4b))
* forward result text when the turn emitted no assistant message ([#858](https://github.com/agentclientprotocol/claude-agent-acp/issues/858)) ([61ae860](https://github.com/agentclientprotocol/claude-agent-acp/commit/61ae8609d4343da6758c2376c6cf684c7fb0956a))
* hold a turn open while its background subagents are still live ([#870](https://github.com/agentclientprotocol/claude-agent-acp/issues/870)) ([7a70f82](https://github.com/agentclientprotocol/claude-agent-acp/commit/7a70f82739e085014cad878f08513cdef7b7fe16))
* Refine tool calls from streamed input ([#867](https://github.com/agentclientprotocol/claude-agent-acp/issues/867)) ([2c19974](https://github.com/agentclientprotocol/claude-agent-acp/commit/2c19974d5b80d3178b35e80a4bb0a1050588aab9))
* Use valid npm version for publish ([#855](https://github.com/agentclientprotocol/claude-agent-acp/issues/855)) ([8b366d8](https://github.com/agentclientprotocol/claude-agent-acp/commit/8b366d8e9ad55e9237bf2d618cfc99b57fac570d))
* **deps:** update to @anthropic-ai/claude-agent-sdk 0.3.205 ([#854](https://github.com/agentclientprotocol/claude-agent-acp/issues/854)) ([f664ced](https://github.com/agentclientprotocol/claude-agent-acp/commit/f664ced76df00674d88aedd018a4261da3bc3f3a))
### Bug Fixes
* Preserve live model on resumed sessions ([#848](https://github.com/agentclientprotocol/claude-agent-acp/issues/848)) ([f3d8ae3](https://github.com/agentclientprotocol/claude-agent-acp/commit/f3d8ae3eb389ee9367f48c8762562a55280ade0a)), closes [#845](https://github.com/agentclientprotocol/claude-agent-acp/issues/845)
* Report usage for cancelled active turns ([#846](https://github.com/agentclientprotocol/claude-agent-acp/issues/846)) ([b03318f](https://github.com/agentclientprotocol/claude-agent-acp/commit/b03318f59c6165146c8d8e036227f35c3abd0ff4)), closes [#844](https://github.com/agentclientprotocol/claude-agent-acp/issues/844)
* tolerate missing text in streamed thinking chunks ([#852](https://github.com/agentclientprotocol/claude-agent-acp/issues/852)) ([e944ced](https://github.com/agentclientprotocol/claude-agent-acp/commit/e944ceddea79950d6bfb6339266862507c4b964f))
* Use SDK guards for elicitation validation ([#850](https://github.com/agentclientprotocol/claude-agent-acp/issues/850)) ([32b9350](https://github.com/agentclientprotocol/claude-agent-acp/commit/32b93501d7a35a3b405b5022b4caaad492eed11c))
* Add refusal fallback consent dialog support ([#834](https://github.com/agentclientprotocol/claude-agent-acp/issues/834)) ([15dfd83](https://github.com/agentclientprotocol/claude-agent-acp/commit/15dfd83daa84ced98ecbaa7c83fd5a53124030c1))
* **deps-dev:** bump the minor group with 3 updates ([#831](https://github.com/agentclientprotocol/claude-agent-acp/issues/831)) ([8d5febf](https://github.com/agentclientprotocol/claude-agent-acp/commit/8d5febf85485c1ad19b81501fb5c6d4275448a7c))
* Update to claude-agent-sdk 0.3.198 ([#836](https://github.com/agentclientprotocol/claude-agent-acp/issues/836)) ([307ab82](https://github.com/agentclientprotocol/claude-agent-acp/commit/307ab82712213413446466d808e161073e94fc7f))
### Bug Fixes
* Handle model refusal fallback updates ([#833](https://github.com/agentclientprotocol/claude-agent-acp/issues/833)) ([648e3f6](https://github.com/agentclientprotocol/claude-agent-acp/commit/648e3f60bd7e6eadb5f86b0dc475104ab12e7b02))
* Handle SDK idle turns without results ([#835](https://github.com/agentclientprotocol/claude-agent-acp/issues/835)) ([57b00cc](https://github.com/agentclientprotocol/claude-agent-acp/commit/57b00ccac610e2eeaf0a753934a0c3b78d27ccb0))
* Add Fast mode session config support ([#828](https://github.com/agentclientprotocol/claude-agent-acp/issues/828)) ([fa949a2](https://github.com/agentclientprotocol/claude-agent-acp/commit/fa949a20db0e33f2d63aebeb37e9fea212d8ee95))
* **deps-dev:** bump prettier from 3.9.1 to 3.9.3 in the minor group ([#821](https://github.com/agentclientprotocol/claude-agent-acp/issues/821)) ([b8df8e0](https://github.com/agentclientprotocol/claude-agent-acp/commit/b8df8e0e5460fd782214f4dde488f7476c80c454))
* **deps:** bump @anthropic-ai/claude-agent-sdk to 0.3.197 for Sonnet 5 ([#826](https://github.com/agentclientprotocol/claude-agent-acp/issues/826)) ([ef42c46](https://github.com/agentclientprotocol/claude-agent-acp/commit/ef42c46e5aea3bb53f433b9f9dd36a62a9f2df6a))
* **deps:** bump fast-uri from 3.1.2 to 3.1.3 ([#822](https://github.com/agentclientprotocol/claude-agent-acp/issues/822)) ([64aa130](https://github.com/agentclientprotocol/claude-agent-acp/commit/64aa130c66c299f9835193796ba372b3ed40e7c1))
* Add version flag handling ([#813](https://github.com/agentclientprotocol/claude-agent-acp/issues/813)) ([9616bda](https://github.com/agentclientprotocol/claude-agent-acp/commit/9616bdac47505e4a14c36d667fcffc9ae97e1f2a)), closes [#809](https://github.com/agentclientprotocol/claude-agent-acp/issues/809)
* **deps-dev:** bump expect-type from 1.3.0 to 1.4.0 in the minor group ([#814](https://github.com/agentclientprotocol/claude-agent-acp/issues/814)) ([61272ac](https://github.com/agentclientprotocol/claude-agent-acp/commit/61272acb30dcafaa2455d334b11ce2ad97339707))
* **deps:** Update @anthropic-ai/claude-agent-sdk to 0.3.191 ([#810](https://github.com/agentclientprotocol/claude-agent-acp/issues/810)) ([228f02e](https://github.com/agentclientprotocol/claude-agent-acp/commit/228f02ecfb23be16e59e121c6b42c0f2b2f40a4e))
* Push session title updates at turn end ([#812](https://github.com/agentclientprotocol/claude-agent-acp/issues/812)) ([1fe7ec0](https://github.com/agentclientprotocol/claude-agent-acp/commit/1fe7ec09a3a7bcb7501231dae4b0ffe6ef9b70a4))
* **deps:** bump the minor group with 11 updates ([#807](https://github.com/agentclientprotocol/claude-agent-acp/issues/807)) ([8f6ebd1](https://github.com/agentclientprotocol/claude-agent-acp/commit/8f6ebd1d9198edf723f4c8c1aa2b49b906c46646))
This document defines a provider-neutral experimental ACP extension implemented by `claude-agent-acp`. It is intentionally shaped like a possible future first-class ACP API: implementations publish `_meta.goal`, not provider-specific metadata such as `_meta.claudeCode.goal`.
## Capability negotiation
An agent advertises support in its `initialize` response:
```json
{
"_meta":{
"goal":{
"version":1,
"controlMethod":"_session/goal",
"actions":["clear"]
}
}
}
```
`actions` is the implementation-supported subset of `set`, `pause`, `resume`, and `clear`. Clients must not infer support for an action that is not advertised. The control request contains `sessionId` and `action`; a future version may add action-specific fields such as an objective for `set`.
## Session state
The current snapshot is published in `session_info_update._meta.goal`. Clearing a goal publishes `goal: null`.
```json
{
"objective":"Ship the change",
"status":"active",
"iterations":3,
"lastReason":"Tests still need work",
"createdAt":1710000000123,
"controlMethod":"_session/goal"
}
```
Common statuses are `active`, `paused`, `blocked`, `limited`, and `complete`. Optional fields allow implementations to report budgets, usage, iteration count, and the last continuation reason. Timestamps are Unix milliseconds.
## Lifecycle architecture
A goal belongs to the ACP session, not to an individual `session/prompt` request. Goal activity and prompt activity are independent:
-`status: active` means the persistent objective can drive more work; it does not mean an ACP prompt is currently executing.
- A prompt completes when its current backend turn reaches a quiescent boundary, even when the goal remains active.
- A later autonomous cycle may publish more session updates outside that completed prompt.
- While a turn is running, clients use steering or prompt queueing when advertised. While the session is quiescent, clients may send an ordinary `session/prompt`.
This separation prevents a persistent goal from monopolizing the session's prompt slot and lets clients model “working now” independently from “objective remains active.”
## Claude mapping
Claude's session-scoped `/goal` command installs a Stop hook. The runtime emits internal `active_goal` messages when that hook updates or clears its state; the adapter maps them into the neutral snapshot before the exhaustive SDK message switch. `condition`, `iterations`, `set_at`, and `last_reason` become `objective`, `iterations`, `createdAt`, and `lastReason`. Provider-only bookkeeping such as `tokens_at_start` is not exposed.
Some Claude runtime versions persist the goal and begin the Stop-hook workflow without emitting the initial `active_goal` message on the SDK stream. To avoid leaving clients without visible state for the whole long-running prompt, the adapter publishes a minimal active snapshot as soon as it submits `/goal <condition>`, and publishes `goal: null` for `/goal clear`. While that command is pending, late updates for the previous goal are ignored. A matching runtime `active_goal` remains authoritative and enriches the optimistic snapshot with iteration, reason, and timestamp fields; a failed command restores the previously published state.
`set` and `clear` are advertised for out-of-band control; pause and resume are not. When a goal turn is running, the adapter injects the corresponding `/goal` command at steering priority `now` so it cannot remain queued behind the Stop-hook workflow; on an idle session it uses the ordinary prompt lifecycle. Cancelling a turn does not clear the session-scoped goal: clients use the goal control method when they intend to replace or remove it.
| `defaultToNo` | no | `true` | The ask must not be approvable by a stray keystroke; the reject options are listed first and a client that pre-selects an option should focus the decline. |
The permission title normally duplicates `toolCall.title`: one operation has one heading across the
tool card and approval UI. `ExitPlanMode` is the deliberate exception and uses the action-oriented
permission heading `Ready to code?`. Commands, paths, URLs, and other structured details remain in
`rawInput`, `content`, and `locations`.
`description` temporarily carries the SDK's non-blank `decisionReason` for diagnostics, prefixed
with `Reason: `. The SDK `description` operation subtitle is not copied there.
## Tool-call presentation
The permission request carries the same standard ACP tool information used for normal tool updates:
-`name` is the SDK tool name (for example `Read` or `mcp__server__tool`), matching the standard
`name` field on the initial `tool_call` update;
-`kind`, `title`, `content`, and `locations` come from `toolInfoFromToolUse`;
-`status` is `pending`;
-`rawInput` is the original SDK input object;
-`blockedPath` is appended to `locations` when it is valid and not already present;
- subagent calls include `_meta.claudeCode.parentToolUseId` on the tool call;
- Sandbox Network and Computer Use requests synthesize JSON content when the normal renderer has no
content.
Compact text removes control characters, collapses whitespace where appropriate, and enforces length
limits. Invalid optional presentation text is omitted instead of being truncated into misleading UI.
Shell permission titles (`Bash` and `PowerShell`) preserve the full command verbatim, including
whitespace and line breaks, without applying compact-text normalization or length limits.
Permission options are fixed. When a durable suggestion contains a command prefix, path, host, or
other rule, the adapter includes that value directly in `PermissionOption.name`, for example
`Yes, and don't ask again for npm test commands`. Selecting the option applies the exact snapshotted
Claude SDK `PermissionUpdate`; the client cannot edit it. A selected reject is distinct from
`{ "outcome": "cancelled" }`: cancellation aborts the tool use instead of returning a user rejection.
"Command running in background with ID: bpux8xmfg. Output is being written to: /private/tmp/claude/tasks/bpux8xmfg.output. You will be notified when it completes.",
"This session is being continued from a previous conversation that ran out of context. The summary below covers the earlier portion of the conversation.\n\n"+
"Summary:\n1. Primary Request and Intent:\n Count upward.\n\n2. Optional Next Step:\n None.\n\n"+
"If you need specific details from before compaction (like exact code snippets, error messages, or content you generated), read the full transcript at: /tmp/session.jsonl\n"+
"Continue the conversation from where it left off without asking the user any further questions. Resume directly — do not acknowledge the summary, do not recap what was happening.";
"1. Primary Request and Intent:\n Count upward.\n\n2. Optional Next Step:\n None.",
);
});
it("strips the older tagged transcript framing",()=>{
expect(
compactionSummaryText(
"This session is being continued from a previous conversation that ran out of context. The conversation is summarized below:\n<summary>\nOld style body.\n</summary>\nPlease continue the conversation from where it left it off without asking the user any further questions.",
),
).toBe("Old style body.");
});
it("fails closed on a continuation prompt whose framing it does not recognize",()=>{
expect(
compactionSummaryText(
"This session is being continued from a previous conversation that ran out of context. Here is what happened:\n\nThe user counted.\n\nResume directly.",
),
).toBeUndefined();
});
it("strips a leading analysis block even when the summary tags are missing",()=>{
expect(
compactionSummaryText(
"<analysis>\nPrivate reasoning about <summary> tags.\n</analysis>\n\n1. Primary Request:\n Count.",
{"type":"user","uuid":"11111111-1111-4111-8111-111111111111","parentUuid":null,"sessionId":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","timestamp":"2026-01-01T00:00:00.000Z","message":{"role":"user","content":[{"type":"text","text":"Create a short HTML page"}]}}
{"type":"assistant","uuid":"22222222-2222-4222-8222-222222222222","parentUuid":"11111111-1111-4111-8111-111111111111","sessionId":"aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa","timestamp":"2026-01-01T00:00:01.000Z","error":"rate_limit","isApiErrorMessage":true,"message":{"id":"msg_usage_limit","type":"message","role":"assistant","model":"<synthetic>","content":[{"type":"text","text":"You've hit your individual spend limit · run /usage-credits to ask your admin for a higher limit"}],"stop_reason":"stop_sequence","stop_sequence":null,"usage":{"input_tokens":0,"output_tokens":0,"cache_read_input_tokens":0,"cache_creation_input_tokens":0}}}
expect.stringContaining("/investigate-alert kafka lag on prod-3"),
{persist: true},
);
expect(titles()).toEqual(["Investigate Kafka lag alert on prod-3"]);
});
});
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.