Skip to content

v0.33.0

Choose a tag to compare

@github-actions github-actions released this 30 May 06:31
· 4109 commits to main since this release

v0.33.0

This release adds aft_inspect — a single codebase-health view for agents — and reworks how diagnostics reach the agent. It also renames aft_navigate to aft_callgraph and lands a large batch of aft_search correctness fixes.

aft_inspect — codebase health at a glance

aft_inspect gives an agent the "open the project and see what's wrong" view in one call, instead of stitching together greps and separate tools. One call returns a summary across categories; pass sections to drill into any of them.

Categories:

  • diagnostics — compile/type errors from language servers
  • metrics — file count, lines of code, symbol count
  • todos — TODO/FIXME/HACK/XXX/BUG markers with file, line, and author
  • dead_code — exported symbols with no reachable caller
  • unused_exports — exported symbols nothing imports
  • duplicates — near-identical code blocks across files

Treat dead_code as a hint, not an authority: reachability is call-based, so symbols reached only through method dispatch (receiver.method()) or referenced only in type position can still appear as false positives. Verify before deleting.

It runs in tiers. Metrics and todos return synchronously from cache. dead_code, unused_exports, and duplicates run as background scans on session idle; calls return cached results immediately (marked stale when a refresh is pending) rather than blocking. Results persist to disk per project, so they survive restarts.

Options:

  • sections — one category or an array; all for everything; omit for summary-only
  • scope — restrict to a file or directory
  • topK — cap drill-down items per category

Scan results persist across restarts

Tier-2 scan results are stored on disk. When you reopen a project after editing files, aft_inspect serves the last completed scan immediately (flagged stale) while a fresh scan runs in the background, instead of showing nothing until the rescan finishes.

Diagnostics now flow through aft_inspect

Diagnostics no longer arrive automatically after every edit. Previously edit, write, and apply_patch waited on language-server diagnostics inline on each call. That work moved into aft_inspect, which an agent runs after a batch of edits and before tests or a commit. The result is faster edits and a single deliberate point to check the codebase.

  • The standalone lsp_diagnostics tool is removed; its capability is part of aft_inspect's diagnostics category.
  • A new lsp.diagnostics_on_edit config option (default off) restores per-edit diagnostics for users who want them.
  • aft_inspect diagnostics are build-authoritative: TypeScript/JavaScript files excluded by tsconfig.json (files/include/exclude, following extends) are skipped, so results match a real tsc run instead of reporting phantom errors on excluded files.
  • Scoped diagnostics on a single file wait briefly for a cold language server to start and publish, so the result arrives in one call rather than requiring a re-run. Scopes whose file types have no registered or applicable server report a terminal no_server status instead of waiting forever.

aft_inspect diagnostics are a fast checkpoint, not the project-wide authority — a clean tsc / cargo check / pyright run remains the real gate.

aft_navigate is now aft_callgraph

The call-graph tool is renamed from aft_navigate to aft_callgraph. The new name matches what the tool does — answer code-relationship questions (callers, call tree, impact/blast radius, execution paths, data flow) from a real call graph — and is the term models reliably reach for. All operations (callers, impact, call_tree, trace_to, trace_to_symbol, trace_data) are unchanged.

The Rust call graph now resolves cross-file callers. Calls through crate::, super::, self::, a workspace crate name (e.g. a binary's mycrate::module::func(...)), and use-imported short names now resolve to the right definition. Previously only same-file callers were found, so callers/impact on a Rust symbol returned far too few results and dead_code over-reported. Liveness also now flows through private intermediary functions, so handlers reached only via a private router are no longer flagged dead.

aft_search correctness

A batch of fixes to the unified aft_search shipped in v0.32:

  • Disabled vs. unavailable. With semantic_search: false, a natural-language query now returns a clear "not enabled" result instead of silently degrading to a lexical scan. The degraded lexical fallback is reserved for when semantic is enabled but temporarily building or unavailable.
  • Truthful routing. interpreted_as reports the lane that actually ran (lexical when the semantic lane was skipped), not the lane that was requested.
  • Result provenance. Each result carries the lane that produced it plus a hybrid_boosted flag, and more_available now accounts for engine caps and semantic overflow so "more results exist" is accurate.
  • Quoted phrases. Surrounding quotes on a literal query ("was not found on PATH") are stripped before matching, matching rg -F / code-search behavior, instead of searching for the quote characters.
  • Classifier routing. A sentence-final ? no longer forces regex mode; a query mixing natural language with an error code routes correctly; bare escape sequences route to regex while Windows-path-shaped queries stay exempt.
  • No hidden truncation. Lexical candidates beyond the old internal cap are no longer dropped silently before fusion.

Edits no longer echo back to the agent

edit, write, and apply_patch were returning unnecessary diff bytes back to LLM. The agent-facing result is now minimal (success plus added/removed line counts).

Bug fixes

Editing and refactoring:

  • aft_safety undo history no longer lost on restart. The first edit to a previously-backed-up file after a restart could overwrite that file's entire on-disk undo history (and reuse a backup id). Prior history is now hydrated before the new snapshot is appended.
  • apply_patch pure-insertion hunks insert at the resolved context line instead of end-of-file.
  • aft_transform add_member on a generic impl<T> Foo<T> block now inserts methods into the impl block, not the struct body.
  • aft_refactor move no longer adds a spurious import when a parameter or local variable shadows the moved symbol's name.
  • aft_import organize correctly handles Rust nested use trees (a::{b::{c, d}, e}) without corrupting them.
  • aft_zoom no longer raises spurious mutual-exclusion errors when a model sends empty or empty-content targets/symbols parameters.

Search and indexing:

  • The semantic index verifies per-file freshness strictly and uses canonical paths for watcher invalidation, so edits refresh the right entries and large files aren't downgraded to a weaker freshness check.
  • aft_outline accepts JSON registry/package URLs and outlines their top-level keys.
  • URL fetching for aft_outline/aft_zoom retries transient connect/transport failures and now runs entirely in Rust.

Reliability and security:

  • The worker bridge stays alive through transient starvation timeouts and only escalates to a kill on a genuine hang, so a busy bridge no longer drops unrelated requests.
  • SSRF protection on URL fetches now blocks RFC 6598 (CGNAT, 100.64.0.0/10) and RFC 2544 (198.18.0.0/15) ranges, including their IPv4-mapped IPv6 forms.
  • Windows hardening: validated LoadLibraryExW ONNX Runtime loading, NuGet cache scanning, storage directory creation, and a binary-replacement retry (contributed in #66/#69).
  • Killing a PTY-mode background task on Windows now finalizes reliably instead of hanging, so bash_kill and the polling that waits on it always return.
  • LSP and formatter "not installed" warnings no longer re-fire on every session, and synthetic notifications preserve the active model and variant.

Join us on Discord: https://discord.gg/F2uWxjGnU