Remove Ask/Execute modes and general product tool approvals so requests use the selected runtime, enabled capabilities, and execution account permissions. Migrate retired application metadata while preserving user content. Retire the Results page while retaining conversation images and stored artifacts. Add local and remote workspace file imports, timestamps and sorting, improve image discovery and saving, and refine workspace navigation and supervision responsiveness. Include the accompanying web-search changes, tests, probes, and product documentation. Remote imports require an updated Agent. Existing artifacts are not automatically copied into project directories. Validation evidence and outstanding failures remain documented in feature progress files; no full test suite or real-model calls were rerun for this commit. Release note: Run requests without switching work modes, import files into a selected local or remote workspace folder, sort workspace files by date, and keep using conversation images after removal of the Results page.
92 KiB
SSH 远程主机与 GoodBuddy Agent 实现说明
工作区文件上传
工作区“导入文件”复用 workspace/manage,由 Desktop 分块读取本机原件并通过新
importFile 动作写入所选远程目录。需要包含该动作的新 Agent;已有版本不支持时报告失败,
不回退为桌面 artifact。文件时间同时保留 Agent 的 mtime 与可用 birthtime,不使用
Linux ctime 作为创建时间。实现及验证边界见
工作区文件和工作栏进度。
状态
下述状态段保留 2026-09-10 的实现与验证截面,不定义额外的信任框架。“新增 Host 只探测、Host 卡片手动准备
Agent/Runtime、Host 直接从 GitHub/北京镜像下载、项目始终使用 Host current 环境”已经完成源码接线,
详细事务与验收边界见
SSH Host 远程环境准备与直连下载设计;
控制面直连源码可直接使用既有 package format v1 包,不等待携带 installer 的新 Agent
包,也不通过额外目录元数据判断 bootstrap 能力;公开能力仍等待 GitHub/北京镜像、
Linux x64/arm64、取消和离线 GoodBuddy 传输的真实 Host 验收。
Windows 到 Linux x64 的安装、Agent-owned Prompt、Agent 本地模型 gateway、断线恢复、
同一 OpenCode Session 续接、取消和终态清理已经使用真实模型与工具验证。Agent
0.11.14 已通过独立 workflow 发布 Linux x64/arm64 复合包和签名累计目录;当时源码
候选为 Agent 0.11.24、Desktop 0.13.0,修复远端原生问答转交和取消待答后的同会话
续发。Agent 0.11.24 要求先升级至 Desktop 0.13.0;当时候选尚未发布。远程文件/Git 管理、
可选模型限额、无限请求时长下的独立连接超时和移除固定十分钟 Prompt 时限由
Agent 0.11.23 提供,显式请求期限与取消仍有效。当前问答源码的真实 SSH/确定性模型证据
及完整生产链路验证边界见工作栏进度。
正式发布状态以 Agent 与 Desktop 独立发布渠道为准。
现有源码显示本地与远端 OpenCode 原生 Task,并取消 GoodBuddy 对生产 Prompt 的
固定墙钟总时限。失败的 agent-v0.11.3 保持不可变且未发布。
2026-09-14 发布状态补注:Desktop 0.13.2 与 Agent 0.11.25 已正式发布,包含此前
问答修复;Agent 0.11.25 的维护发布要求 Desktop 0.13.2。下节进程复用为当前未发布源码,
不是这两个发布的已有能力;历史验证段的日期与边界保留。
跨会话进程复用(未发布)
2026-09-28 Story Graph 接线、2026-10-03 会话开关补充:远程 OpenCode/Continue 的 Ask 和 Execute 通过现有受管 HTTP MCP、工具二进制通道读取桌面图谱。Main 固定项目和会话,并复核监督者 应用开关、会话“使用故事图谱”开关及 Runtime 分配;关闭会话开关后已有远程绑定也拒绝读取。图谱读取不复制数据库到 Host,也不调用模型。三个只读工具、 分页和版本限制由专项设计定义, 源码 Host 探针及协议测试见验证记录。
已发布版本的 RuntimeAcpBackend 按 binding 拥有原生进程,AgentOwnedAcpPrompt 的一条 ACP
连接对应一个原生 Session;同一会话后续 Prompt 可复用,但不同会话不共用进程。
上文“Host 共享 Runtime 环境”指安装与 Agent 环境,不代表原生 OpenCode 进程已共享。
锁定 OpenCode 1.18.29 / ACP SDK 0.25.1 的 Windows 隔离探针已确认:同一个 acp
进程与一条连接可运行两个工作区 Session,原生 chat.headers 能向本机合成模型请求
附带各自 sessionID。它未经过 Agent 所有权、生产 helper、真实工具或 Linux Host,
不是远端交付证明。
进程 owner 与 binding 拆分、单 ACP 连接分派、会话级权限以及模型桥逐 operation
路由的唯一方案见
Runtime 进程复用技术设计 §6。
实施必须保留本文件的 released binding、Agent-owned Prompt、transcript/ACK、模型调用
结果不确定性与断线规则,并在开发期间执行下文真实 Host 验证,不为复用新增持久化账本。
当前源码已接入共享 process owner、AgentAcpConnection 和逐 operation 模型路由;
验收进展见工作栏进度。
取消/失败的 Session 可以留下运行中的共享进程,结果中的 processTree 如实返回
running,不能再据 Prompt 终态推断整进程为空。新行为需要配套 Desktop/Agent,
已发布 Desktop 0.13.2 / Agent 0.11.25 不包含这些改动。
产品语义
本节记录现有实现。2026-09-28 确认的应用中心迁移与云环境管理目标见 PRD、功能逻辑及UI 设计,尚未接入源码。
远程 Host 与项目能力默认关闭。用户在“设置 > 平台功能”的独立 “远程项目”页签启用开关后,Renderer 才显示 SSH Host 管理、托管 SSH 项目创建和已保存 远程项目;Main 在 IPC 边界执行同一开关校验,避免隐藏界面被绕过。关闭开关不删除 Host、 项目或凭据;当前远程项目切回第一个普通本地项目。应用启动仍固定 选择普通本地项目,不会因为保存了远程项目而自动连接 Host。
远程项目不保存产品工作模式。Runtime 使用所选 SSH 账号可访问的文件、进程、网络和已接入工具,
不要求额外 trust tier、consent checklist、一般工具审批或“受控执行”授权。
当前源码要求 runtime/acp capability 6,旧版本在精确协商处提示更新,不补 execute 重试。
2026-10-04 的源码 Host 验证与配套签名包验收分开,见统一执行进度。
Runtime 不获得 root 或 SSH 账号本身没有的权限。托管 SSH Prompt 会把当前选中的文本模型 profile 和凭据作为有界、逐 Prompt 的控制消息交给 Agent;该凭据不进入命令参数、环境变量、 语义日志或模型调用账本,并在 Prompt 终态清除。此行为只适用于用户已明确启用的可信组织 网络和已认证 SSH Host。
组件
应用迁移与云平台接入计划(待实现)
实现顺序对应 FR-RH-1 至 FR-RH-6:
- 从
SshHostsSettingsSection提取独立主机工作页面,接入ApplicationCenter和App页面导航;复用现有 SSH 服务、验证弹窗、安装操作及通知,完成列表与详情改版。 - 扩展应用标识、排序、常驻和配置读取。读取已发布四应用配置时保留原相对顺序及偏好,
新入口追加且默认不常驻;云管理初始关闭,共享远程能力继承
remoteProjectsEnabled。 配置工具公开契约、默认值、持久化、Preload 和 Main 校验同步修改,不能仅扩展 Renderer。 - 按功能逻辑整理能力依赖,将共享远程开关的设置入口迁入应用中心。保留旧值、Host ID、 加密凭据、Host Key 与项目引用;不为页面迁移重建主机或修改 Agent 协议。
- 云平台适配器在 Main 中查询真实 API,凭据复用加密存储;Renderer 仅接收脱敏配置、
实例快照与操作结果。采用满足首批平台发现和导入的最小接口,不预建资源编排框架。
平台连接和实例关联采用独立记录,SSH 主机仍为执行目标,项目继续使用
local / ssh。 - 确认首批平台版本及测试环境,补齐需要的私钥和私网连接路径,逐个验收发现、导入、 SSH 验证、环境安装和真实任务执行。具体存储字段、迁移及适配 API 在实施时细化; 变更已发布存储前遵守数据库迁移规范。
验证覆盖已有用户配置读取、重复实例关联、状态来源、平台查询失败、SSH 不通、删除影响、 能力依赖与页面离开。平台 API 测试与原有远程 Agent 测试分别记录;导航迁移通过不代表 云平台适配完成。新增能力交付前,本文件以下 SSH 组件及历史记录继续描述现有实现。
现有远程执行组件
桌面保存托管 SSH 子任务事件时,共用 执行记录差量存储。 Agent transcript 与公共 Runtime 事件不改变;桌面的来源去重、消息投影事务和恢复序号 继续保留。工具字段比较与 schema 35 对 schema 34 重复块的整理也在该共享桌面层完成; 不把工具过程改为仅存内存,不要求单独升级 Agent。
Renderer
-> 窄 Preload / Main IPC
Main
-> SSH Host 与 Host Key 管理
-> SSH connection pool
-> 签名 Agent / Runtime 安装
-> 远程项目当前环境准备与稳定配置 SQLite 事务
-> 永久项目、对话、Task 与已同步事件 SQLite
SSH attach
-> 远端私有 Unix socket
Detached GoodBuddy Agent
-> Workspace / Git 协议
-> Agent-owned OpenCode ACP Prompt Promise
-> Prompt-scoped Provider gateway / model-call ledger
-> 有界语义 transcript / page / ACK
-> 有界私有诊断记录
-> 直接拥有的 Runtime 进程
不提供把远端路径交给本机 Runtime 的伪本地模式,也不提供 SSH stdio Runtime fallback。
SSH Host
- Renderer 只管理脱敏 Host 快照,不接触密码、密文、SSH Client 或任意命令接口。
- Main 在认证前取得 Host Key,展示算法与 SHA-256 指纹,并保存完整 key blob。
- 首次连接需要用户确认。Host Key 变化展示旧/新值并要求显式替换。
- 密码使用 Electron
safeStorage;系统 SSH Agent 认证不启用 Agent forwarding。 - Host 地址、用户或 Host Key generation 变化时关闭旧连接,并定向退役依赖旧 Host identity 的 Workspace 和 Runtime 会话。下一次选择使用 Host 管理的当前连接记录解析 current Agent/Runtime,不读取项目中的旧 revision 或组件 identity;当前 registry、连接或 capability 无效时才要求显式修复。
Agent 安装与生命周期
-
托管 OpenCode 的直接 ACP profile 与模型桥最终配置都设置
snapshot: false,避免 GoodBuddy 不使用的自动 Git 快照摘要阻塞原生执行;策略和保留的文件、Git、子代理能力 见 Runtime 并行与输出边界。 此设置随新启动的 Agent Runtime 生效,不改写用户仓库或已运行进程的配置。 -
Agent bundle 通过 manifest、Ed25519 签名、payload digest、平台和架构校验。
-
外层
agent-package.json描述符上限为 4 MiB,覆盖包含 OpenCode 离线依赖的实际包 (2026-09-08 Linux x64 验证包为 1,101,863 字节)。Desktop 解包、Host prepare/commit 与目录生成器使用相同上限;其余元数据仍为 1 MiB,签名、文件数量、归档大小和完整性校验不变。 -
Runtime 组包使用的 OpenCode 离线依赖缓存按插件版本复用,安装与替换规则见 Runtime 资源。复制进 Runtime 包的依赖仍属于签名 manifest 的 payload。
-
安装使用当前 SSH 用户目录中的 GoodBuddy-owned 路径和 side-by-side digest 目录。
-
Agent 代码与固定 Node Runtime 一起位于签名 compound payload。显式安装或重装从本次 已完整校验的准备目录原子发布整个 Agent,不扫描旧安装、不创建跨版本 Node 硬链接; Agent 不匹配不会阻止升级,也不会覆盖 GoodBuddy-owned 路径以外的内容。
-
桌面包只携带版本 lock 与 production 公钥,不携带远端 payload。Host 卡片只有一个按 版本事实显示“安装远程环境”“更新远程环境”或“重新安装”的主按钮;次级 SegmentedControl 选择“自动”“Host 下载”或“GoodBuddy 传输”,默认“自动”且不持久化。 每个复合包绑定 Agent、固定 Node 与桌面维护的 OpenCode Runtime 精确工件。添加或重新 验证 Host 只保存并探测,不自动传输完整包。
-
Host 管理独占 Agent/Runtime 的包准备、更新和完整 payload 验证。已有项目的打开和切换 只更新本地项目选择。Workspace 和执行路径按需读取 Host current registry, 执行固定
attach-or-bootstrap并复用当前 Agent 连接;同一进程内复用已确认 identity。 它们不取得安装包、不发布组件,也不通过 SFTP 重读或哈希 payload;已登记 Runtime 的能力读取和 Prompt 启动只核对 registry 与 manifest 元数据,不再次执行、读取或检查 OpenCode 二进制。 -
Agent 的固定 attach/按需启动命令只读取 Host 管理已提交的 installation registry 和 与其 digest 匹配的有界 manifest 元数据,不在每次项目切换时重新验签或哈希完整 payload。 完整验签、payload 扫描和 registry 写入仍只发生在显式 Host 准备/更新流程。
-
项目切换不执行远程核对,立即选择本地项目配置。Workspace 或 Runtime 首次实际使用时 才通过当前 Agent 连接核对所需能力;失败只影响该操作。新建或显式保存项目仍执行完整 准备,并只事务写入 Host、路径和 Runtime 选择。
-
SSH 连接先尝试 attach;Agent 不存在或未运行时执行幂等 bootstrap,然后重新 attach。
-
Agent 是按需启动的 detached process,不注册开机服务,不依赖 systemd、D-Bus 或 Linger。
-
每个模型桥 helper 都为 loopback HTTP 入口生成一次性随机路径 capability;只有写入当前 OpenCode 子进程配置的 URL 可以访问该入口,其他本机用户即使发现临时端口也不能提交模型请求。
-
Agent 监听当前用户拥有的私有 Unix socket。SSH 中断只关闭 relay,不拥有 Agent 和活动 Runtime 的生命周期。
-
私有握手的 HMAC 响应按固定 32 字节的规范 Base64URL 校验,不套用要求字母数字开头 的应用 ID 规则;health nonce 使用固定前缀。读取握手时,流结束或关闭都立即失败, 不留下未结算 Promise;Host Key、同 UID 校验和 HMAC 验证保持不变。
-
SSH Host 设置通过固定探针和有界 SFTP 显示 Host 已登记的 Agent/OpenCode 版本,并与当前 GoodBuddy 所需版本比较。进入或切回该设置页只读取本地 Host 列表,不连接任何 Host; 用户点击“刷新版本”后才探测对应 Host,探测不安装或切换远端组件。项目切换与此按钮 解耦且不建立连接;实际远程操作才建立或复用 SSH/Agent 连接。
-
“平台功能 > 远程项目”中的本地 Agent 包清单与 Host 状态分离。Main 对用户数据目录中 Linux x64/arm64
.gbagent分别执行外层可信签名、桌面/协议兼容性、内部 Agent/Runtime 签名、架构与完整 payload 校验;首次打开和手动刷新还会读取“关于与更新”所选来源的 小型签名目录。Renderer 只得到本地/在线版本、是否有更新、架构、远端 Runtime 版本、 协议和本地状态,不得到缓存路径、key ID 或 digest。目录检查不下载.gbagent,在线 包下载只由用户点击带目标版本的操作触发;离线导入/导出通过 Main 管理的文件对话框完成。 -
GitHub 来源按每页 10 条读取 Release 元数据,最多检查原有的 100 条历史发布, 找到首个有效 Agent 目录及签名地址后立即停止。每次响应仍保留 1 MiB 上限, 避免一次读取全部历史正文和资产详情导致目录检查失败;签名、URL 与包校验不变。 2026-09-06 使用当前 Main 目录读取实现验证公开 GitHub 与北京镜像,两者均可读取 Agent
0.11.19的 Linux x64、Linux arm64 和 macOS arm64 条目,未下载或安装包。 -
“自动”只在 operation/prepare 前用 Host capability probe 选择 acquisition:直连明确 可用才选 Host 下载,否则选 GoodBuddy 传输;显式选择不被改写。prepare、commit 或 adoption 失败后都不跨 acquisition 自动 fallback。
-
Host 下载由桌面控制面通过固定 SSH prepare channel 和结构化 stdin 发送候选信息, Host 取得 compound
.gbagent并核对大小与 SHA-256。显式 GoodBuddy 传输在在线目录 不可用,或本地已验证包版本不低于在线候选时优先租用本地包,包括更高版本离线导入; 线上存在更新且可用时仍取得线上新包。需要下载时,同一次操作会验 SHA-256 与签名、 缓存并取得 lease,再以有界流式 SFTP 上传一个 compound archive 和归档中已验证的 bootstrap Node;约 294 MiB 完整包不会一次读入 MainBuffer,Host 仍再次校验完整包。 -
两种 acquisition 交付到固定 operation staging 后,完全共用 control-plane
prepare → commit → Agent activate/health → Runtime activate → finalize → cleanup。 Main 只保存清理 operation staging 所需的 operation ID。中断或 adoption 失败后,下次 更新尽力清理旧暂存并重新 prepare,不保存或恢复 Agent/Runtime metadata 副本。确认 adoption 后才显式 cleanup;cleanup 失败不回滚健康环境,也不阻塞下一次 fresh prepare。 Host 在 prepare 解包时 完成一次完整 payload 校验,commit 和后续注册检查不再遍历包体。首次 bootstrap 不依赖 既有 Agent daemon,也不要求 format v1 归档携带agent/lib/package-installer.cjs。 -
即使版本号均为当前版本,Host 卡片仍提供同版本“重新安装”,用于修复 registry、签名 或安装 identity 异常。GoodBuddy-owned 同 digest 目录损坏时先隔离后替换,并在发布或 原子 commit 失败时恢复;commit 成功后的激活失败保留新发布内容,下次点击重新安装时 清理旧暂存并重新 prepare/adopt。不要求删除 Host、凭据或引用项目。
-
Host 卡片的“版本匹配”badge 只表达版本事实,不代表 Agent 正在运行或环境健康。重新安装 失败时明确显示本次操作未完成,并以随后重新检查的版本卡片表达当前事实;提交结果 不确定时不声称旧版本未被替换。
-
更新成功后才定向清理该 Host 的 Agent 连接和 Runtime 选择缓存。引用项目再次打开时 解析新的 current registry 并建立当前连接,无需刷新项目记录;当前环境无效时要求用户 显式修复,但不在项目切换中下载或安装。失败或取消保留 Host 配置、凭据、项目、 Workspace 和旧组件。
-
当前 Agent 可以常驻。新安装提升为 current 后,已包含退役逻辑的旧 Agent 每 250 ms 检查 registry 并进入 draining,不再接受新 Prompt;无活动任务时退出,有任务时等待完成。已连接 Desktop 的 终态 transcript ACK 也计入排空条件;断线任务完成后不等待离线 Desktop。待答问题仍是 活动任务。旧安装退出前可以重新 Attach 原任务,但不得重新 bootstrap 已退役安装。
-
Prompt 完成后释放空闲 Runtime;共享进程仍有其他活动任务时保留,最后一个任务完成后 关闭并核对进程树为空。保留语义 transcript 与会话标识;下一轮重建 Runtime,OpenCode 加载原生 session,Continue 通过已有冷启动路径从持久对话历史初始化。
-
显式 stop/retire 可校验并停止已被 registry 替换的旧安装。退出只清理 GoodBuddy 自己的 socket、状态和子进程,不删除会话历史,不删除或覆盖无关 Host 文件。
升级残留清理
Agent adoption 和所有 Runtime 激活成功后,Main 调用新安装的
cleanup-obsolete --installation-id <current-id>。清理由当前 Agent 代码执行,不调用
旧安装的二进制。命令扫描现存 Agent installation 目录,跳过 current 和 candidate,
返回 complete、removed 与逐安装的 deferred 原因。清理不可用或存在延期项时记录
警告,已成功的安装不回滚;下次更新或再次调用该命令时重试,没有后台清理服务。
删除旧 payload 前须完整验证安装包,在既有 bootstrap lock 内确认原 daemon 的生命周期
记录已失效,并只读检查已有 semantic-prompts.sqlite 与 journal。活动、结果未知、
未确认的终态、尚存的 ACP channel,以及缺失或无法读取的记录都会阻止清理。随后根据
该安装的 Runtime owner 记录回收可确认归属的孤儿进程;身份冲突、无法检查或仍有子进程
的 owner 记录保留,等待重试。删除前还检查进程是否使用该 payload,并再次核对 registry。
只删除已确认不再使用的 Agent 可执行文件目录,保留 state、历史和 Workspace。
仍存活的 legacy daemon 不会被此命令回收。 旧实现没有原子排空并拒绝新工作的操作,
持久记录也不足以证明存活 daemon 的内存任务为空。因此即使没有连接或没有持久操作,
仍返回 live-or-unproven-daemon-inactivity,不能把升级后的旧版本自动退出规则追溯应用于
缺少退役逻辑的进程。此轮不裁剪共享 Runtime digest 目录,也不扫描 payload 已丢失而
仅剩 state 的安装。用户报告的六个 daemon、五个旧 helper 和约 2.67 GiB 占用未据此宣告解决。
Host 级环境生命周期
- Agent、Node 和 Runtime 是 Host/SSH 账号级共享环境。新增或重新验证 Host 后先保存 Host 并只读探测,不自动安装;用户随后在 Host 卡片明确选择安装或更新方式,失败保留 Host 并允许重试。
- Host 可以按签名目录固定的 URL、大小和 SHA-256 直接从当前 GitHub/北京镜像来源下载
完整
.gbagent,也可使用 GoodBuddy 本机下载、流式 SFTP 传输和离线导入。自动模式只在 操作开始时择一;执行失败不会在同一次操作中切换 acquisition。 - 项目只保存 Host ID、远端路径和 Runtime 选择。创建或保存时验证 Host current 环境;打开或切换只读取本地配置。Workspace/Runtime 实际使用时从 Host current registry 和当前 Agent 连接取得 live identity,不再扫描、下载、上传或发布 Agent/Runtime。完整 事务、兼容边界和验收要求以 Host 环境准备设计 为准。
- 打开新建/项目设置弹窗只读取本地 Host 验证记录,不并发检查所有 Host;目录浏览或保存 才连接所选 Host。
- 项目选择器中的管理操作默认浮动隐藏,在悬停、键盘焦点或触屏环境显示。管理任意已保存 项目不先激活项目,因此 Host 不可达或远端目录已不存在时仍可删除其本地记录。
- “远程项目”在选择器中按已保存 SSH Host 轻量分组。Host 标题显示 Main 已持有的真实 Agent 连接状态(未连接、连接中、就绪或异常),读取和展示状态本身不连接 Host; 项目副标题只显示远端路径,不重复“托管 SSH”类型。
- 删除 Host 时确认框列出所有引用它的本地项目记录,包括归档项目。确认后只删除本机 Host、凭据、项目及其关联记录,不连接 Host、不删除远端目录或内容;Host 设置写入或 项目事务失败时恢复另一侧,避免只删掉其中一类本地记录。
Workspace
Main 传入已规范化的绝对 POSIX root。Agent 返回 Workspace identity、访问模式、Git 状态和有界能力。
- 创建项目时,用户可以直接输入远端工作目录,或通过输入框右侧的文件夹按钮浏览并选择目录。
- 项目保存前的目录浏览使用 Main 管理的只读、有界 SFTP,只返回目录;每次请求重新解析并校验当前 Host revision 与 Host Key generation,不安装 Agent、不暴露任意 shell/SFTP 接口。
- 普通目录直接列出;符号链接通过
stat检查目标,仅列出目录目标。文件链接、断链、循环链接和目标不可读的链接不列出。返回项保留当前目录下的链接名称和路径,进入该项时沿用realpath解析目标路径。 - 浏览从 SSH 账号 Home 或当前有效绝对路径开始,限制扫描次数、返回条目和总时限;取消、Host 变化、超时或连接失败时关闭 SFTP 并保留用户原先输入。
- 每次浏览最多扫描 2,000 项、读取 64 批、返回 500 个目录,总时限 30 秒。链接检查逐项执行,计入同一次浏览的扫描及时间限制;检查期间取消、超时或通道报错仍关闭目录句柄和 SFTP 通道,忽略迟到的结果。
- 选择目录只更新项目草稿,仍需通过正常的 Agent、Workspace、Runtime 验证和项目保存事务才会持久化。
- Workspace handle 按后端实际支持的方法提供能力;Runtime 本身使用 SSH 账号的正常权限,移除模式不补齐尚未实现的 Workspace API。
- 文件预览按有界页面传输并保持 UTF-8 字符边界;超过单页大小时先返回当前页,用户可继续加载,不把单页传输上限误作文件总预览上限。搜索、Git diff、目录项和显式文件传输继续保持各自的字节、条目数和路径长度上限。
Runtime
托管 SSH 项目支持签名 OpenCode ACP bundle 和 Continue 1.5.47 HTTP 宿主。
Composer Runtime 菜单显示 OpenCode、Continue 和管理入口,不显示直连模型或
DeepSeek Harness。项目与历史会话保留 OC/CN 选择;不支持的旧 selection 恢复为项目
默认值。Main 校验已安装 Runtime 身份与选择一致,按相应 CN/OC 模型 profile 建立模型桥。
本机配置的 SKILL 包和 stdio MCP Server 不上传或分配给远程 Runtime;远程 ACP Session
仅接收当前请求由 Agent 管理的 HTTP MCP 能力(例如图片工具),不继承本机原生
MCP 配置。Continue helper 将 ACP Session 的服务器作为显式 sessionMcpServers 交给
共享 ContinueHostAdapter,与模型桥配置一起生成最终配置;不先写入会被独立模型分支
丢弃的原生配置。新建、加载和续接 Session 使用当前列表,空列表清除旧能力;Continue helper
使用原生 agent 模式提供工具。本机独立模型 profile 仍不继承原生 MCP,
既有知识库和自定义 MCP 的显式分配规则不变。
Node.js、Python 等工具执行环境同样不修改或同步到 Host,
完整边界见工具执行环境。
统一执行
请求直接启动已签名 Runtime,不要求额外的进程隔离命令。ACP 权限回应保留活动请求归属、 合法允许选项与取消处理,不再维护产品只读名单。模型路由仍按独立 Session 隔离,见 共享 Agent Session 设计。
- 直接启动已签名 Runtime entrypoint;
- 使用 Agent 本地模型 gateway 时,签名 Agent launcher 会
exec候选 manifest 锁定的 Node Runtime;进程 owner 校验最终 Node executable,而不是已经被替换的 shell launcher 路径; cwd为项目 Workspace;- 继承 SSH 账号的正常环境、文件系统、进程和网络能力;
- 独占和共享启动均不携带产品模式,工具和模型按请求归属路由;
- 不进行 T2/T3、confinement attestation、approval bridge 或逐工具批准。
保留输入字节上限、用户取消和进程组清理;输出只用有界内存队列与 journal
配合背压,不按 Prompt 累计输出量停止 Runtime。生产 Prompt 不设置固定墙钟总时限;
只要 Runtime 尚未按自身协议结束,Main 和 Agent 就允许其持续运行。启动、握手、单个
控制 RPC、重连尝试和关闭清理仍使用独立的有界超时,测试可以显式注入短 Prompt 时限
验证取消升级,但该覆盖值不是生产默认。无界 Prompt 继续复用已发布的必填
deadlineAt 字段,以 year-9999 哨兵表达;Main 与 Agent 必须同时理解该哨兵,Agent
0.11.10 及更早版本仍会按其 manifest 上限夹紧,因此桌面启用这一语义前必须配套更新
到 Agent 0.11.13 或更高版本。
执行清单接入范围
OC todowrite / CN Checklist 顶部展示的权威需求及接入设计见
Runtime 执行清单,
远程实现与验证范围见执行清单验证记录。
目标范围包括远程 GoodBuddy Agent 运行 OC 和 CN;ACP 仅承担传输与远端协议。
CN 1.5.47 的 serve 提供 HTTP /state、/message,没有原生 ACP 命令。
Agent 的 continue-acp-helper.ts 复用 ContinueHostAdapter 启动该宿主,转换 ACP
Session、文字、工具、问答、清单与取消。Main 冻结的模型配置仍通过既有 Agent gateway
执行,CN 配置仅持有 loopback 路由及占位凭据。成功的原生清单经
_meta.goodbuddyChecklist 进入同一 operation 的 semantic transcript,Main 校验 CN
来源和统一 schema;普通工具参数和正文不生成清单。
2026-09-18 Linux x64 已通过 CN 开发复合包验包、安装、Agent 启动及 CN 激活,随后
通过真实模型清单新增/清空、未 ACK 断线重放、取消和同对话 Ask 续发。默认组包现同时
携带 OC/CN,additionalRuntimes 随主 Runtime 一起验签、安装和加载,仍可读取已有单
Runtime 包。2026-09-19 完整桌面验证覆盖联合包安装、CN 项目创建、清单更新、重启和
取消后续发;实测范围及尚未覆盖的平台见上述验证记录。开发包尚未发布。
2026-09-18 实测 OC 1.18.29 的 ACP 仅转发 todowrite 工具活动,没有原生 plan
通知。已有 OC 插件现将精确 todo.updated 事件经 _meta.goodbuddyTodoEvent 转发,
保留原 Session ID、完整条目及空数组。Main 校验原生事件类型、Session 和清单 schema
后输出 checklist,不从工具标题、截断字符串或正文推测清单。标准 plan.entries
也可映射 OC 清单;尚未确认的 plan_update、plan_removed 只形成活动状态。
清单恢复复用下节流程及既有 semantic transcript/ACK;已通过首份清单未 ACK 时断开、
同操作重连、随后收到空清单的真实 Host 验证。顶部显示与数据库历史由对应模块单独验收。
同次验证复现原生 ACP 冷启动超过 15 秒控制超时。runtime/startPrompt 的控制等待
现至少为 30 秒,其余控制请求沿用原时限;Runtime 外层仍保留启动超时和取消处理。
ACP 与断线
- 管控面只负责有界 JSON-RPC:连接、查询、启动、取消、关闭和重连。数据面只负责 ACP/blob 数据与 Agent 本机 journal。二者共享同一个经过 Host Key 校验和认证的 SSH attach 字节流,但不共享生命周期:管控连接关闭不会隐式取消 Agent 已接受的 Runtime 动作。
- 帧只保留连接 identity、channel identity、单调 sequence、类型和长度。Main 与 Agent 都按调用顺序 FIFO 写入,输入队列达到固定字节或条目上限时暂停 SSH stream。 顺序、可靠传输、分包和网络背压全部交给 SSH;协议不实现 credit/window、优先级 调度、跨 channel 超车、批发送或第二套拥塞控制。
- Agent 在把 Main 输入交给 Runtime 前、以及把 Runtime 输出交给 Main 前,先把 ACP frame 写入本机 journal。ACK 只推进 cursor 并裁剪已确认 frame,不表示 channel 已终止。
- Main 持久化 binding identity 和单调 cursor;保留中的 connection lease 即使处于 offline/reconnecting,也可以先把新 cursor 落盘。重连提交不能覆盖 resume 过程中并发落盘的更新。
- Runtime 事件仍对协议定义的单项传输字段应用既有边界,但不按固定工具调用数或 Desktop 累计展示量中止 Prompt;待消费事件达到阈值时通过 ACP 入站暂停施加背压,不取消原生 Runtime。Main 和 Renderer 不再按 500 条工具/子 Agent 活动或 2,000 个交错展示块丢弃 对话详情;独立运行记录也改由 Main SQLite 完整保存并按批渲染。旧版已经触发本地上限的 历史继续显示可能不完整的提示,不能通过迁移隐藏既有数据缺口。
- OpenCode 原生 Task 工具按
subagent_type、description、prompt和稳定 tool call ID 解析为子 Agent 事件。本地 OpenCode SDK 与远端 ACP 增量工具事件复用同一转换;ACP 首帧缺少参数时可以先显示普通工具活动,后续参数确认其为 Task 后必须替换为子 Agent 状态卡,并持久化任务说明、终态与输出。卡片展开后分为“执行过程”和“最终结果”: 正文、折叠思考与可展开工具记录按收到的顺序显示,工具状态原位更新;完成后仅在最终 结果区显示与末尾正文完全相同的返回结果,避免重复。失败或取消保留已有过程,未终结 工具不再显示进行中。 - 本地 SDK 通过 Task
metadata.sessionId关联子会话,复用稳定消息块 ID 保存过程。 固定 OpenCode 1.18.29 的 ACP 不转发子会话,因此 Agent 的模型桥 helper 在受管临时目录 写入事件插件,并通过既有 ACPsession/update的_meta.goodbuddySubagentEvent转发到所属 Task;不修改签名 Runtime 包。插件文件随 helper 退出清理, 事件继续经过既有 Agent transcript、ACK 和 Desktop 消息持久化路径。 - 托管 helper 显式设置
OPENCODE_ENABLE_QUESTION_TOOL=true,启用 ACP 默认隐藏的原生 问题工具。插件只处理question.asked,通过 SessionparentID逐级确认根会话,并核对/question当前待答列表;不从工具进度或正文构造问题。父、子孙会话问题使用_meta.goodbuddyQuestion送到所属 ACP 会话,有原生 Task 关联时附带对应 call ID。 - Agent 按当前 ACP 会话和 Prompt 保存待答映射,Desktop 公开 ID 包含 binding、operation
和原生问题 ID。回答与跳过经既有认证控制通道的
runtime/respondToQuestion发送;后端 检查 controller、generation、connection、binding 和活动 operation,再调用插件仅绑定127.0.0.1的临时 HTTP 入口。该入口使用进程级随机路径,能力 URL 不写入语义记录。 插件复用 OpenCode 注入客户端的进程内 HTTP 适配器调用/question/{id}/reply或/reject;空答案数组表示拒答,非空答案数量须与问题数量一致。问答不经过 ACP 权限审批。 用户取消托管 Prompt 时,Agent 同步记录语义终态和操作终态。Desktop 等待取消升级及 终态核对后关闭旧 binding、释放会话通道;同一对话的下一条消息使用新 binding,避免 将新请求写入仍携带旧 operation ID 的 binding。断线附加原请求的规则保持不变。 - 语义记录分页另带 Agent 当前
pendingQuestions,用于附加同一存活 Prompt 后恢复待答 问题;历史问答元数据不重新生成表单。原生已回答、拒答、会话空闲、取消、Prompt 终结 和进程退出清除相应映射,迟到的回答报错。回复失败保留桌面输入供重试,答案不会跨连接 自动重放。插件随 OpenCode 实例释放临时端口,helper 退出时删除插件文件。 以上只适用于当前 Agent 管理的 SSH OpenCode 生产路径,不声明任意 ACP 服务的问答兼容性。 真实二进制、SSH 传输和取消验证见工作栏进度。 未发布进程复用源码补齐 Desktop 重启后的多任务并行附加、实时待答快照及 Main 答案 持久化,详见恢复与终态投影; 不把该待答投影当作 durable transcript 或旧版本已经支持的行为。 Desktop Main 接收实时问题时保存其消息位置,回答后不移动到后续输出之后;实时待答 快照不伪造语义来源。位置去重、旧会话边界见 Runtime 交互边界, 当前源码的真实 Host 证据见问答位置持久化。 - ACP 工具结果同时支持文本
content和rawOutput.output,移除 OpenCode 的<task><task_result>外层包装后渲染正文。恢复已有子代理时使用 ACP 所带的所属toolCallId继续路由,不等待新的父 Task metadata,也不重放模型请求。 远端实时过程需要包含该插件的 Agent;旧 Agent 的最终结果仍可查看,历史未采集过程 不会被补造。 - 远端 ACP 普通工具失败后,只有最后一次工具失败之后收到非空白助手正文、Prompt 正常
完成且没有
pending/in_progress工具时,才在done前将仍失败的工具更新为recoverable,保留调用 ID、名称、输入、输出和错误。失败前的正文、推理和纯空白 不作为恢复依据;后续再次失败会清除该依据。原生子代理失败不参与普通工具恢复, Prompt 失败、取消或outcome-unknown也不触发转换。Agent-owned 与直接 ACP 路径 共用此规则;转换表示后续响应已处理失败,不表示工具重新执行成功。 - 本机 OpenCode SDK 路径允许不同会话并行,同一会话仍按请求顺序执行。每个请求独立拥有
SSE 事件订阅,并在正常完成、错误、取消或消费方结束迭代时主动关闭自己的响应流,
不关闭其他会话的订阅或共享 Server。聊天与原生 Compact 共用
consumeEventSubscription, 在结束 SDK 迭代器之前先取消对应订阅,避免 SDK 移除取消监听后留下仍有缓冲的响应流; 不改写 SDK 或提前取消其他请求。取消导致事件迭代结束时保留原取消原因,不改报 “事件流意外结束”。这一清理规则属于本机 SDK 路径,不改变远端 Agent 持有 ACP Prompt 的断线继续执行语义。 - 同一 detached Agent 存活时,短暂 SSH 断线依次执行
controller/resume、runtime/resumeAcpChannel和runtime/replayAcpChannel,从 Main 已确认的 cursor 后只重放 Agent 到 Main 的已记录输出。重复 frame 会被确认但不会再次交给上层。若上一代连接只留下没有活动请求的 detached binding,完成精确 controller takeover 后会先有界停止并核对遗留 Runtime process,再用新 channel epoch 重新打开同一 binding 并恢复已有 ACP session;其他 controller、未证明 takeover 或仍有活动请求的 binding 仍被拒绝。 - Main 到 Runtime 的 ACP 输入、模型请求、工具请求和 blob 不自动重放。
- Continue helper 的会话与上下文仅保存在进程内。Desktop 冷打开已完成的 CN 对话时, 关闭旧空闲 binding,以新 binding 和已有对话历史创建会话;同一存活会话内续发仍递增 Prompt 序列。活动请求恢复沿用原 operation 和序列;start 未确认时通过既有 attach 核对,不递增序列或重新发送 Prompt。
- 无法确认外部 Provider 是否已处理的模型调用保持结果未知,避免重复计费或重复副作用。
- 只有远端返回 identity 匹配且
closed: true时,Main 才删除持久化 binding;传输失败或未确认 close 会保留 recovery identity。 - 终态 close 由 Agent 在一个事务中为两个方向记录 sequence high-water tombstone,删除剩余 frame 和 active channel,并归零对应 journal quota。tombstone 用于拒绝迟到的旧 epoch frame,因此当前不会按时间自动裁剪。
- 断线不主动终止正在运行的 Runtime。用户取消、显式关闭或 Agent shutdown 才触发停止; 输出队列和 journal 达到容量时暂停读取并等待 ACK 释放容量,不把展示或传输容量转换为 Runtime 取消。连接恢复只受当前用户取消信号和单次重连控制超时约束,不把 Prompt 已运行 时长当作停止条件。
- Agent 失联期间继续把 Runtime 输出写入本机 journal;重新连接只校验 controller identity、恢复 binding,并从 Main 最后确认的 cursor 后同步缺失数据。已接受的 指令和结果不确定的 Provider 请求都不自动重放。
Agent-owned Prompt 与 Desktop 恢复
- 托管 SSH 的生产 Prompt 从一开始就由 Agent 持有 ACP
ClientSideConnection、原始 Prompt Promise、Provider 轮次和 Runtime 进程。SSH relay 或 Desktop 进程不属于该 Promise 的生命周期,因此正常退出、强制结束 Desktop 或本机网络中断后,Host 仍能继续 后续模型/工具轮次。该路径现在要求runtime/acpcapability v5;v5 同时保证 Agent 能理解 Prompt-scoped 模型连接的自定义 Header/Body,旧 v4 Agent 由现有受管更新流程 升级后再运行。 - Agent 把 ACP session update、permission decision 和唯一 Prompt 终态写入有界语义
transcript。Main 不恢复旧 JSON-RPC Promise,也不重发
session/prompt;Fresh Desktop 只对同一 controller/binding/operation 执行 takeover、attach 和 ACK-exclusive page。 - 每个 Agent 语义 sequence 在 Main 映射为零到多个公开事件,最后追加内部 checkpoint。
Desktop 在同一 SQLite 事务中去重 provenance、归并原 assistant message,并在 checkpoint
时提交 Task 终态;事务成功后生成器才继续并向 Agent ACK。断电发生在同一 sequence
中间时会重读该 sequence,已写事件按
(binding, operation, sequence, eventIndex)去重, 未写事件继续归并,不会重复 Provider 或工具执行。 - 工具失败恢复所需的正文依据从 Desktop 已提交的
task_events推导:按remote_semantic_sequence数值及remote_event_index顺序判断最后一次失败后是否有 非空白text,重连时与已有工具状态一起交给 Runtime,保留断线前的有效依据。 不从会原地更新或被截断的展示块推断顺序,不新增表、字段或持久快照。终态转换按callId排序,并重发已为recoverable的工具,使部分终态落库后的重读仍使用稳定的eventIndex,沿用既有 provenance 去重和 checkpoint 提交。 重连时,工具及原生子代理的状态也以已提交的远端活动事件为准,覆盖消息终态处理派生的 失败状态,避免将未完成活动误判为可恢复错误,保证终态重放内容一致。 - 远程 context metrics 与对话级压缩后的估算值按本次请求实际使用的 Runtime 选择写入
context_state_json。实时接收与恢复入口都传入请求的选择;数据库在未传入时按对话层、 项目层解析,缺省执行方式为 OpenCode(规则见 执行方式与模型选择设计)。 继承项目设置的对话保持runtime_selection_json = NULL, 不为接收 usage 固定对话 Runtime;去重和消息/指标写入仍在同一 SQLite 事务中完成。 - ACK 后 Agent 删除已确认事件,只保留小型操作终态与游标用于幂等核对;未 ACK 输出继续
保留。Main 按 transcript page 的最高连续 sequence ACK,终态仍立即 ACK。单事件、单页、
单 Prompt 总字节和事件数都有上限;Agent 始终为唯一终态预留一个事件和最大事件字节,
避免配额耗尽后无法记录终态或无法重启。已 ACK 终态操作和已交付模型 ledger 在 daemon
运行期间也按固定上限裁剪,不依赖重启。Agent 重启不能重建内存中的 Runtime/Prompt
Promise,因此启动时把遗留 nonterminal 记录变为
outcome-unknown,Desktop 只同步该 终态而不自动重放。 - prepare 已接受但 start RPC 未到达时,Agent 使用两分钟 prepare-to-start watchdog 清除
进程和 Prompt 凭据并记录
outcome-unknown,避免无界 Prompt 哨兵造成永久悬挂。 - Desktop SQLite 仍是永久可见项目/对话数据的权威;Agent transcript 只是尚未同步事件的 权威。启动后 Renderer 先订阅恢复进度,再触发每项目恢复。项目选择器依次显示网络、 Agent、Runtime、cursor、完成或失败/重试;只阻塞受影响项目的发送和队列,已有历史与 其他项目保持可用。
- 完成提示是项目选择器内恢复进度的收尾反馈,首次收到该项目该
requestId的完成状态后 显示 3 秒,然后从收起按钮和展开菜单同时隐藏;不另发全局成功通知。计时由ProjectSwitcher持有,切换项目、开合菜单或重复状态快照不延长期限,也不重放已隐藏的 提示;新requestId的恢复可以再次展示。进行中状态和失败提示持续保留;重试操作仅放在 展开的项目列表对应项目旁,收起时只显示状态,不在新建项目按钮旁增加恢复按钮。 隐藏仅作用于展示层,App保留完成业务状态,继续用于发送、队列恢复和事件顺序判断。 - 正常应用退出对已接受托管 SSH 请求执行 detach,不等待远端完成;本地请求和尚未接受的
请求仍按原行为取消。用户显式“停止”始终发送稳定 operation cancellation,并等待 Agent
语义终态。已进入 Agent-owned
run但 start/attach 响应仍不确定的请求继续保留为interrupted + remote_recoverable,并自动走 exact attach;不会因为尚未收到第一个公开 事件而丢失恢复身份。
Agent 本地模型 gateway
- Main 在
runtime/preparePrompt中发送当前解析后的有界 profile;Agent 只在该 operation 的内存状态中持有 Provider URL、API Key 和认证信息。OpenCode 仍通过 Prompt 私有 Unix socket 发出模型请求,但 HTTP Provider dispatch、响应交付和稳定 call ledger 全部位于 Agent,因此 Desktop 断电后可以继续下一轮。 - Agent 校验固定 model、协议和 API path,拒绝 background/store、provider web search、
provider MCP、持久 conversation、非文本 modality 和其他可独立计费能力;请求/响应 body
各保留 64 MiB 的内存传输上限,用于容纳长上下文和图片输入,响应同时核对声明长度与短读。
Desktop blob 模型桥保留已发布 v1 的 canonical JSON 字节,不添加尾随换行。单条消息按
最多 2 MiB 的帧发送,接收端逐帧消费流量额度,跟踪 JSON 结构并在消息上限内组装;
已发布端的单帧消息可直接接收,多帧大消息要求两端均使用更新后的实现。每个
(binding, operation, roundIndex)只 dispatch 一次;已 dispatch 但未证明完整交付的调用 变为outcome-unknown,不会自动重试。 - Agent 不按固定模型调用次数或 Prompt 累计输出 Token 数停止 Runtime;每次 Provider
请求遵循所选模型 profile 的单次输出设置;未设置时保留 Runtime 请求中的 Token 参数,
更新后的 Agent 不补入固定 32,000 Token,也不再按 60 秒或桥接层的 120/150/180 秒
总时长中止请求。它通过非 critical 的
runtime/model-bridge-optional-limitsv1 capability 声明支持省略 profile limits;Main 在建立托管 Runtime 时按实际连接的 capability 选择 profile。锁定的已发布 Agent0.11.22不支持省略这两个字段,Main 对该路径保留原有 32,000 Token、60,000 ms 默认值及 1,000,000 Token、300,000 ms schema 上界;这些兼容 值不应用于声明支持省略 limits 的 Agent。 显式请求超时、Prompt deadline、用户取消和连接关闭仍会中止对应操作。模型桥协议不包含 Prompt 调用次数或累计 Token 配额字段。实际 usage 在语义 transcript 中同步回 Desktop 的 usage/task 数据。 - 新组包的 Runtime manifest 将
maximumPromptRuntimeMilliseconds设为0,表示由 Prompt 自身的 deadline 决定时长,不再额外截为十分钟。旧 manifest 中的正数限制仍按其 声明执行。独占进程 owner 使用真实剩余时长安排 Prompt deadline;共享路径由 binding 执行逐 Prompt 输入与期限检查,不把历次 Prompt 累计当作整个进程的配额。 启动与停止等待的有界超时不再缩短 Prompt。 - helper 可以接收并发模型桥请求,同一 Session/operation 的稳定模型桥按到达顺序 等待并交付,不同 operation 可并行。请求在排队后再次核对原路由,过期请求不转交给 新 operation;每个响应只有在 HTTP 完整 flush 后才发送 delivery ACK。
- GoodBuddy 自己管理会话标题,因此传给 OpenCode 的配置禁用 title Agent;一次用户 Prompt 不会额外触发标题模型请求。
- Agent gateway 不再把 Provider 请求往返 Desktop;legacy blob bridge 只保留给旧的 非 Agent-owned 测试/兼容路径。凭据不进入 Renderer、SSH 命令参数或远端环境。
- Unix socket 接收端按
readableLength中已经缓冲的字节增量排空一个声明长度的帧, 不会在部分大响应到达时反复请求尚未缓冲的完整剩余长度;短读、连接结束、错误和取消 都会使当前交换失败。原生 Linux 回归覆盖至少 256 KiB 的 broker 响应。 - Unix broker 的请求超时
0表示不设置请求总时限,不等于零毫秒连接等待。 连接仍有独立的默认 5 秒超时;只有显式正数请求时限才与连接时限取较小值, 用户取消仍关闭连接并中止 dispatch。 - Renderer 把相邻 text/reasoning delta 合并为消息 block 时始终替换最后一个 block, 不修改既有 React state 对象。这样开发环境 StrictMode 重复调用 state updater 时, block metadata 与 canonical 消息正文保持一致。
Agent 开发期间的真实 Host 验证
2026-09-10 Desktop 0.12.11 / Agent 0.11.23 候选复测:共享 Linux x64 Host 的当前
源码通过工作区协议重命名保护、字面路径/重命名/合并提交差异、Unix 桥接 256 KiB 往返及取消,
以及继承 Runtime 指标的数据库重开与去重。隔离 Agent 报告版本 0.11.23,桌面 managed ACP
经真实 SSH、Agent 和既有已安装 OpenCode 各完成一次 Ask、Execute;共 2 次真实模型请求,
全部 HTTP 200、completed 且已交付,指标持久化后未固定继承选择。首次连接准备超时,未发送
模型请求;重试成功后清理测试进程与目录,并按本轮 bundle 摘要确认、清理一次遗留上传目录。
本次为当前源码复测,不是正式 0.11.23 复合包安装验收;三个原生包由发布 CI 构建和验证。
本地发布回归为 3845 项通过、66 项跳过,发布说明校验、typecheck、lint 通过;发布准备未执行
本地桌面生产构建或打包。
本轮 020a9ad 工作树修复使用当前源码在共享 Linux x64 Host 验证:默认 Unix broker
完成 256 KiB 响应并传递取消;生产 AssistantDatabase 在临时库中写入继承项目的指标,
重开后去重重放,未固定对话选择。当前 Workspace 协议的目标存在/同名/硬链接重命名
保护、字面路径 diff、重命名 diff 和 merge commit diff 均通过,Git 使用 Host 已配置身份。
当前 Desktop createManagedRemoteAcpRuntime 经真实 SSH attach、隔离 Agent、OpenCode
和 Agent gateway 完成 Ask 与 Execute,均得到两字符回答和 done。Execute 的真实
model-usage 转换为指标后通过生产数据库持久化与去重,继承设置保持未固定。
共 3 次真实 Provider 调用(2 次 Ask、1 次 Execute),均 HTTP 200、completed 且已交付;
前两次运行在模型完成后被测试 harness 的 usage 元数据/事件名断言拦截,并非产品失败。
未修改产品来适配 harness:构建时直接解析 ACP SDK 的 ESM 入口,凭据只通过既有
safeStorage 与模型控制协议使用。各次隔离 Agent 停止后剩余所属进程数为 0,测试目录和
上传文件均已回收,原 Host registry 与已安装组件未改变。此次不覆盖 UI 点击或安装升级。
2026-09-10 已发布模型桥兼容修复:从 agent-v0.11.22 读取的源码与当前源码分别在共享
Linux x64 Host 启动隔离 Agent daemon。当前 Main 的 createManagedRemoteAcpRuntime
经真实 SSH attach、Agent protocol、OpenCode 和 Agent gateway,在两版 Agent 上各完成
一次 Ask、一次 Execute,均返回 OK;模型账本共 4 次调用,全部 completed 且已交付。
旧 Agent 未声明 optional-limits capability,当前 Agent 声明该能力。使用既有加密设置和
固定 Host identity,凭据仅经协议进入内存;测试 daemon、Runtime 和运行目录已回收。
本次覆盖托管 Runtime 入口,未执行 UI 点击、安装升级或长时间 Provider 等待。
6 个聚焦测试文件共 77 项通过;另用真实 tag codec 验证四种消息双向互通。typecheck、lint
通过;全量 npm test 为 3,739 项通过、4 项失败、64 项跳过,失败涉及发布/便携包夹具、
DSH MCP 暴露和 Runtime 发现,未扩展修复范围。
2026-09-10 模型桥限制修复:共享 Linux x64 Host 使用当前源码构建的 gateway、Unix
broker 和 loopback helper,通过 2 MiB 请求/响应往返,并确认客户端取消传到 broker。
使用 GoodBuddy 加密设置中的模型凭据、既有固定 SSH identity 和 OpenCode 1.18.29
运行 Ask、Execute,两个模式均收到 HTTP 200 并返回 OK。共发出 3 次真实 Provider
请求:Ask 成功,首次 Execute 的最终结果因本地命令采集超时未保留,单独复测 Execute
成功。运行中测试凭据只经 SSH stdin 进入内存;测试进程和临时目录由测试运行回收。
本次实机检查覆盖当前源码的模型桥与 Runtime helper;未重装共享 Agent,也未重跑完整
Desktop attach/bootstrap。Prompt 长时运行和精确 deadline 使用假时钟回归验证。
最终聚焦回归为 14 个文件、193 项通过、5 项平台跳过;typecheck、lint 和开发 build
通过。此前全量 npm test 为 3,703 项通过、22 项失败、63 项跳过,失败分布在 Runtime
发现、发布/便携包夹具、DSH ACP、模型设置和内置工具分类;该次全量结果来自并行修改中的
工作区,未据此修改其他任务的文件,也未把聚焦通过等同于全量通过。
2026-09-09 已在隔离 Linux x64 Host 验证当前源码的快照配置修复:桌面
ManagedRemoteExecutionServices 经 managed ACP、真实 detached Agent 和模型桥启动
OpenCode 1.18.29,Ask 完成原生读取,Execute 完成 4,000 行文件的 CRLF → LF 转换。
4 次实际 Provider 请求全部为 HTTP 200,最终原生配置在两种模式均为 snapshot: false,
权限仍为 ask/allow,transcript ACK 分别为 15/15 和 12/12。测试 Agent、模型桥、
Runtime 与 relay 均已回收,原有 Host registry 未改变。这是实际链路和关闭验证,
不是 Linux 前后性能对照,也未注入取消;不代替正式发布资产校验。
任何会改变已部署 GoodBuddy Agent 或桌面到 Agent 生产链路的源码改动,都必须在开发期间 使用共享 Linux x64 真实测试 Host 验证。适用范围包括 Agent daemon、Agent protocol 及共享 contract、Agent 组包与安装、attach/update、Runtime 启动与进程归属、Workspace、 model bridge,以及生命周期和恢复逻辑。单元测试、mock、fixture、CI 或正式发布前回归 都不能替代这一步;不得等到准备发布时才首次运行受影响的真实链路。
测试 Host 有两个网络入口:
192.168.0.23:局域网入口,在本地网络可达时优先使用;10.7.0.23:VPN 入口,局域网入口不可达时使用。
两者指向同一台物理 Host,只代表两条访问路由,不能计为两个独立 Host、两种架构或两份 覆盖结果。测试只使用已固定的 Host identity 和 GoodBuddy 已有凭据存储;地址不得写入 产品行为或默认配置,用户名、密码、私钥等凭据不得写入源码、文档、命令、日志或测试输出。
开发时应在改动链路达到可运行状态后尽早执行真实 Host 验证,并在最终相关改动后重复受 影响的场景。必须使用当前源码构建或当前候选包,不能只验证 Host 上已经发布的旧 Agent。 按改动范围至少选择以下场景:
- Agent 组包、安装或升级:验证当前候选的 attach-or-bootstrap、安装/更新、版本切换及 随后的连接。
- Runtime profile、进程启动/归属或工具能力边界:通过桌面生产入口启动真实 Runtime, 验证受影响入口、启用与分配以及所需写入、 进程和网络能力。
- Agent protocol、RPC、stream、model bridge 或模型消息链路:执行最小有界真实模型调用, 禁用非必要工具和附件,并记录实际调用次数;大消息或工具链路改动还应覆盖对应的真实 payload/工具场景。
- 会话、owner、取消、超时、断线或恢复逻辑:执行与改动直接相关的中断、取消、Agent/ Runtime 重启、SSH 断开或重连序列,并确认不会错误重放结果未知的操作。
- Workspace 或 Host 文件路径:只在 GoodBuddy 专用测试目录操作,验证真实路径和权限, 不得读取、覆盖或删除无关 Host 文件。
停止或修改远端进程前必须先核对其启动身份、PID/进程组和 GoodBuddy 归属。若两个入口均 不可达,应立即把真实 Host 验证报告为开发阻塞,保持该验证未完成,不能把 Agent 改动表述 为已完成,也不能把首次真实验证推迟到发布阶段。
离线配置缓存简化验证(2026-09-08)
npm test -- tests/opencode-config.test.ts src/main/agent/opencode-runtime.test.ts src/main/agent/bundled-runtimes.test.ts tests/remote-runtime-bundle.test.ts tests/agent-bundle.test.ts --testTimeout=30000 通过 108 项;npm run typecheck、npm run lint 和 npm run build 通过。
全量 npm test -- --testTimeout=30000 --hookTimeout=120000 当次结果为 3556 项通过、28 项失败、58 项跳过;其中离线配置路径断言随后修正并通过上述聚焦测试,未重跑全量。其余失败涉及 Agent 包元数据大小限制、Darwin 组包超时、Runtime 探测、DSH 和打包夹具。
测试 Host 的 SSH 端口可达,但候选复合包验证受元数据大小限制阻塞,未部署或执行实机安装/更新验收;本次真实模型调用 0 次。
以上为缓存简化阶段的历史记录,不代表后续发布前修复的最终结果。
发布前修复实机验证(2026-09-08)
共享 Linux x64 Host 上使用当前源码、锁定 Node 与 OpenCode 1.18.29、进程内临时签名
身份组包,签名目录读取、生产 preparePackage/commitPackage、adopt、Runtime activate
与 health 通过。所有写入位于独立 GoodBuddy 测试 HOME,未修改共享安装。
真实 Desktop 协议客户端已通过 Ask 文本回复、Execute 原生 Task 子代理在 Workspace 外 的专用测试目录写文件、读回校验、关闭连接后重连同一 daemon,以及 stop/bootstrap 后 health。首轮发现握手 Base64URL 误拒绝后完成上述修复;最终源码复测通过,独立 Unix endpoint 连续 20 次握手也通过。两轮模型账本各 5 次 completed,本轮合计 10 次真实文本 模型调用,没有发布工件、签名目录或 release tag。
最终自动化回归与尚未覆盖的系统休眠场景见 工作栏进度。
已完成的 E2E 验收记录
macOS arm64 Host 支持
agents.yml 增加 macos-15 / darwin-arm64 的原生 CI 组包任务,使用临时测试
签名校验 Agent、固定 Node、Koffi 和 OpenCode,并比较两次组包的字节摘要。
构建输入与检查的权威说明见 BUILD.md 的 Agent 原生 CI 策略。
此 CI 任务不发布工件。生产 lock、agent-release.yml、安装器、Desktop 包管理和
SSH Host 链路现支持 linux-x64、linux-arm64、darwin-arm64,三个目标共用
原有 catalog JSON 和签名格式,不增加 Mac 专用目录。旧版 Linux-only Desktop
读取器不能解析混合目录,首次发布 Darwin 条目前需先升级 Desktop。
macOS 保持 SSH 按需启动 detached Agent,不要求 launchd、开机服务或管理员权限。
私有 socket 使用 /private/tmp,通过 getpeereid 核对 UID;进程身份、启动标识和
进程组通过系统原生 API 获取。取消前枚举 Runtime 的实际后代并核对 PID、启动时间
和可执行文件,停止独立进程组中的工具,再停止 Runtime,避免只杀主进程组留下工具。
2026-09-06 当前源码在真实 macOS arm64 Host 的隔离目录通过生产安装器
preparePackage / commitPackage、adopt、health、Runtime activate、stop、
bootstrap 和再次 health。实际 Desktop 协议客户端通过 Attach、只读 Workspace
打开、真实 Ask 输出、Execute 写入并读回测试文件、取消工具并验证子进程退出,以及
重新连接同一 daemon。两个 Darwin 原生进程测试通过,其中一个覆盖独立进程组子进程。
共享 Linux x64 Host 同时通过当前源码组包、生产安装、生命周期、真实 Ask 和重连。
这些验证没有发布 catalog 或工件;GitHub Actions 和正式下载渠道的发布验收尚未执行。
最终本地 typecheck、lint、开发 build 和 diff whitespace 检查通过。最终全量
npm test 为 3520 通过、57 跳过、0 失败(326 个测试文件通过、9 个跳过)。
此前 ActivityPanel 的批量记录用例超时、App 的实时浏览器用例未观察到预期调用,
分别复跑后通过;未修改这两个用例或放宽超时,随后完整测试套件通过。
隔离测试 ledger 统计 Mac 模型请求 7 次,Linux 首轮
1 次;最终 Linux 源码重装后又完成 1 次最小 Ask,总计 9 次真实模型请求。
以下为较早的仅构建阶段记录,摘要不代表上述最终源码产物:
2026-09-06:在真实 macOS 26.5.2 / arm64 Host 的独立测试目录运行当前源码
build/agent-ci-bundle.cjs --platform darwin --arch arm64,退出码为 0。
测试使用固定 Node 24.19.0、OpenCode 1.18.29 和内存临时签名密钥;Node 官方
归档 SHA-256、OpenCode integrity、Mach-O 架构、内外层签名和两次组包摘要比较
通过,Agent CLI 加载、Koffi 原生模块加载与 OpenCode --version 检查通过。
生成 goodbuddy-agent-0.11.18-darwin-arm64.gbagent,本次测试包 SHA-256 为
9c63ba080def56ebd371a622f2650b89d0c652444077bd6ee19c4bd51b60f6ff。
临时签名每次独立运行都会变化,因此该摘要只标识本次测试产物,不是发布输入。
源码压缩传输 529,624 字节,大依赖由 Host 直接下载并复用 npm 缓存。
真实模型调用为 0 次;没有安装 Agent 服务,没有修改在线 catalog 或发布工件。
该仅构建阶段的聚焦测试为 53 项通过、1 项平台跳过,typecheck、lint 和开发生产 bundle 构建通过;这组历史结果不替代完整 Host 支持改动后的最终验证。
Linux 历史验收
-
2026-09-16:当前源码通过本机 Linux x64/arm64 两份
0.11.18旧包副本的生产签名、 manifest、包内 lock 和 payload 校验(OpenCode1.18.9),原缓存元数据未变。 共享 Linux x64 Host 的 LAN/VPN 两条路由均通过固定主机密钥验证;在/root/tmp独立目录运行当前源码校验与preparePackage/commitPackage,随后旧包 Agent bootstrap、health、stop 全部通过,未操作原有 Agent,模型请求为 0 次。 相关扩大回归为 326 通过、1 跳过;全量npm test为 4146 通过、67 跳过、4 失败, 另有 App 测试文件因缺少LocalInferencePage导入失败。大离线包超时用例复跑通过; 其余失败为 heartbeat fixture 重复pinned列及导航设置默认字段导致的断言差异。 Node/Agent 类型检查和本次改动文件 lint 通过;全量 typecheck 受上述缺失组件阻塞, 全量 lint 受 story-graph demo 的 22 项document未定义错误阻塞。 -
2026-09-06 使用当前源码隔离 Agent 验证原生子代理过程插件。最终场景收到 37 条 ACP 插件事件,桌面侧从已保留活动重建跟踪器后仍接收后续文本与工具;子代理和父请求正常 完成,最终模型调用账本为 4 次 completed。此前成功场景另 4 次,两轮真实 Host 共 8 次模型请求。
-
同日 Windows 隔离桌面实际发送 OpenCode 原生 Task,展开卡片可看到进行中的正文与 read 工具,取消后已有过程保留且工具显示已取消;正确工作区场景完成后显示测试文件 内容,最终结果不重复留在过程末尾。本机有界代理共记录 10 次模型请求(含错误路径、 取消和成功场景);另外 2 次使用原生测试配置的请求返回 401,改选显式测试模型后通过。 未改动正常用户设置,也未发布 Agent 包。全量静态与测试结果见 本轮验证记录。
-
2026-08 的本地 fixture 完整验证 Linux x64 Agent
0.11.2-e2e.12、Node24.19.0和 Agent protocol2.0;当时没有 arm64 fixture,因此该记录不能作为当前独立发布 的双架构验收。Agent0.11.10后续已由原生 workflow 发布并公开验证双架构工件; 当前源码 lock 固定为0.11.21;正式发布状态以独立 Agent Release 与签名 catalog 为准。 -
2026-08-30 在共享 Linux x64 Host 的隔离测试 HOME 中验证当前
0.11.13源码候选: 签名 Runtime 清单的测试墙钟上限为 1 秒,模型桥首轮故意延迟 2.515 秒后 Prompt 仍在 5.770 秒正常完成;随后 OpenCode 原生 Task 依次产生running、completed子 Agent 事件并完成父请求。测试结束后隔离 Agent、Runtime、socket 和 Workspace 已全部清理, Host current Agent 仍为0.11.10。 -
2026-08-31 使用隔离 Linux x64 Agent
0.11.14候选完成 remote-authoritative 矩阵: 15 秒短 smoke、2 分钟正常 detach、5 分钟本机 harness 强制结束、并发对话、SSH relay 丢失、显式取消、确定性 Provider 错误、2 秒 Provider 结果未知、AgentSIGKILL/重启, 以及 reopened Desktop SQLite 恢复。成功工具的 START/END sentinel 都各出现一次; Provider 结果未知与 Agent 重启只提交outcome-unknown,未重放 Prompt、模型调用或工具。 -
同一矩阵中的 Desktop schema v32 实际恢复保持原 project/conversation/request/ assistant-message 身份,在同一事务中提交语义 provenance、消息与 cursor;重新打开
assistant.sqlite后消息和 Task 都完整,重复 provenance 返回 false,recoverable Task 归零。 -
最终源码复核后重新构建测试签名 package: SHA-256
39307fd1dccd638dcb723027591bcd83deab7057d550c99eff6f037e339829f4, installationagent-2cad05acfebe853394807e3a11f7befcd9f47215c2cf3a33a03d5f644b45716e, Runtime1.18.29/ bundlesha256:6c7fc975415ef2547d3729bc4772d3e78362c2e76c05d1fc24968a0468fcb7ba。 最终 15 秒 detach/recovery 使用两个模型轮次、一个工具和一个终态,ledger 两轮均completed + delivered,语义latest=ACK=41,保留事件、Runtime owner、ACP channel/ frame 都为 0,START/END 各一次。最终取消另使用一个模型轮次、一个工具和一个 cancelled 终态,语义latest=ACK=29,清理计数同样为 0。最终补充验证共 3 次真实文本模型调用。 采证后已按 PID/starttime/executable 停止精确隔离 daemon 并删除隔离 Host 测试根目录;/root/.goodbuddy下的共享 Agent 安装和进程未被修改。 -
2026-08-31 使用当前工作树短期测试签名 Linux x64 候选,在全新隔离 HOME 和 installation 中验证有界诊断:bootstrap、detached daemon、attach、relay 断开与同 controller 重连、
controller/resume、Runtime candidate 激活和 OpenCode ACP 进程启动均通过;新diagnostics --installation-id命令在 daemon 重启后读取到 23 条完整 JSONL。诊断目录 为0700、文件为0600,单文件 3719 bytes,未超过 64 KiB。六类测试哨兵覆盖 Prompt、 密钥、环境、SSH 参数、用户文件内容和原始错误消息,CLI 输出与磁盘均未出现哨兵。把隔离 diagnostics 目录临时设为不可写后,Attach 和agent/status仍正常;随后已恢复权限。 -
2026-09-02 使用后续锁定为
0.11.15的当前源码 Agent bundle 在共享 Linux x64 Host 的唯一/tmp/goodbuddy-e2e-no-reverify-*隔离 HOME 验证已登记 Runtime 的快速激活路径。测试 复制 Host current Runtime registry 与 bundle,在副本 OpenCode 二进制追加哨兵字节后,runtime activate仍依据匹配的 registry 与 canonical manifest 成功返回activated=true,确认普通激活不重新哈希 payload 或执行 OpenCode 版本探测。本次没有 模型调用;harness 成功后已删除整个隔离目录,未修改共享 Agent/Runtime 安装或进程。 本次未注入模型凭据或执行 Prompt,真实文本模型调用 0 次;三文件轮转继续由聚焦测试覆盖。 测试结束前按 PID、UID、starttime、executable 和唯一 installation 核对并停止所有本次 daemon,本地及 Host 临时目录均已清理,共享 current Agent 和/root/.goodbuddy未修改。 -
2026-09-03 协调发布候选将上述已验证源码锁定为 Agent
0.11.15,并将 Desktop 最低 版本同步为0.12.2;Agent protocol2.0、固定 Node 与 OpenCode Runtime lock 均未 改变。Agent bundle/package/catalog/workflow、Runtime 注册加载、Desktop package workflow 与 Release Notes 聚焦测试106/106通过、1 项平台用例跳过;全量npm test为3478通过、51跳过,typecheck 与 lint 通过。本轮没有新增模型调用, 也未在本地运行 production build、package 或安装探针。 -
2026-09-03 使用包含当前 Runtime capability 修复的源码 harness,在共享 Linux x64 Host 的唯一
/tmp/goodbuddy-e2e-runtime-capability-*隔离 HOME 中读取签名 Runtime 副本。 Agent 成功报告已登记 OpenCode Runtime;最终源码又在唯一/tmp/goodbuddy-e2e-direct-modes-*隔离 HOME 中分别直接启动 Ask 与 Execute,两个模式 都未经过外部进程隔离命令。Runtime owner 和隔离目录均已清理,未修改 Host current Agent/Runtime。本次只验证能力声明和真实进程启动,没有发送 Prompt,真实文本模型调用 0 次。 -
2026-09-03 使用包含本次模型轮次与输出背压修复的当前源码 Agent,在共享 Linux x64 Host 的唯一
/tmp/goodbuddy-e2e-*目录完成 Runtime 激活和 Agent 本机模型 gateway 验证。模型 gateway 通过所选 Anthropic 连接返回预期随机哨兵,HTTP 状态为 200,实际 文本模型调用恰好 1 次;Host 临时目录随后删除,共享 Agent/Runtime 安装和进程未修改。 -
2026-09-04 使用当前源码 Desktop 和共享 Linux x64 Host 的既有 Agent/Workspace 生产链路验证分页文件预览。专用测试文本共 262,166 bytes,首个 256 KiB 页面在三字节 UTF-8 字符前回退并显示 262,143 bytes;继续加载后完整追加剩余文本,页面不再显示加载 按钮且没有错误。测试未调用模型;专用远端文件、目录和本机隔离用户数据均已清理。
-
正常 Host 更新路径把 Linux x64 Host 的 Agent 更新为
0.11.2-e2e.12,并确认 OpenCode Runtime 已安装版本与所需版本均为1.18.29。 -
一条新的 Ask 用户操作只提交一次。OpenCode 先在 build 模型轮次请求一个原生
read,读取专用测试 Workspace 中的证据文件,再在第二个 build 模型轮次生成最终 回答;没有 title 模型轮次,也没有第二个工具调用。 -
两个模型轮次都记录已交付,远端 helper 保持休眠且 Unix socket 没有未读响应积压。 持久化的 canonical 助手正文精确为
GOODBUDDY_REMOTE_TOOL_4C6B9D8A。验收操作没有 重放任何结果未知或已经完成的 Provider 请求。
项目保存
远程项目只持久化稳定配置:
- Host ID;
- 规范远端工作目录;
- Runtime selection。
Agent installation、Host revision/Host Key generation、Workspace identity、Runtime bundle/adapter digest 和 capability generation 都属于 live connection/lease,不进入项目 domain object 或 SQLite。打开托管 SSH 项目不接受 Renderer 回传的旧项目草稿,而是从 Host store 解析当前连接目标,通过 Agent/Runtime 安装管理器的 current/activate 读取路径取得 registry identity,再用同一个 Agent 连接验证 Workspace 路径和 Runtime capability。该流程 不会扫描完整 payload、取得安装包或发布组件。
实时 Runtime 创建只接受 OpenCode,使用当前解析后的模型 profile 准备 Agent 本地 gateway, 从当前 Agent 连接和 Runtime registry 取得会话 identity,并在该连接上打开 Workspace 和 ACP channel。Host 编辑或环境更新会定向失效 Agent 连接与 Runtime 缓存,下一次请求自然 重新取得 current 环境;无需修改项目。每次 Prompt 沿用 ACP Runtime 的能力范围和请求归属, 不恢复产品模式。
Renderer 在用户主动打开已有托管 SSH 项目时立即切换,不显示远程激活状态。Host、Agent、
Workspace、Runtime 和 Saving 进度仅用于新建或显式保存项目;进行中可显式取消并禁用会
产生冲突的项目创建和设置入口。远端 RPC 拒绝只向
Renderer 暴露固定方法名、数字 RPC code 和有界 service code,不转发 Host 私有错误详情。
runtime/preparePrompt 在远端明确拒绝且尚未接受 Prompt 时会关闭对应 Main binding,
不会把确定性失败错误保留为 outcome-unknown。未确认终态的 Prompt 仍不会自动重放;
同一当前 Agent identity 上的 prompt-running binding 会阻止不同的新 operation,直到
原 operation 恢复或取消,避免遗留 Host 工作与新 Prompt 并行。只有 Host/Agent/Runtime
identity 已变化且旧 authority 无法恢复,或原 binding 已有 outcome-unknown 终态时,显式
新 Prompt 才替换旧 binding。新 ACP session 的首次 Prompt 会把 Desktop 已持久化的有界
会话历史作为不可信数据一并发送;成功加载或恢复原 ACP session 时不会重复注入历史。
Linux Runtime 进程直接启动已签名 Runtime 或 Agent model bridge
helper;监督器核对启动后的最终 executable,再登记为运行中进程。
不持久化 T2/T3、consent、approval bridge、confinement 或组件验证结果。数据库 schema
v32 保留项目及关联用户数据,并加入 remote-recoverable Task/message/provenance/cursor;
执行空间表保持 project_id/kind/root_path/ssh_host_id
四列,并删除旧 Runtime 验证表。
Agent 有界诊断
Detached Agent 不依赖 stdio 留存故障证据。每个 installation 在固定私有目录
~/.goodbuddy/state/<installationId>/diagnostics/ 中维护
agent-diagnostics.jsonl、.1 和 .2,每个文件不超过 64 KiB,目录权限为 0700,
文件权限为 0600。记录覆盖 daemon 启停、detached 启动、连接、恢复和 Runtime
启动/退出;每条只包含固定事件、时间、PID、固定原因和白名单错误码。当前写入不含模式;
启动清理在既有日志锁内仅删除已验证 formatVersion 1 的顶层 workMode,保留嵌套内容与损坏行。
诊断写入使用最多 64 条的有界异步队列。连接、恢复和 Runtime 回调只把已经归一化的固定
记录入队,不等待磁盘;原始 Error 不进入队列。队列满、目录不可写或轮转失败只丢弃诊断,
不得改变 Attach、协议、Runtime 或退出结果。daemon 停止和 bootstrap 生命周期结束时执行
有界 flush。多个 Agent 进程通过 GoodBuddy 私有短期锁协调 append 和轮转,不把长期锁作为
运行前提。
已安装 Agent 提供只读固定命令:
goodbuddy-agent diagnostics --installation-id <installationId>
该命令只能从 installation 对应的固定 state 目录读取上述有界文件,并逐行输出已验证 JSONL; 不接受任意路径,也不扩展 Agent protocol。诊断不得包含 accepted Prompt、模型输入输出、 模型密钥、完整配置、环境变量、SSH 参数、用户文件内容、路径或原始错误消息。应用内反馈的 “附加最近桌面诊断记录”只读取 Desktop 诊断,不会自动取得或上传这些远端 Agent 记录。
资源与发布
- 所有桌面构建(包括
portable与release:package)只携带agent-runtime-lock.json、remote-runtime-lock.json与公开的agent-release-keys.json,不嵌入.agent-resources、.remote-runtime-resources或任何可安装 Linux 远端 payload。 build/agent-package.cjs在对应原生 Linux 架构组装确定性.gbagent,外层签名覆盖 描述符和每个内部文件身份;内部 Agent 与 Runtime 仍分别使用既有签名 manifest 和 lock 校验,但所有 production 层统一使用一组 GoodBuddy 通用发布身份并通过签名域区分用途, 不要求内部 Runtime 单独配置密钥。build/agent-catalog.cjs为双架构包生成签名累计目录, 拒绝同一版本/架构改变字节。remote-runtime-launch-contracts.ts中的 OpenCode Runtime lock 版本使用现有componentVersionSchema校验,不再硬编码为1.18.29,避免 Desktop 升级后仅因版本 不同拒绝已有完整签名旧包。包内 manifest、lock 与 descriptor 的版本一致性,以及签名、 哈希和协议兼容性检查仍须通过;构建与发行的 OpenCode pin 保持1.18.29。- Agent lock 的 Node/koffi 版本同样使用
componentVersionSchema,允许完整旧包携带 不同于 Desktop 构建 pin 的依赖版本。验证时仍以包自身 lock 精确核对 manifest 的 Node.js、koffi 和 koffi native 版本;Node24.19.0、koffi3.1.4发行 pin 不变。 .github/workflows/agents.yml只使用进程内临时测试 key 做分支/PR 原生验证,不发布。.github/workflows/agent-release.yml才可在 annotatedagent-v<version>标签和受保护agent-signingEnvironment 中构建 production 包。Agent GitHub Release 必须--latest=false;北京 OSS 先写agent-releases/v<version>/,GitHub 公开后才切换 单一agent-releases/latest.json指针,使客户端始终从同一不可变版本目录读取目录与签名。- Main 的本地缓存只发布完整验证成功的内容。在线目录和包都绑定固定 GitHub/OSS URL、 大小和 SHA-256;选取规则是桌面最低版本满足、Agent protocol major 相同且 minor 不高于 当前支持值的最高 SemVer。缺少某架构仅使该架构 Host 的托管 SSH 无法激活。
agent-release-keys.json读取时按 UTF-8 JSON 解析并严格验证 schema、唯一 key ID、 规范 Base64、有效 Ed25519 key、环境和撤销列表,不把 CRLF/LF 或普通 JSON 空白作为 信任条件。上传到 Host 前重新序列化为确定性 LF JSON。签名目录、描述符、manifest 和 payload 仍按原始签名字节及 SHA-256 验证。
2026-09-20 冗余代码清理验证
- 删除没有生产调用的结构化命令 runner、两个进程身份辅助函数、占位 peer provider、 平台查询辅助函数和五个旧 Runtime 请求构造/摘要辅助函数。保留实际 CLI、进程检查器、 请求 schema、原生 peer 校验及包签名验证,不改变 Ask/Execute 或协议行为。
- 清理后的当前源码 Agent、Main attach transport 和 protocol client 在共享 Linux x64 Host 上通过固定 Host Key 连接,完成启动、状态/能力读取、只读工作区打开及真实文件读取, 断开后再次连接并重复读取。验证没有使用模拟 Agent 或旧安装包的 Agent 实现。
- 本轮测试进程剩余 0;专属 Host 目录、上传文件及本地隔离 profile 已删除。 文本和图片模型请求均为 0 次。这是未使用代码删除后的启动/连接验证,不是新增的 Runtime 模型调用、安装更新或其他架构验收。
- 临时证据为
redundancy-cleanup-host-{build,run}.cjs与redundancy-cleanup-host-live.log;定向回归 230 项通过,typecheck、lint 通过。 - 同期全量
npm test为 4,844 通过、67 跳过、11 失败;失败来自并行修改中的五个 Renderer 帮助提示/焦点测试套件。更新后的五个套件连同更新设置大小展示回归共 64 项 定向复跑全部通过;未把这次复跑记为又一轮全量通过。
生命周期验证(2026-09-23)
通过已有 lifecycle-host harness 重建当前源码的 Agent、daemon 和桌面驱动,使用已保存
凭据与固定 Host Key 经 LAN 连接共享 Linux x64 Host。运行文件均位于独立
/root/tmp/gb-lifecycle-* 目录,Runtime 使用 Host 已安装的 OpenCode。两次 Ask/Execute
运行合计 8 次真实 Provider 请求,另一次空闲更新验证没有模型请求。
- Ask 完成后测试所属子进程为 0;下一轮重建 Runtime、加载同一原生 session,并准确回忆 上轮标记。第二轮完成后子进程再次为 0。
- Execute 启动等待 8 秒后写文件的工具任务,Desktop 断开,再把新安装提升为 current。 旧 daemon 进入 draining,活动进程仍在;重连并恢复原 operation 后正常收尾,旧 daemon 退出,测试所属子进程为 0。
- 空闲更新中,旧 daemon 在提升后 3 秒断言窗口内退出,新 current daemon 仍为 ready。 各次运行清理时所属子进程均为 0,未修改共享安装 registry。
8 个定向套件共 213 项通过,覆盖 CLI 退役安装 stop/retire、daemon 常驻与排空、共享及
独占 Runtime 回收、待答问题仍属活动任务、断线恢复、原生历史加载和 Desktop 冷启动。
远程 UI/IPC 定向复跑 28 项通过,SettingsPanel 完整套件通过;IPC/App 扩展运行共
517 项通过、4 项失败,失败位于并行修改中的
心跳、设置读取次数和监督者导航断言。全量 npm test 运行到 600 秒工具时限仍无最终汇总,
期间报告数据库迁移、监督者和导航测试失败,不能记为全量通过。npm run lint 通过。
类型检查早期通过,最终复跑被并行新增的 tests/incremental-review-live.electron.test.ts:23
中环境变量对象类型错误阻塞。
本次实机覆盖当前源码的 daemon、registry 提升、托管 ACP、真实 Runtime 与模型请求。 未重复完整签名包安装和 UI 更新点击,也未在实机重跑 Continue 或问题答复;这些场景 不能以本次 OpenCode 结果替代。历史发布说明中的技术预览记录保留,当前远程项目设置与 说明文档已去除该标签;Linux 桌面控制等其他预览功能不受影响。
升级残留清理验证(2026-09-24)
本轮在产品源码改动完成后,重新从工作区构建 cleanup CLI 和隔离验证脚本,并在共享
Linux x64 Host 重跑。使用既有 GoodBuddy 加密凭据存储和固定 Host Key;没有输出凭据。
本机临时 harness 位于 C:/Users/jiang/AppData/Local/Temp/opencode/,执行命令为:
node "C:\Users\jiang\AppData\Local\Temp\opencode\upgrade-cleanup-build.cjs"
node "C:\Users\jiang\AppData\Local\Temp\opencode\upgrade-cleanup-run.cjs"
upgrade-cleanup-build.cjs 打包 upgrade-cleanup-cli.ts、upgrade-cleanup-linux.ts
和 upgrade-cleanup-host.ts;run 脚本通过 Electron 启动 host 驱动。Host 驱动读取共享安装
registry 以定位 Node 和 koffi 依赖,仅在 /root/tmp/gb-upgrade-upload-* 上传测试脚本。
远端执行形式如下,其中 <current-id> 来自共享 registry,<upload-root> 是本轮唯一目录:
NODE_PATH='/root/.goodbuddy/agent/installations/<current-id>/lib/node_modules' TMPDIR='<upload-root>' '<installed-node>' '<upload-root>/linux.cjs' '<upload-root>/cli.cjs'
场景在独立 /root/tmp/gb-upgrade-cleanup-* HOME 中生成临时签名测试安装和既有格式的
生命周期、语义、journal、owner 记录,通过该 HOME 的 current 安装执行真实 CLI:
goodbuddy-agent cleanup-obsolete --installation-id current。测试用实际 Node 进程表示
不含退役逻辑的旧 daemon/helper,不是部署历史发布包或运行真实模型任务。
本次构建与远端运行退出码均为 0。远端断言确认:孤儿 Runtime 被回收,所属旧安装 payload
删除;存活 legacy daemon 延期;另一个带 starting 操作记录的进程存活;历史数据库字节
不变;current/candidate payload 保留;第二次调用没有重复删除。运行输出为:
{"passed":true,"productionCli":true,"realOrphanReclaimed":true,"liveLegacyDeferred":true,"activeWorkPreserved":true,"historyPreserved":true,"idempotent":true,"providerCalls":0}
测试结束清除自身进程和隔离目录,没有清理共享用户安装或修改其 registry。早先隔离实测 发生在最终补充两个本地回归用例之前;本节记录的是之后重新构建源码的复跑。此前最终本地 9 个定向套件 99 项通过,typecheck 和改动文件 ESLint 通过。
本次三分钟时限内未找到可直接运行 backend/bridge Vitest 套件的 Linux harness,未安装 额外测试依赖,故这两类 Linux 套件未运行。上述 cleanup 场景不替代这些套件,不证明完整 UI 更新或签名复合包安装流程通过;真实模型调用为 0 次。
发布前完整回归(不能替代开发验证)
以下清单只用于复核开发期间已经在真实 Host 上通过的链路,不得作为 Agent 改动的首次 真实 Host 验证:
npm testnpm run typechecknpm run lint- 发布候选的生产构建由 main 分支 CI 验证;发布前不在本地执行生产构建或打包,详见 发布手册。
- 用测试签名复合包验证在线下载源选择和离线导入/导出;正式 Agent 候选还需公开校验 双架构 production 包与签名目录。
- 在已固定 Host Key 的 Linux x64 测试 Host 上验证 attach-or-bootstrap。
- 在 GoodBuddy 专用测试目录验证无模式请求与能力分配,不保留产品只读名单。
- 验证可以写文件、启动进程和访问网络,同时不触碰无关 Host 文件。
- 运行一次有界的真实模型调用,确认凭据不进入 Renderer、SSH 参数、远端环境或磁盘, 只在当前 accepted operation 生命周期内进入 Agent 内存。
- 中断并恢复 SSH,确认活动 Runtime 不被网络抖动终止。
Prompt 完成与空闲回收验证(2026-09-24)
Runtime 可以先收到完整模型正文并返回 ACP end_turn,随后 helper 才完成 delivery ACK。
RuntimeAcpBackend 的正常完成路径现在要求 broker 等待已接收的 exchange 完成,最多等待
2 秒,再关闭 socket;取消等强制关闭路径不等待这一步。ACK 超时或交付失败仍记录
outcome-unknown,语义 transcript 与 reconciliation 保持一致。
正常完成时,Agent 在串行 control 操作内先持久化语义终态,再将 binding 标为空闲并回收
Runtime。回收失败记录 daemon.stop.failed,reason 为 idle-runtime-cleanup,不把已提交的
completed 改成未知结果。确定性回归覆盖共享与独占 Runtime 的 stop/reconcile 失败,以及
等待 ACK 期间不得提交终态或停止 Runtime。
Desktop 的下一次显式发送会淘汰缓存中的不可用 binding,再通过 cold-open 创建新请求并
传入已有对话历史。OpenCode 和 Continue 的未知终态均有回归;不会重放原来的未知请求。
remoteRecoveryOnly 只允许附加同一活动 operation,已完成或结果未知的缓存不能借恢复
入口发起新请求。缓存仍有活动 operation 时,不同 request ID 的发送被拒绝;普通失败后
已回到 ready 的会话仍可继续使用。
本机模拟范围
agent-owned-acp-prompt.local.test.ts 使用本机已安装的 OpenCode 1.18.29、真实 ACP 和
loopback fake model。测试暂缓 delivery ACK,确认正文 ACK_OK 和 ACP 完成先到达,释放
ACK 后提交 completed,随后注入清理异常并确认终态不变。该用例注入了
completePrompt 回调,没有经过完整 RuntimeAcpBackend 完成路径;backend 的提交顺序、
清理诊断和 reconciliation 由 runtime-acp-backend.test.ts 的独立回归检查。
本轮本机定向复跑 7 个套件,199 项通过、10 项 Unix-only 用例在 Windows 跳过,耗时
5.60 秒。套件为 runtime-acp-backend、agent-owned-acp-prompt、
agent-owned-acp-prompt.local、model-bridge、model-bridge-client、
runtime-composition 和 acp-remote-runtime。本轮没有运行完整测试套件。
最终源码 Linux 场景
源码修正完成后,重新构建临时 lifecycle-host-agent、lifecycle-host-daemon 和
lifecycle-host-driver,通过既有 GoodBuddy 加密凭据存储与固定 Host Key 连接共享
Linux x64 Host。执行命令为:
node "C:\Users\jiang\AppData\Local\Temp\opencode\lifecycle-host-build.cjs" agent daemon driver
node "C:\Users\jiang\AppData\Local\Temp\opencode\lifecycle-host-run.cjs" driver --fake-model --completion-only
测试在独立 /root/tmp/gb-lifecycle-* HOME 启动当前源码的 Agent daemon,通过 Desktop
createManagedRemoteAcpRuntime、SSH attach、Agent protocol、
createProductionRuntimeProtocol 和 RuntimeAcpBackend 运行 Host 上已安装的 OpenCode。
该路径使用真实 Runtime process owner、model bridge、ACP 和语义存储,没有注入 backend
的 completion 回调。测试只替换 daemon 的外部模型 HTTP 响应,返回确定的 SSE 文本。
两轮 Ask 均收到完成事件,每轮结束后测试目录所属的 Runtime/helper 进程数为 0。第二轮 在回收后重新启动 Runtime,保留同一原生 session ID,模型请求中带有第一轮保存的标记。 运行输出的关键记录为:
{"inspected":true,"oldState":"ready","draining":false,"remainingOwnedProcesses":0,"realProviderCalls":0,"fakeModelCalls":1}
{"inspected":true,"oldState":"ready","draining":false,"remainingOwnedProcesses":0,"realProviderCalls":0,"fakeModelCalls":2}
{"currentSourceAsk":true,"runtimeRecreated":true,"nativeHistoryPreserved":true}
{"stopped":true,"realProviderCalls":0,"fakeModelCalls":2,"remainingOwnedProcesses":0}
{"exit":0,"stderrBytes":0}
构建和运行退出码均为 0,fake model exchange 共 2 次,真实 Provider 请求为 0 次。清理 只停止测试 daemon、其 Runtime 进程并删除隔离目录;没有更改共享用户安装或 registry, 没有停止无关 Host 进程。
此次 Linux 场景验证正常完成、空闲回收和下一轮恢复原生历史;没有在 Host 上注入 ACK 延迟或清理失败,也没有覆盖未知终态后的新 binding 场景、Continue、Execute、断线恢复、 完整 UI 操作或签名包安装。故障时序与未知终态的下一次发送以本机定向回归为证据,不能用 这两轮成功请求替代。
目录符号链接验证(2026-10-04)
bounded-directory-sftp.ts 已支持目录链接。该路径由 Desktop Main 的 SSH connection
lease 调用,不经过 Agent daemon 或 Runtime;本次直接构建并运行修改后的 Main SFTP
源码,无需更改 Host 上的 Agent 安装。
聚焦命令 npm test -- src/main/ssh/bounded-directory-sftp.test.ts src/main/ssh/ssh-host-directory-browser.test.ts src/main/ssh/ssh-connection-pool.test.ts
通过 3 个文件、40 项测试,覆盖目录目标筛选、条目路径、扫描及返回上限,以及等待
stat 时取消、超时、通道错误、迟到回调和清理。npm run lint 通过。
最终 npm run typecheck 通过;IPC 聚焦测试
npx vitest run src/main/ipc.test.ts -t "requires a directory through project creation IPC"
通过 1 项,172 项未选中。
全量 npm test 在 120 秒后由执行器终止,结束前报告 Magic Notes storage 启动读取
耗时测试失败;本轮没有全量通过结论。
真实共享 Linux Host 验证复用 GoodBuddy safeStorage 凭据和固定 Host Key。LAN
192.168.0.23 未建立连接,VPN 10.7.0.23 成功。测试在独立
/root/tmp/gb-directory-links-* 目录创建普通目录、相对及绝对目录链接、链式链接、
文件链接、断链和循环链接,通过生产 lease.listDirectories 验证可见项与原始条目
路径,再进入三类目录链接确认返回目标的规范路径及子目录。取消一次真实浏览后,
同一 lease 再次浏览成功。测试目录已删除,模型调用 0 次。
临时探测脚本为 C:\Users\jiang\AppData\Local\Temp\opencode\directory-symlink-host.ts,
运行命令为 node "C:\Users\jiang\AppData\Local\Temp\opencode\directory-symlink-host-run.cjs",
退出码 0。Host 场景未注入目标权限错误或 stat 超时,这些失败分支由聚焦回归覆盖;
本次验证范围不含 Renderer 操作和项目创建验证。