Skip to content

v0.60.0

Choose a tag to compare

@github-actions github-actions released this 17 Oct 00:14
· 5477 commits to main since this release
988f4f3

v0.60.0

AFT 0.60.0 makes call graphs much cheaper to keep current: a one-file edit now updates a project's graph in seconds rather than minutes, and linked git worktrees reuse their main checkout's graph until they change. aft_inspect dead-code and unused-export results are more accurate on Rust, Go and TypeScript, and inspect uses far less memory on large projects. OpenCode 2 users get native shell and patch tools, and stopped subagents are no longer woken by their own background commands. CortexKit daemon users get approval modes, permission asks for sandboxed workers, Windows remote builds and many reliability fixes.

Upgrading

  • Every project rebuilds its call graph once after upgrading, including the call-graph data stored for each checkout view. Call-graph tools and aft_inspect's dead-code categories report building until it finishes.
  • aft_inspect's cached analysis is in a new format and is rebuilt once on the next run.
  • aft.db moves from schema 15 to 18 on first start (permission grants, open permission asks, approval modes and macOS fix-it cards), and its reader floor rises to 18, so AFT 0.59 and older refuse to open it afterwards. To go back to 0.59, stop AFT, then in one transaction drop the tables each step added and set schema_version to the previous number:
    • schema 18 → 17: drop access_modes, access_scope_agents and macos_permission_cards. Approval modes fall back to the default and open macOS fix-it cards are forgotten locally.
    • schema 17 → 16: drop access_asks. Open permission asks are discarded; a worker that retries its call asks again.
    • schema 16 → 15: drop access_scopes, access_grants, access_launch_params and access_materialized. Saved permission grants and launch-time folder grants are discarded.
    • Before starting the older binary, also lower only the aft.db entry in the storage root's reader-floor.json to 15, and leave every other entry unchanged. Lowering the database alone does not lower that floor.
  • OpenCode 2: AFT's bash and apply_patch now register as shell and patch, so OpenCode 2 renders them natively and each session rebuilds its prompt cache once (#406, thanks @null-axiom).
  • With remote runs enabled, the bash tool's runon description changed (it now mentions windows), so those sessions also rebuild their prompt cache once, on every host.
  • CortexKit daemon: sessions now have approval modes. Primary agents default to full access for now; ask and read-only remain available. In ask mode a primary agent asks the user before touching files outside its project, and a macOS permission denial raises a fix-it card with steps for System Settings.
  • CortexKit daemon: GitHub bot writes from an agent session are sent only under that session's agent scope. A session that isn't bound under its agent's scope is refused with bot_write_requires_scope before anything is sent; restarting the host session binds it.
  • CortexKit daemon: index data for a deleted linked worktree is removed 10 minutes after its last session, not after a day. Other checkouts keep seven days.

New

  • runon: "windows" runs a command on a remote Windows runner when the daemon's build service offers one. runon also takes a vCPU count (linux,4c) and ,net for outbound internet.
  • bash_status and bash_watch show a queued runon task's wait time and queue position, and after it starts, when the runner will stop it.
  • A bash command that finishes within its call ends its reply with a [task …] line naming its task, and its remote job for runon.
  • CortexKit daemon: call modes. flow serves only the read and navigation tools, and codemode serves the primary agent's tool set with bounded, run-scoped bash. Anything a mode does not serve is refused as call_mode_unsupported.
  • CortexKit daemon: sandboxed worker shells. A worker's reads and writes outside its checkout become permission asks to its primary agent, and the worker resumes with the answer. Git commits, hooks, builds and its own temp folder keep working, and shared build-cache servers are out of reach (enforced on macOS, reported as unenforced on Linux).
  • Primary agents can read their own workers' bash task records and status, including revived workers, without gaining control of the task; a worker's launch environment stays private. Sessions can also grep and glob their own task output folders.

