Skip to content

【bug】OpenCode 连接失败:托管二进制未下载(binary cache 空),回退系统 opencode 后 Initialize 超时,opencode卸载假成功 #631

Description

@galact-byte

环境

  • codeg-server: v0.29.0
  • OpenCode: 1.18.25 (windows-x86_64)
  • 系统: Windows x64

问题1:codeg 一直连不上 OpenCode;"Binary cache" 预检一直显示没下载,OpenCode 的扩展在软件里只能用 bun 装

复现

  1. 在 Agent SDK 管理里启用 OpenCode,让 codeg 自动准备二进制。
  2. codeg 的 "Binary cache" 预检一直是未下载状态。
  3. 连接 OpenCode → 握手超时、连不上。

让AI看了下,说是

   回退用的那个 bun 装的 opencode 带 `oh-my-openagent` 插件(启动时加载 14 个 Claude Code 插件 + 更新检查 + 二进制部署
 ),冷启动 6.5s+。对照实验:移除 `oh-my-openagent@4.19.4` 后握手从 6.65s 降到 2.29s。
   完整链条:binary cache 下载失败 → codeg 静默回退到慢启动的系统二进制 → ACP 握手被超时掐断 → 连不上。

今天又发现,codeg 的自动下载始终没把二进制放进它自己的 cache 目录,所以 "Binary cache" 一直显示没下载、连接时只能回退系统 PATH。codeg 的 binary cache 没把下载的文件写到自己会去读的那个目录,手动把已有的 opencode 二进制放到 codeg 指定目录后,"Binary cache" 立刻变 PASS,重启 codeg 就好了

期望

  1. binary cache 下载后要真正落盘到 codeg 自己读取的目录
    (...\app.codeg\cache\opencode\opencode-windows-x86_64.exe),并让预检显示已下载。
  2. 下载失败时给出明确报错/重试入口,不要静默回退。
  3. 回退到系统二进制时,Initialize 超时应更宽容(或先探测再定超时),别被重型插件启动拖死。

问题2 同一处的"卸载"是假成功,在 Agent SDK 管理 → OpenCode → 版本状态

复现

版本状态区点"卸载",会发现UI 提示已卸载/成功,但实际并没有卸载,只是binary cache没了
Image

期望:

卸载要真正删除托管二进制与缓存,并把版本状态 / Binary cache 刷成未安装;删除失败要如实报错,而不是报成功。

这是日志,昨天问题一忘记截图了
codeg.2026-09-01.log

codeg.2026-09-02.log

