AFT v0.29.0 is the compression-overhaul release: a fundamental dispatch fix lifts existing compressors out of silent failure on real-world bash invocations, eight new tool-specific compressors land alongside seven new TOML filters for high-leverage tools agents actually run, and `bun test` learns to keep output from chained shell commands.

## Specificity-based compressor dispatch

Until v0.29, package-manager compressors (`bun`, `npm`, `pnpm`) claimed any command starting with their head token — so `bun run vitest`, `npm test`, and `pnpm test` were silently routed through the package-manager fallback path instead of through the specific test-runner compressors that knew how to keep failure detail.

v0.29 introduces a two-tier dispatch system:

- **Specific** compressors (vitest, eslint, biome, pytest, tsc, plus the seven new ones below) match by token-anywhere and win first.
- **PackageManager** compressors (bun, npm, pnpm) match by head-token and run only if no Specific match was found.

This means `bun run vitest --reporter=verbose` now compresses through the Vitest reporter logic, not the generic Bun fallback. The same fix unlocks `npm test`, `pnpm test`, `pnpm run typecheck`, and similar idiomatic invocations that were never reaching their intended compressor.

## Shell-prefix normalization

A real-DB sweep of 165 historical bash invocations found that **~21% of `bun test` calls** and **~7% of `npm` calls** were wrapped in shell-prefix idioms agents reach for routinely:

- `cd /path && bun test`
- `env FOO=bar npm install`
- `timeout 30 cargo build`
- `(cd /path; cmd)`
- `nohup cmd &`

These wrappers hid the real command head from per-module matchers, so all of them silently fell through to generic middle-truncation. v0.29 normalizes shell prefixes once in the dispatcher before passing to compressors. Each module's matcher stays unchanged; the normalization is one well-defined entry point.

Multi-command chains (`pwd && git status && bun test`) are intentionally **not** normalized — extracting the "intended command" from a genuine pipeline is ambiguous, and the existing generic path handles those reasonably.

## Seven new Rust compressors

| Tool | What's preserved |
|---|---|
| **prettier** | Formatting issue list (`[warn]` / `[error]` lines), warning count, file failures; drops "Code style issues found" boilerplate |
| **ruff** | Rule violation lines (`F401`, `E501`, etc.), file:line:col anchors, summary count |
| **mypy** | Type errors with file:line:col, error notes, "Found N errors in M files" |
| **go test** | `--- FAIL: ...` blocks, panic traces, file:line diff markers, package summaries |
| **golangci-lint** | Per-linter issue blocks, summary, exit reason |
| **playwright** | Failure stack traces, test titles, retry blocks; drops per-step pass output |
| **next (build/lint)** | Errors, warnings with code-frame, route info; drops compilation progress lines |

Each compressor caps catastrophic output (1000+ errors) at sensible limits so a runaway run still fits the inline output cap, with a `+N more...` trailer.

## Seven new TOML filters

| Tool | What it does |
|---|---|
| **deno** | Drops `Download` / `Check` progress, keeps errors and summary |
| **pip install** | Shortcircuits "Requirement already satisfied" runs to a one-line summary |
| **uv install** | Same shape as pip — collapses noop runs, keeps errors |
| **aws cli** | Caps verbose JSON output, keeps errors |
| **psql** | Caps long table output, keeps errors and notices |
| **curl / wget** | Drops progress bars, keeps response status and errors |

## `bun test` chained-command output preservation

When `bun test` is part of a chain like `bun test && bun run build` or `bun test; echo done`, the v0.28.2 pass-only path was keeping only the bun header and summary — silently dropping the chained command's output.

v0.29 detects the `Ran N tests across M files. [Xms]` boundary line (both singular `file.` and plural `files.` forms) and preserves everything after it verbatim. Chained commands' output is no longer lost.

## `aft_navigate` LAST_SESSION fallback

Between-request Rust events (watcher invalidation, gitignore matcher rebuilds, semantic-refresh) now inherit the most-recently-known session id on the same thread, so plugin logs read correctly even when the event isn't tied to an active tool dispatch. Previously these lines emitted untagged.

## Coverage

This release adds **~600 lines** of new compressor logic, **+51 unit and integration tests**, **+12 dispatch specificity tests**, and **+2 chained-output regression tests** — for a total of **2,635 Rust tests** in the workspace, all green.