Changed

  • Call graphs update incrementally: a one-file change takes about 13 s instead of about 3 minutes on a large repository, and switching branches across 50 commits about 28 s instead of 5 minutes, with results identical to a full build.
  • A linked worktree no longer builds its own call graph until something asks for it. Until its files differ from the main checkout, aft_callgraph, zoom's call-graph annotations and aft_inspect's dead-code categories answer from the main checkout's graph, with the worktree's own paths.
  • aft_inspect dead code and unused exports are more accurate: Go package initializers, Rust static values, macros, aliases and private trait methods called through their type, TypeScript namespaces, test imports with a query suffix, and public roots. Rust code compiled only for tests is left out of production findings.
  • aft_inspect peak memory on large Go projects dropped by about two thirds (hugo: about 1.4 GB to about 420 MB), and duplicate-code results take about half the memory to load. Output is unchanged.
  • Scoped aft_inspect reports only what it actually checked for that scope, and pages its results.
  • Rust: automatic cargo check runs are off in checkouts with daemon worker sessions, where aft_inspect skips its own cargo check and says so; the daemon runs at most two rust-analyzers at once.
  • Edits are faster: diff previews compute each diff once, batch edits build their output once, and a hashline edit needs two round trips instead of three.
  • Single-file aft_outline calls reuse already-parsed symbols instead of parsing the file again.
  • Bash replies arrive sooner after the command ends (median about 100 ms instead of 230 ms).
  • aft_search ranks better for sentences that name an identifier, and keeps its semantic lane for every non-regex query.
  • The CortexKit daemon does less idle work: a cheaper health pass that re-reads each repository's status only when it changes, a lighter idle tick, and helper processes started without copying the daemon's memory.
  • bash_status on a session's own task no longer searches for worker records, and looking up a worker task's owner uses memory or the database instead of walking session folders.

Fixed

  • A search run right after an AFT edit now sees the edit. It no longer depends on when the operating system reports the change, and no longer answers "complete" from the old index.
  • OpenCode 2: a stopped subagent is no longer woken by its own background commands, and its commands are stopped with it. Shutdowns and failures stop nothing (#409, thanks @null-axiom).
  • OpenCode 2: completion notices arrive as synthetic messages, and one that arrives during a long wait: true command or a bash_watch hands control back to the agent (#407, thanks @null-axiom).
  • An idle AFT bridge now lets one-shot hosts exit (#389, thanks @FrancoStino).
  • aft_zoom ambiguity menus keep their context, and the selectors they show can be passed back as they are.
  • aft_import and other tools now resolve a relative path against the project, not the filesystem root.
  • Plugins no longer move or create project config files while loading; a project's legacy .opencode/aft.json or .pi/aft.json is read where it is.
  • Bash: spawn failures name the reason, a cancelled call's still-running command is named once on the next call and keeps its completion notice, and a command that could not be confirmed started never runs after a crash.
  • Bash: a background task's output files and finished status survive a daemon restart, and a remote job's exit status is kept.
  • Configure no longer walks the whole project on the bind path; on large new checkouts that walk had delayed session start by 11 to 21 seconds. aft_inspect waits briefly for it and marks diagnostics as pending if it is still running.
  • Views: disk-limit checks run one at a time instead of all at once, and a check that ran out of time no longer records unmeasured views as empty.
  • Views: storage retention clears the backlog of deleted checkouts instead of a few per pass, and removes orphan view folders after an hour.
  • File access checks no longer blame the operating system for time spent waiting in AFT's own queue: a check that never started is refused as read_io_queue_timeout, and the macOS Privacy & Security hint is shown only on macOS. Checking a path no longer lists its parent folder.
  • Call graph: a refresh blocked by another checkout's writer waits for it instead of replaying itself, and recovers if that writer dies (#411, thanks @chpock).
  • aft_inspect: waiting for another process's cache writer is reported as waiting, not as failed input, and is retried within 30 seconds (#412, thanks @chpock).
  • OpenCode and Pi: an idle session that never started a background task no longer warns about undelivered completions (#413, thanks @chpock).
  • Swift: valid code using try/try?/try! with await in conditions, or casts followed by ??, is no longer rolled back as invalid syntax, and an edit that only tree-sitter rejects is kept when swiftc -parse accepts it.
  • With views on, searching a parent folder whose child checkouts are not indexed yet scans them on disk and says so, instead of finding nothing (#405, thanks @TreedsSlop).
  • aft_search result trailers say (cap) when a complete list was cut to one page, and (walk) only when part of the project went unsearched.
  • CortexKit daemon: the health report keeps its last measured figures, marked stale, when it is too busy to refresh them, instead of reporting zeros.
  • CortexKit daemon: primary agents keep their scope across AFT restarts and reconnects, temporary refusals no longer downgrade a session to unscoped, and a bot_write_requires_scope refusal explains what the session is missing.
  • CortexKit daemon: revived workers keep their remote runner and launch settings.
  • CortexKit daemon: worker bash refuses synthetic CPU load, including load hidden behind exec, nohup, setsid, stdbuf, time or caffeinate, and asks for a deterministic proof instead.
  • Many reliability fixes from an external audit, across the bash task lifecycle, the daemon protocol, GitHub reads and writes, index publication and the file watcher.
  • aft_inspect's file scan now stops at its time limit even inside large ignored or hidden folders, and reports an unfinished scan instead of presenting it as fresh.