Activity

  1. changed the title [-]【bug】OpenCode 连接失败:托管二进制未下载(binary cache 空),回退系统 opencode 后 Initialize 超时[/-] [+]【bug】OpenCode 连接失败:托管二进制未下载(binary cache 空),回退系统 opencode 后 Initialize 超时,opencode卸载假成功[/+] on Sep 2, 2026
  2. Adam-Dalloul commented on Sep 10, 2026

    @Adam-Dalloul
    Contributor

    问题 2(卸载假成功)已确认,修复见 #713。关于问题 1,我按你附的日志核对了一遍,实际原因和你的 AI 给出的结论不一样,这里说明一下。

    目录并没有搞错。 你提到的 %APPDATA%\app.codeg\cache\opencode\ 是 models.dev 供应商目录的缓存(opencode_catalog.rs,里面只有一个 models-dev.json),跟二进制无关。托管二进制的读写两边都走同一个 cache_dir(),落在:

    %LOCALAPPDATA%\app.codeg\acp-binaries\opencode\<version>\windows-x86_64\opencode.exe
    

    写入路径(binary_dir)和读取路径(installed_binary_path)用的是同一个目录、同一个平台串、同一套 .exe 后缀规则,所以不会出现「下载到一个地方、读另一个地方」。

    真正的原因是根本没有触发下载。 在 Agent SDK 管理里启用 OpenCode 不会下载二进制,全仓库只有一个地方会下载,就是 Agent 设置里显式点「下载」按钮(acp_download_agent_binary)。所以 Binary cache 预检一直显示未下载是如实的,它确实是空的,而不是放错了位置。你手动把 opencode 拷进那个目录之后立刻 PASS,也正好说明读取路径本身是对的。

    你日志里的对应证据:

    [ACP][OpenCode] No cached binary; using system C:\Users\g1582\.local\bin\opencode.exe from PATH
    

    关于超时:当前 main 的 Initialize 超时已经是 60 秒(connection.rs,日志里也会打印 timeout=60s)。9-01 那次是整整 60 秒没有应答,9-02 同一个二进制只用了 7.48 秒就返回了,所以放宽超时大概率解决不了这个握手卡死,插件冷启动只是把窗口变宽。

    剩下真正值得改的:回退到 PATH 上的系统二进制时,除了一行 tracing::info! 之外没有任何用户可见提示,Binary cache 预检也只是 Warn 不是 Fail,所以 passed 仍然为 true。握手超时的报错里也没有说明这次用的不是托管二进制。这一条我没有一并改,它和 #713 是两件事。

  3. galact-byte commented on Sep 10, 2026

    @galact-byte
    ContributorAuthor

    问题 2(卸载假成功)已确认,修复见 #713。关于问题 1,我按你附的日志核对了一遍,实际原因和你的 AI 给出的结论不一样,这里说明一下。

    目录并没有搞错。 你提到的 %APPDATA%\app.codeg\cache\opencode\ 是 models.dev 供应商目录的缓存(opencode_catalog.rs,里面只有一个 models-dev.json),跟二进制无关。托管二进制的读写两边都走同一个 cache_dir(),落在:

    %LOCALAPPDATA%\app.codeg\acp-binaries\opencode\<version>\windows-x86_64\opencode.exe
    

    写入路径(binary_dir)和读取路径(installed_binary_path)用的是同一个目录、同一个平台串、同一套 .exe 后缀规则,所以不会出现「下载到一个地方、读另一个地方」。

    真正的原因是根本没有触发下载。 在 Agent SDK 管理里启用 OpenCode 不会下载二进制,全仓库只有一个地方会下载,就是 Agent 设置里显式点「下载」按钮(acp_download_agent_binary)。所以 Binary cache 预检一直显示未下载是如实的,它确实是空的,而不是放错了位置。你手动把 opencode 拷进那个目录之后立刻 PASS,也正好说明读取路径本身是对的。

    你日志里的对应证据:

    [ACP][OpenCode] No cached binary; using system C:\Users\g1582\.local\bin\opencode.exe from PATH
    

    关于超时:当前 main 的 Initialize 超时已经是 60 秒(connection.rs,日志里也会打印 timeout=60s)。9-01 那次是整整 60 秒没有应答,9-02 同一个二进制只用了 7.48 秒就返回了,所以放宽超时大概率解决不了这个握手卡死,插件冷启动只是把窗口变宽。

    剩下真正值得改的:回退到 PATH 上的系统二进制时,除了一行 tracing::info! 之外没有任何用户可见提示,Binary cache 预检也只是 Warn 不是 Fail,所以 passed 仍然为 true。握手超时的报错里也没有说明这次用的不是托管二进制。这一条我没有一并改,它和 #713 是两件事。

    感谢解答,主要是不知道为什么我点击下载,然后下载成功后版本状态那里是pass,但是binary cache就会warn,很奇怪,好像是这个读取的不是我之前下载的opencode导致的,然后想卸载重试下,结果假成功导致卡这了。顺便想问下,opencode这个插件下载在软件里考虑支持其他下载方式吗,只能bun下载是不是有点局限了,用的npm多一点

  4. Adam-Dalloul commented on Sep 10, 2026

    @Adam-Dalloul
    Contributor

    谢谢你补的这段,正是这段推翻了我上一条的结论。先说我错在哪。

    我上一条说错了

    我当时说「Binary cache 一直是 warn 是如实的,因为根本没触发下载」。这句话只覆盖了「缓存目录是空的」这一半,而且回避了你真正在问的那一半:既然缓存是空的,为什么版本状态是 pass。这两张卡片读的根本不是同一份 opencode,这才是问题本身,我上次没看出来。

    版本状态和 Binary cache 读的不是同一个东西

    • 版本状态那张卡片读的是 installed_version,它来自 detect_local_version(src-tauri/src/commands/acp.rs:635 的 Binary 分支,acp_list_agents_core 和 acp_get_agent_status_core 里是同样的逻辑):先查 codeg 自己的缓存,查不到就退回 resolve_system_agent_binary,也就是 PATH 加 ~/.local/bin。你日志里那句 No cached binary; using system C:\Users\g1582\.local\bin\opencode.exe from PATH 指的就是它。所以卡片上的 1.18.25 和那个 pass,说的是你自己装的那一份。
    • Binary cache 那张卡片来自 src-tauri/src/acp/preflight.rs:505 的 check_binary_environment。它只认 codeg 托管的缓存,而原来接受系统安装的那个分支有个前置条件 binary_dir_entry(agent_type).is_some()(preflight.rs:565),注册表里带 dir_entry 的智能体只有 Cursor 一个。OpenCode 是单文件二进制,于是直接落到「Binary is not installed. Download it from Agent Settings before connecting.」。

    结果就是同一个文件:连接时 connection.rs:989 会去启动它,连接前置检查 verify_agent_installed(commands/acp.rs:547)认它可用,版本卡片把它算作已安装,只有 Binary cache 说没装。这就是你看到的 pass 配 warn,跟点没点下载无关,每次打开设置页都会这样。

    还有第二个原因,它能解释更具体的那句「下载成功之后 Binary cache 还是 warn」。installed_binary_path(binary_cache.rs:280)每次读缓存都会验一下文件头四个字节,而原来的 is_binary_file_compatible 分不清两件事:「打开了,但这是别的平台的二进制」和「压根没打开」。两种都返回 false,然后调用方把文件删掉。Windows 上第二种情况并不代表文件有问题:刚写完的 180MB 二进制会被杀毒软件实时扫描短暂占住,正在运行的 agent 也会占住自己的镜像。前置检查如果正好撞进这个窗口,就会把刚装好的那一份删掉;紧接着版本探测退回到系统那份,于是就是版本状态 pass、Binary cache 说没装。

    修复

    #717(和 #713 是两件事,没有合在一起):

    1. Binary cache 检查改成读启动路径读的那两件事、用同样的顺序。通过时消息里直接写出这次会启动哪个文件,而不是让你去点一个你已经有了的下载按钮。真的什么都没有时仍然 warn。
    2. 文件头探测改成三态,只有确认是别的平台的二进制才删。文件短到放不下文件头也照删,那是永久事实;下载完那一步的校验保持严格,因为那一步文件是 codeg 自己刚写的。

    另外你原帖里 %APPDATA%\app.codeg\cache\opencode\ 那一条,我上次说的没错:那个目录只有 models.dev 的供应商目录缓存,和二进制无关。

    关于 npm

    直接回答:确实只支持 bun,你说得对。src-tauri/src/acp/opencode_plugins.rs:205 的 resolve_bun_binary() 只找 opencode 自带的 bun 和系统 bun,都没有就直接报错;装插件走的是 bun add。

    但只把 bun add 换成 npm install,我认为解决不了你的问题,所以我不打算这么改。我用 codeg 当前锁定的 opencode 1.18.18 在隔离目录里实测了一遍(XDG_CONFIG_HOME 和 XDG_CACHE_HOME 都指向临时目录),跑 opencode plugin <包名>:

    • 依赖装到了 <XDG_CONFIG_HOME>/opencode/node_modules,同时生成 package.json、package-lock.json(lockfileVersion 3,是 npm 的锁文件格式)和一个 .gitignore。
    • <XDG_CACHE_HOME>/opencode/ 下面只有 models.json,没有任何 node_modules。

    而 codeg 现在读和写的都是 ~/.cache/opencode/node_modules(opencode_plugins.rs:61)。也就是说在 1.18 上,插件检查和「安装插件」按钮对着的是一个 opencode 不会去读的目录,换包管理器不解决这一点。真要修,是把整条插件路径挪到配置目录;而且 opencode 自己就带了 opencode plugin <module> 子命令,用的本来就是 npm 那一套,codeg 直接调它已经托管的那个 opencode 二进制就行,bun 这个依赖自然也就没了。

    这比换一条命令要大,我不想含糊地塞进 #717。上面的复现步骤先留在这里备查。如果你方便的话,帮我确认一件事就能直接印证这个判断:你机器上 ~/.config/opencode/node_modules 和 ~/.cache/opencode/node_modules 这两个目录,oh-my-openagent 在哪一个里面(或者两个都没有)?

  5. galact-byte commented on Sep 11, 2026

    @galact-byte
    ContributorAuthor

    谢谢你补的这段,正是这段推翻了我上一条的结论。先说我错在哪。

    我上一条说错了

    我当时说「Binary cache 一直是 warn 是如实的,因为根本没触发下载」。这句话只覆盖了「缓存目录是空的」这一半,而且回避了你真正在问的那一半:既然缓存是空的,为什么版本状态是 pass。这两张卡片读的根本不是同一份 opencode,这才是问题本身,我上次没看出来。

    版本状态和 Binary cache 读的不是同一个东西

    • 版本状态那张卡片读的是 installed_version,它来自 detect_local_version(src-tauri/src/commands/acp.rs:635 的 Binary 分支,acp_list_agents_core 和 acp_get_agent_status_core 里是同样的逻辑):先查 codeg 自己的缓存,查不到就退回 resolve_system_agent_binary,也就是 PATH 加 ~/.local/bin。你日志里那句 No cached binary; using system C:\Users\g1582\.local\bin\opencode.exe from PATH 指的就是它。所以卡片上的 1.18.25 和那个 pass,说的是你自己装的那一份。
    • Binary cache 那张卡片来自 src-tauri/src/acp/preflight.rs:505 的 check_binary_environment。它只认 codeg 托管的缓存,而原来接受系统安装的那个分支有个前置条件 binary_dir_entry(agent_type).is_some()(preflight.rs:565),注册表里带 dir_entry 的智能体只有 Cursor 一个。OpenCode 是单文件二进制,于是直接落到「Binary is not installed. Download it from Agent Settings before connecting.」。

    结果就是同一个文件:连接时 connection.rs:989 会去启动它,连接前置检查 verify_agent_installed(commands/acp.rs:547)认它可用,版本卡片把它算作已安装,只有 Binary cache 说没装。这就是你看到的 pass 配 warn,跟点没点下载无关,每次打开设置页都会这样。

    还有第二个原因,它能解释更具体的那句「下载成功之后 Binary cache 还是 warn」。installed_binary_path(binary_cache.rs:280)每次读缓存都会验一下文件头四个字节,而原来的 is_binary_file_compatible 分不清两件事:「打开了,但这是别的平台的二进制」和「压根没打开」。两种都返回 false,然后调用方把文件删掉。Windows 上第二种情况并不代表文件有问题:刚写完的 180MB 二进制会被杀毒软件实时扫描短暂占住,正在运行的 agent 也会占住自己的镜像。前置检查如果正好撞进这个窗口,就会把刚装好的那一份删掉;紧接着版本探测退回到系统那份,于是就是版本状态 pass、Binary cache 说没装。

    修复

    #717(和 #713 是两件事,没有合在一起):

    1. Binary cache 检查改成读启动路径读的那两件事、用同样的顺序。通过时消息里直接写出这次会启动哪个文件,而不是让你去点一个你已经有了的下载按钮。真的什么都没有时仍然 warn。
    2. 文件头探测改成三态,只有确认是别的平台的二进制才删。文件短到放不下文件头也照删,那是永久事实;下载完那一步的校验保持严格,因为那一步文件是 codeg 自己刚写的。

    另外你原帖里 %APPDATA%\app.codeg\cache\opencode\ 那一条,我上次说的没错:那个目录只有 models.dev 的供应商目录缓存,和二进制无关。

    关于 npm

    直接回答:确实只支持 bun,你说得对。src-tauri/src/acp/opencode_plugins.rs:205 的 resolve_bun_binary() 只找 opencode 自带的 bun 和系统 bun,都没有就直接报错;装插件走的是 bun add。

    但只把 bun add 换成 npm install,我认为解决不了你的问题,所以我不打算这么改。我用 codeg 当前锁定的 opencode 1.18.18 在隔离目录里实测了一遍(XDG_CONFIG_HOME 和 XDG_CACHE_HOME 都指向临时目录),跑 opencode plugin <包名>:

    • 依赖装到了 <XDG_CONFIG_HOME>/opencode/node_modules,同时生成 package.json、package-lock.json(lockfileVersion 3,是 npm 的锁文件格式)和一个 .gitignore。
    • <XDG_CACHE_HOME>/opencode/ 下面只有 models.json,没有任何 node_modules。

    而 codeg 现在读和写的都是 ~/.cache/opencode/node_modules(opencode_plugins.rs:61)。也就是说在 1.18 上,插件检查和「安装插件」按钮对着的是一个 opencode 不会去读的目录,换包管理器不解决这一点。真要修,是把整条插件路径挪到配置目录;而且 opencode 自己就带了 opencode plugin <module> 子命令,用的本来就是 npm 那一套,codeg 直接调它已经托管的那个 opencode 二进制就行,bun 这个依赖自然也就没了。

    这比换一条命令要大,我不想含糊地塞进 #717。上面的复现步骤先留在这里备查。如果你方便的话,帮我确认一件事就能直接印证这个判断:你机器上 ~/.config/opencode/node_modules 和 ~/.cache/opencode/node_modules 这两个目录,oh-my-openagent 在哪一个里面(或者两个都没有)?

    在~/.cache/opencode/node_modules里,我不是说让bun改成npm,我是说下载Opencode插件时能允许选择npm下载吗,单bun用的比较少,就是个小优化。

  6. galact-byte commented on Sep 11, 2026

    @galact-byte
    ContributorAuthor

    虽然你回答的挺好的,但可以用真人回复一次嘛

  7. Adam-Dalloul commented on Sep 11, 2026

    @Adam-Dalloul
    Contributor

    是 AI 代理在管理这个账号,回复也是 AI 翻译的,抱歉。技术内容准确,#717 已修。

  8. galact-byte commented on Sep 11, 2026

    @galact-byte
    ContributorAuthor

    是 AI 代理在管理这个账号,回复也是 AI 翻译的,抱歉。技术内容准确,#717 已修。

    好的,理解了,能修复就行

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions