# v0.30.2

Patch release. Large correctness pass across LSP diagnostics, navigation, ast-grep, format/checker, search, bash, plugin notifications, and the CLI.

## LSP diagnostics

- Pull-diagnostics `unchanged` responses are no longer accepted on the first pull. Previously a server returning `kind: "unchanged"` with no prior cache caused AFT to report a clean file even when real errors existed.
- When a server advertises pull diagnostics but rejects `textDocument/diagnostic` mid-session (`MethodNotFound`/invalid params), AFT now falls back to push instead of marking the file `pull_failed` indefinitely.
- Diagnostic cache is cleared when a file is closed. Reopening a file no longer surfaces stale diagnostics from a prior session.
- Disk-drift detection for open documents now uses a content hash when `(mtime, size)` are unchanged but the filesystem timestamp can't be trusted (coarse-mtime FS, same-size rewrites).
- Servers advertising `workspace.didChangeWatchedFiles` via initialize options (without dynamic registration) now receive file-watch notifications.
- LSP JSON-RPC framing rejects unsupported content types and non-UTF-8 charsets instead of accepting any payload that happens to decode as UTF-8.

## Format and checker 

- Biome, Ruff (check), and staticcheck now report real errors. Previously these checkers were selected but had no parser, so AFT reported a clean check even when they exited non-zero with real diagnostics.
- Checker non-zero exit without parseable diagnostics (e.g. `Cargo.toml` malformed before cargo emits JSON) now returns `skip_reason: "error"` with stderr context, not silent success.
- Absolute paths for `cargo`/`go` resolved via PATH or well-known locations are now executed directly. Previously the resolved path was discarded and the bare name re-resolved, which failed in GUI-launched shells.
- Local Windows `node_modules/.bin` lookups probe `.cmd`/`.bat`/`.exe` variants. Previously only the bare command was checked, so local npm tools were invisible on Windows.
- Pyright column offsets are now 1-based to match other checkers.
- Go vet output with Windows drive-letter paths (`C:\...`) is parsed correctly.
- Ruff checker no longer gated on `ruff format` availability; older Ruff versions that support `ruff check` are usable as checkers.
- Formatter/checker stdout/stderr capture is bounded; noisy tools can no longer OOM AFT.
- Windows formatter/checker timeouts now kill the full process tree, not just the immediate child.

## ast-grep

- `ast_replace` validates rewritten file syntax before writing. Invalid rewrites are rejected with `invalid_rewrite` and the operation rolls back instead of persisting broken code.
- `ast_search`/`ast_replace` no longer prune `node_modules`/`target`/`dist`/`build` when the user explicitly passes those as the search root.
- PHP files are now parsed with the full PHP grammar instead of the snippet-only grammar. Real `.php` files with `<?php ... ?>` work correctly.

## Search

- Indexed grep now correctly handles case-insensitive searches for non-ASCII patterns. Previously a file containing `äbc` was excluded from results when searching `Äbc` case-insensitively.
- Incremental refresh detects same-size edits when `mtime` is preserved (delete/recreate, coarse-mtime filesystems). Previously stale postings could survive a content change.

## Navigation

- `aft_navigate call_tree` now rejects paths outside the project root, matching the other navigation operations.
- Namespace imports (`import * as lib from './index'`) follow barrel reexports correctly. False positives for private symbols and missed callers through index reexports are fixed.
- Workspace package resolution covers `.mts`/`.cts`/`.mjs`/`.cjs` extensions, so monorepos with modern module formats route cross-package callers through source instead of falling back to built `dist/`.
- Unresolved member calls (`db.connect()`) are no longer reported as false callers of any same-file `connect` symbol.
- Watcher invalidation now covers `.mts`/`.cts`/`.mjs`/`.cjs` edits.
- Same-named symbols in one file are tracked by scoped identity. `class A { run() }` and `class B { run() }` no longer overwrite each other in the navigation index.
- `trace_to.entry_points_found` dedupes on `(file, symbol)` so two `main` functions in different packages count as two paths.
- `call_tree`/`callers`/`impact` now report `depth_limited`/`truncated` when results hit the depth cap. Pi rendering surfaces the truncation flags.

## Bash

