v0.38.0
v0.38.0: Code Health you can trust
Dead code and unused exports are back on the dashboard, rebuilt on a real analysis engine. Plus: tools stay responsive while your project compiles, trace_data moves to the persisted call-graph store, and Pascal joins the language table.
Dead code and unused exports, rebuilt on oxc
In v0.35.3 we pulled dead-code and unused-export numbers from the sidebar and status displays because they over-reported — barrel re-exports, package entry points, and dynamic imports produced false positives we weren't willing to show. This release replaces the TypeScript/JavaScript analysis with a real module-graph engine built on oxc: scope-aware export liveness, barrel and re-export chains, package.json entry-point resolution, tsconfig-aware module resolution, and dynamic-import handling.
On AFT's own repository the unused-export count dropped 62% — and the survivors check out as genuinely dead when inspected by hand. Both categories are live again in the TUI sidebar, /aft-status, aft_inspect, and the agent status bar.
Honest framing, per language: TS/JS findings are import-graph verified by the new engine. Findings for other languages still come from the call-graph analyzer, which can over-report dynamic dispatch targets (trait methods, interface implementations) — those upgrades are next on the roadmap, and results remain labeled by language so you can weigh them accordingly.
The engine also reports its own gaps: files it could not parse and files outside the analysis root are listed in aft_inspect output instead of being silently skipped.
Tools stay responsive during builds
Filesystem event processing moved off the bridge's request thread. Previously, a compile writing thousands of files (cargo's target/, webpack output) could queue tool calls behind a flood of watcher events — requests timed out at 30 seconds while the bridge chewed through events. Events are now received, filtered, and coalesced on a dedicated thread; the request loop only ever sees the handful of source files that actually changed. Tool calls answer in milliseconds mid-build.
trace_data on the call-graph store
aft_callgraph op=trace_data now projects from the persisted call-graph store like the other five ops, instead of re-walking files with the legacy engine. Cross-file value flows resolve through the store's type-aware edges, recursive functions trace correctly, and results come back from an index instead of a parse.
Pascal support
.pas/.pp/.dpr files now work in aft_outline, aft_zoom, and the AST tools (ast_grep_search/ast_grep_replace) — programs, units, classes, procedures, and functions extract with correct ranges. (#109)
Ctrl-C and shutdown behavior
AFT's signal handling now follows a strict contract: if AFT is the only SIGINT/SIGTERM listener in the host process, it owns termination — cleanup runs with a 5-second cap and the process exits with the conventional signal code. If other plugins or the host also listen, AFT cleans up and defers termination to them — and logs which listeners it deferred to, by name, so a hung Ctrl-C is attributable from the log instead of requiring a debugging session.
Status panel reliability
- The TUI sidebar no longer loses its connection permanently after heavy host load: clients only remove a server's port file when its process is provably dead, and the server re-publishes its port file every 15 seconds if it goes missing. (#110)
- Transient environment problems (a JSON schema fetch timing out, a registry being unreachable) no longer count as code errors in the status bar or
aft_inspectsummaries. They remain visible in detail rows, tagged[environmental].
Bash output protection: chained commands
The pipe protection that keeps bun test | grep fail from hiding failures now handles command chains: cd pkg && bun test | tail -3 && bun run typecheck | tail -1 gets each segment's noise filter stripped independently, with the same fail-closed rules — comments, redirections, substitutions, and side-effectful filters leave the command untouched.
Fixes
edithonorsoccurrence: 0— the first-match selector was treated as an empty parameter and re-prompted withambiguous_match.- Error responses no longer leak status-bar internals — structured tool errors carried a
status_bardata block meant for transport, not for the agent. - Cloning a repository you already have no longer corrupts the original's call-graph cache — two checkouts of the same repo now build per-clone stores instead of re-rooting each other's metadata back and forth.
- Analysis caches distinguish
.tsfrom.tsx— identical content parsed under different grammars no longer shares a cache entry. aft_inspectscoped to a directory reports scope-accurate language breakdowns instead of project-wide ones.
Questions or feedback? Join us on Discord.