Releases: cortexkit/aft
v0.7.6
Critical Bug Fix
- Replaced jsonc-parser with self-contained JSONC stripper —
jsonc-parser's UMD bundle breaks under both ESM named imports (Node.js strict ESM in OpenCode's runtime) andcreateRequire(Bun/OpenCode hybrid). Replaced with a zero-dependency comment stripper + trailing comma removal +JSON.parse. This was the root cause of plugin loading failures since v0.7.2.
Full Changelog: v0.7.5...v0.7.6
v0.7.5
Bug Fixes
Version Mismatch Loop Prevention
- Fixed infinite configure loop — When the binary version is older than the plugin, the version mismatch handler now fires only once per binary version instead of re-triggering on every bridge respawn. Prevents the
Failed to configure bridge after 3 attemptserror users were hitting. - Tracker doesn't reset prematurely — Per Oracle audit, the upgrade tracker stays set after replacement so a still-outdated downloaded binary doesn't re-trigger the loop. Resets naturally on plugin reload.
User Experience
- Log file path in errors —
Failed to configure bridge after 3 attemptsandMax restarts reachednow include the path to$TMPDIR/aft-plugin.logso users can find diagnostic logs. - Empty param handling —
lsp_diagnosticstreats empty stringfilePath/directoryas absent instead of throwing a false mutual-exclusivity error.
Full Changelog: v0.7.4...v0.7.5
v0.7.3
Bug Fixes
- lsp_diagnostics empty string handling — Empty string
filePathordirectoryparams are now treated as absent instead of triggering the mutual-exclusivity error. Fixes'filePath' and 'directory' are mutually exclusivewhen agents sendfilePath: ""with adirectoryvalue.
Full Changelog: v0.7.2...v0.7.3
v0.7.2
Improvements & Bug Fixes (Council Audit Round 2)
⚡ Performance
- Event-driven LSP diagnostics — Replaced blocking
thread::sleep(1.5-10s) withrecv_timeoutpolling loop. Post-edit diagnostics now return immediately when the language server responds instead of waiting the full timeout (#10) - Callgraph memory reduction — Reduced
.clone()calls from 80+ to 52 inbuild_reverse_indexby usingArc<PathBuf>/Arc<str>for shared caller data. Hot loop no longer clones entireFileCallDatastructs (#7)
🐛 Bug Fixes
- Backup error misidentification —
restore_latestnow reports the actual I/O error (permission denied, disk full) instead of incorrectly claiming "file not found" via newIoErrorvariant (#12) - Bridge crash orphan processes — Crash recovery timer now checks
isAlive()before spawning, preventing duplicate child processes whenensureSpawned()already created one (#14) - LSP workspace/configuration dispatch — Server requests are now dispatched by method:
workspace/configurationreturns a correctly-typed array instead ofnull, so language servers receive proper config responses (#19)
🔒 Security
- Mandatory checksum verification — Binary auto-downloader now aborts if checksums.sha256 is unavailable or missing an entry, preventing MITM attacks that block the checksum request (#16)
📝 Documentation
- unwrap/expect audit note — Documented in
lib.rsthat remaining.unwrap()calls are in tree-sitter query operations (compile-time grammar constants) and test code, not production error paths (#2) - TypeScript
asassertion note — Documented inbridge.tsthatascasts are guarded bysuccess === falseerror checks on all 16 tool handlers (#6)
Full Changelog: v0.7.1...v0.7.2
v0.7.1
Bug Fixes (Council Audit P0/P1)
🔒 Security
- Path validation coverage — Added
validate_path()to 6 write-capable commands that were missing it:transaction,ast_replace,lsp_rename, globedit_match,checkpoint, andrestore_checkpoint - Path traversal hardening —
validate_path()canonicalization fallback now normalizes..components for non-existent paths, preventingroot/../outside/filebypass
🐛 Correctness
- CRLF byte offset fix —
line_col_to_bytenow scans raw bytes instead of using.lines(), fixing byte offset drift on Windows/CRLF files from line 2 onward - Code deduplication — Consolidated 5 duplicate
line_col_to_byteimplementations into one shared function - Transaction rollback visibility — Failed rollback file paths now appear in the error response under
rollback_failuresinstead of being silently logged at debug level - move_file false success — Returns
moved: falsewith a warning when source file deletion fails after copy, instead of claiming success
🔧 Robustness
- LSP stderr deadlock prevention — Language server stderr pipe switched to
Stdio::null()to prevent blocking after ~64KB of server logs - Bridge recursion guard —
send()now has a 3-attempt depth limit to prevent infinite recursion on repeated version mismatches - Bridge configured flag race — Flag is now set after configure succeeds (not before the await), and reset on failure
- Format logging fix — Successful auto-format now logs at
infolevel instead oferror
Full Changelog: v0.7.0...v0.7.1
v0.7.0
What's New
🆕 aft_conflicts — Single-call merge conflict viewer
Show all git merge conflicts across the repository in one call. Auto-discovers conflicted files, parses conflict markers, and returns line-numbered regions with context — the same format agents see from read. Replaces the typical 13-call workflow (2 bash + 11 reads) with a single tool call.
When git merge or git rebase produces conflicts, the plugin automatically appends a hint nudging the agent toward aft_conflicts.
🔧 Improvements
aft_outlinedirectory auto-detect — passing a directory path tofilePathnow routes to directory mode instead of erroringaft_outlinetree-text format — compact text output replaces JSON, 80% smaller (~46KB → capped at 30KB), with signatures for single-file mode- Session-scoped bridges — each OpenCode session gets its own aft binary process with isolated undo/backup history (~9-15MB per session)
- Bridge timeout auto-restart — hung aft process gets SIGKILL'd and respawned on the next tool call
- Transparent version hot-swap — first tool call retries automatically after binary replacement instead of failing
restrict_to_project_root— new opt-in config option (default: false, matching OpenCode's built-in write behavior)tool_surfacetiers —minimal(3 tools),recommended(12 tools, default),all(17 tools)
🐛 Bug Fixes
- AST replace multi-match —
ast_grep_replacenow replaces all occurrences per file (was only replacing the first) - Crash hardening — fixed panics from unchecked
capture_namesindexing,move_symbolisize overflow, unboundedheading_level, and invalid AST patterns - Batch edit fuzzy matching — batch edits now use the same 4-pass fuzzy matching as single edits
- Hoisted edit batch compatibility —
oldString/newStringinsideedits[]now translates correctly to Rust - Error guards on all 16 tool handlers — Rust error responses no longer crash the plugin with
TypeError: undefined is not an object - Binary resolution loop fix —
ensureBinaryno longer falls back to stale legacy cache for versioned requests buildUnifiedDiffsize cap — large file diffs (>100KB) are skipped to prevent Node.js event loop hangs- Overlapping batch edit detection — batch edits with overlapping ranges now return a clear error instead of corrupted output
📝 Other
- File-based logging — plugin logs go to
$TMPDIR/aft-plugin.loginstead of stderr (no more leaking duringopencode export) aft --version/-V— CLI flag to check binary version- Release script improvements — rebuilds local binary after version bump, updates cache paths, uses
buninstead ofnode - Repo migration — moved to
cortexkit/aft - 89 new tests (730 total) including 54 end-to-end tests through real BinaryBridge
Full Changelog: v0.6.7...v0.7.0
v0.6.7
Full Changelog: v0.6.6...v0.6.7
v0.6.6
Full Changelog: v0.6.5...v0.6.6
v0.6.5
Full Changelog: v0.6.4...v0.6.5
v0.6.4
Full Changelog: v0.6.3...v0.6.4
Full Changelog: v0.6.3...v0.6.4