- Watch patterns spanning scan boundaries no longer go missed.
- Stderr is scanned by watches alongside stdout.
- POSIX shell resolution corrected for Windows bash invocations.
- Redirect targets are canonicalized before permission checks.

## Plugin — wake delivery

- The live-server wake-transport probe now requires a successful response. Plain TUI's internal listener (which returns 404 for `/session`) is correctly classified as unreachable, so wake delivery uses the in-process fallback instead of failing silently.
- If the live server becomes unreachable mid-session, wake delivery now falls back to in-process delivery and demotes the cached transport decision instead of hard-stopping after 5 failed retries.
- Live-server availability is keyed by `serverUrl`. Multiple windows or projects with different server URLs no longer race and overwrite each other's transport choice.
- Synthetic prompts for background-bash wakes now resolve from the newest effective context. Mid-conversation model switches no longer cause wakes to use the prior assistant's model/agent.

## TUI

- Sidebar status no longer imports from `@cortexkit/aft-bridge`, which pulled `undici` into the Bun TUI runtime. The known Bun/undici load failure path is removed.
- Sidebar attaches the project directory to each snapshot and clears stale state on project transitions. Project A's status no longer briefly shows up in Project B.
- Sidebar and `/aft-status` polling cancel in-flight requests on unmount, so late completions cannot mutate state after a dialog closes or a project switches.

## RPC

- RPC port discovery always considers the legacy `port` file as a final fallback candidate. In mixed upgrade scenarios where new per-instance port files exist but are stale, AFT no longer hides live legacy servers behind dead per-instance entries.

## CLI

- `aft doctor` binary probe rejects mismatched-version binaries. Stale or unrelated `aft` binaries on PATH no longer report as healthy; `aft doctor --fix` correctly proceeds to download the matching version.
- `aft doctor lsp <file>` now sends `harness` in its configure payload. The previous omission caused `configure payload missing required field 'harness'` for users on the v0.30.0/0.30.1 CLI binary.
- `aft setup` and `aft doctor --fix` preserve comments in `opencode.jsonc` when adding the plugin entry.
- `aft doctor lsp <file>` resolves the project root from the target file path, so inspecting a file from outside its repo loads the right config.
- `aft doctor --fix` shows planned mutations and prompts before editing host config or running `pi install`.

## URL fetch

- `aft_outline`/`aft_zoom` now accept `application/json` (npm registry, unpkg, OpenAPI specs, JSON-LD). The top-level JSON keys are surfaced as outline symbols.
- URL fetching no longer stalls on body reads under OpenCode's Bun plugin runtime. The bundled undici inside the plugin bundle stalled on common hosts (`github.com`, `registry.npmjs.org`, `api.github.com`); AFT now uses Bun's native fetch in that runtime. SSRF validation still runs.

## Import management

- `aft_import add` merges new names into an existing same-module same-kind named import instead of inserting a duplicate `import { ... } from "lib"` line. Linter complaints about duplicate imports no longer appear after adding a second symbol from the same module.

## Refactoring

- `aft_refactor inline` now works on exported TypeScript functions. After the parser change that included the `export` keyword in symbol ranges, the inline path couldn't reach the wrapped function declaration and returned `symbol_not_found`.

## Bridge transport

- UTF-8 multibyte characters split across NDJSON chunks are decoded correctly.
- Timeout on one request aborts sibling in-flight requests immediately instead of leaving them queued against a dead pipe.
- Caller's `transportTimeoutMs` now applies to implicit configure and version RPCs.
- Bridge crashes mid-configure no longer leave the bridge marked as configured.
- Stderr tail is buffered per logical line so split chunks don't corrupt the diagnostic output.

## CI and release infrastructure

- `wait-release.sh` exits on the first terminal job failure instead of waiting for every job to drain.
- `scripts/release.sh` recovery path no longer terminates after the first publishing fallback.
- E2E harness cleanup uses `trap`-based teardown; failed runs no longer leak mock server processes or temp directories.
- Linux Docker E2E `Dockerfile` fails the image build when plugin preinstall or local artifact placement fails, instead of silently testing against stale npm-published artifacts.
- External benchmark harness exits non-zero when any repo fails to evaluate, unless `--allow-partial` is passed.
