Skip to content

fix(acp): stop the binary-cache precheck from contradicting the launch path - #717

Open
Adam-Dalloul wants to merge 1 commit into
xintaofei:mainfrom
Adam-Dalloul:fix/preflight-binary-cache-system-install
Open

fix(acp): stop the binary-cache precheck from contradicting the launch path#717
Adam-Dalloul wants to merge 1 commit into
xintaofei:mainfrom
Adam-Dalloul:fix/preflight-binary-cache-system-install

Conversation

@Adam-Dalloul

Copy link
Copy Markdown
Contributor

Follow-up to #631, from the reporter's later detail: after a download that reported success, Version Status read pass while Binary cache read warn. Both cards describe the same file, so one of them was wrong. Two independent causes, both in the read path, neither of them the download.

This is separate from #713, which fixes the fake uninstall in the same issue.

1. The precheck refused the fallback the launcher uses

check_binary_environment accepted a user-installed CLI in place of a codeg-managed download only when the registry entry carried a dir_entry:

Ok(None)
    if binary_dir_entry(agent_type).is_some()
        && crate::commands::acp::resolve_system_agent_binary(cmd).is_some() =>

dir_entry is Some for Cursor and nothing else. Every other binary agent, OpenCode included, fell through to "Binary is not installed. Download it from Agent Settings before connecting."

Three other places already accept that same CLI:

  • acp/connection.rs picks the best cached binary and otherwise spawns resolve_system_agent_binary(cmd), logging No cached binary; using system <path> from PATH.
  • verify_agent_installed in commands/acp.rs gates connect on find_best_cached_binary_for_agent(...).is_some() || resolve_system_agent_binary(cmd).is_some().
  • detect_local_version (and the status/list paths) report the system binary's --version as installed_version, which is what the Version Status card renders.

So on a machine whose only OpenCode is ~/.local/bin/opencode.exe, the version card reported it installed, connect accepted it, the launcher spawned it, and the precheck alone called it missing and pointed at a download button. That is the reported pass/warn split, on every settings open, with or without a download in between.

The check now reads the same two facts in the same order the launcher uses. The decision is split into a pure build_binary_cache_check so the verdict is unit-testable without a cache dir or a PATH, and the passing message names the file that will actually be launched:

No codeg-managed binary; will launch the system-installed opencode at
C:\Users\...\.local\bin\opencode.exe (download 1.18.18 from Agent Settings
to use the pinned build instead)

Warn is unchanged when there is genuinely nothing to launch, which is the state connect rejects. passed is unaffected either way, since this item was never Fail.

2. A cached binary codeg could not open was deleted

installed_binary_path treated an unreadable file as a foreign-platform binary:

if is_binary_file_compatible(path.as_path()) {
    return Some(path);
}
let _ = std::fs::remove_file(path);

is_binary_file_compatible returned false both for "opened it and the header belongs to another platform" and for "could not open it at all", and the caller could not tell those apart. On Windows the second case happens with nothing wrong: the anti-virus real-time scanner holds a freshly written ~180 MB agent binary for a moment, and a running agent holds its own image. A preflight landing in that window removed an install that had just succeeded. Right after that, acp_detect_agent_local_version falls back to the system copy and the version card reads pass while the cache check reads nothing installed, which is exactly the state described after a successful download.

The probe now returns a three-way BinaryFormat, and only a positive wrong-platform verdict evicts. A file too short to hold any header stays evictable, since that is a permanent fact rather than a transient one. The post-download check keeps the strict boolean: there codeg owns the file it just wrote, so anything short of a readable, correct header must fail the install loudly rather than cache something unverified.

Tests

Nine new Rust unit tests, all failing before the change:

  • preflight.rs: a system install passes for a single-file agent and names the path; nothing cached and nothing on PATH still warns; a cached binary wins over a system install so the card never describes a file codeg will not spawn; an older cache passes and names the recommended version; every branch keeps the binary_cached id the frontend keys on.
  • binary_cache.rs: only Incompatible evicts; an unopenable path probes as Unreadable; empty and 2-byte files probe as Incompatible; a readable header decides compatibility.

Reverting either production change fails its tests: the preflight arm back to Warn fails system_install_reports_ready_for_single_file_agents, and folding Unreadable back into "not usable" fails only_a_wrong_platform_verdict_evicts_a_cached_binary and truncated_file_probes_as_incompatible.

No frontend file changes, no new user-facing string in i18n/messages/ (preflight check messages are backend English, like every other item in this list), and no behaviour change for Cursor, which keeps passing on a system install exactly as before.

…h path

Agent settings could show "Version Status: pass" next to "Binary cache: warn"
for the same OpenCode install, and the warn told the user to download a binary
they already had. Two separate reasons, both in the read path.

`check_binary_environment` only accepted a user-installed CLI in place of a
codeg-managed download when the agent's registry entry carried a `dir_entry`,
which is Cursor and nothing else. Every other binary agent fell through to
"Binary is not installed. Download it from Agent Settings before connecting."
even though `connection.rs` resolves exactly that CLI and spawns it, the
connect gate in `verify_agent_installed` accepts it, and the version card
counts it as installed through `detect_local_version`. OpenCode is a
single-file binary agent, so a user whose only copy was
`~/.local/bin/opencode.exe` got the contradiction on every settings open. The
check now reads the same two facts in the same order the launcher uses, split
into a pure `build_binary_cache_check` so the verdict is testable, and the
passing message names the file that will be launched instead of pointing at a
download button for one already present.

`installed_binary_path` also deleted any cached binary whose first four bytes
it could not read. `is_binary_file_compatible` returned false both for "opened
it and the header belongs to another platform" and for "could not open it at
all", and the caller could not tell those apart. On Windows the second case
happens with nothing actually wrong: the anti-virus real-time scanner holds a
freshly written ~180 MB agent binary for a moment, and a running agent holds
its own image. A preflight landing in that window removed an install that had
just succeeded, after which the version card fell back to the system copy and
read pass while the cache check read nothing installed. The probe now returns a
three-way `BinaryFormat` and only a positive wrong-platform verdict evicts. A
file too short to hold any header stays evictable, since that is a permanent
fact, and the post-download check stays strict because there codeg owns the
file it just wrote.

Reported in xintaofei#631.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant