SIGN IN SIGN UP

feat(acp): consume Claude's async background-task lifecycle

claude-agent-acp 0.73.0 publishes the lifecycle of Claude's non-agent
background work — background shells, workflows, monitors — as three new
`session/update` variants, gated on the AIR `asyncTasks` capability.
Advertise it (claude only; codex-acp 1.8.0 has no such channel) and read
the frames.

This is not a nicer rendering of something codeg already had. The
transcript watcher can see that a task was launched but explicitly cannot
tell a live task from one whose CLI died, it never sees workflow/monitor
tasks at all, and nothing could stop a task once started. The channel
carries a real terminal edge, an output file path, and
`_session/async_task/stop`.

The frames are consumed BEFORE `MatchDispatch`, beside
`fix_usage_update_nulls`, because that is the only way to see them:
`if_notification` matches on the method and then hard-errors on unparsed
params, and schema 0.11.7's `SessionUpdate` has no catch-all arm. Left
alone they would land on the dropped-update path, which also feeds the
empty-turn diagnosis — a turn that only launched background work would be
reported as an agent that said nothing.

The three variants collapse into one delta type merged in
`apply_event`, so there is a single merge rule and the snapshot a client
attaches to is the same projection a client that saw every frame holds.
Only a `spawned` delta may create a row; rows are retained after they
settle, because the adapter revises finished tasks and an evicted one
would come back nameless.

A live task now defers the idle sweep on its own. That combines with the
transcript watcher's accounting by OR, never a sum: the two observe
overlapping work through different channels, and reaping an idle
connection kills the agent CLI and the background work with it.
X
xintaofei committed
52818ca4e705825432dc34c0217dfb7eb1e7859f
Parent: fece4e8