Skip to content

feat(extensions): integrate OpenCode plugin hooks runtime - #2518

Open
JohnLee1243 wants to merge 2 commits into
GCWing:1.0.0-explorefrom
JohnLee1243:lzh/hooks-1.0.0-explore
Open

feat(extensions): integrate OpenCode plugin hooks runtime#2518
JohnLee1243 wants to merge 2 commits into
GCWing:1.0.0-explorefrom
JohnLee1243:lzh/hooks-1.0.0-explore

Conversation

@JohnLee1243

Copy link
Copy Markdown

Integrate the managed OpenCode Plugin Host with BitFun's hook and agent runtime across CLI, desktop, and app-server surfaces.

  • add framed Plugin Host RPC, lifecycle supervision, and tool invocation
  • add the shared HookRegistry/AgentHookEngine path for native and plugin hooks
  • project plugin Config Hook agents, permissions, tools, and skills into the existing BitFun registries with workspace and generation isolation
  • preserve external agent routing, model binding, steering, and session compatibility across runtime surfaces
  • update protocol schemas, examples, and focused integration contracts

Summary

Integrates OpenCode plugin hooks end to end through the managed Plugin Host.

The change connects Plugin Host lifecycle management, framed RPC, hook dispatch, Config Hook projection, and plugin Tool execution across the shared Rust runtime, CLI, desktop, and app-server surfaces. Plugin-provided Agents, permissions, Tools, and Skills are registered through the existing BitFun owners and remain isolated by workspace and plugin generation.

Type and Areas

Type:

Feature

Areas:

Rust core, Agent Runtime, CLI/TUI, desktop/Tauri, app-server, OpenCode adapter, Plugin Host, plugin RPC, Agent/Tool/Permission/Skill registries, integration tests

Motivation / Impact

BitFun previously had native command hooks and built-in hooks, but no complete runtime path for executing OpenCode plugin hooks.

This change enables:

  • Managed Plugin Host startup and lifecycle supervision.
  • Framed RPC between BitFun and the Plugin Host.
  • Execution of plugin function, tool, and config hooks.
  • Registration of plugin-provided Agents and Tools through existing BitFun registries.
  • Config-based Agent fields including mode, description, prompt, permission, hidden, and temperature.
  • Plugin Tool and Skill isolation by workspace, plugin owner, Agent, and generation.
  • Agent selection and execution through CLI, desktop, and app-server surfaces.
  • Preservation of native hook behavior and existing Agent/session compatibility.

Verification

  • cargo check -p bitfun-core --no-default-features --features opencode-plugin-host
    • Passed.
  • CARGO_TARGET_DIR=target/cherry-pick-check cargo check -p bitfun-cli
    • Passed.
  • cargo test -p bitfun-core --no-default-features --features opencode-plugin-host --lib plugin_config_projection::tests::maps_target_agent_fields_and_plugin_tool_permissions
    • Passed.
  • cargo test -p bitfun-core --no-default-features --features opencode-plugin-host --lib plugin_config_projection::tests::parses_hidden_and_temperature_with_safe_defaults_and_bounds
    • Passed.
  • git diff --check
    • Passed.
  • Full workspace test suite and interactive CLI/manual verification were not run.

Reviewer Notes

  • Plugin Host protocol and process lifecycle remain owned by the OpenCode adapter/service boundary.
  • Hook dispatch uses the shared HookRegistry and AgentHookEngine; native, built-in, and plugin hooks retain distinct source and trust semantics.
  • Plugin Config projections are generation-scoped and replaced atomically.
  • A plugin Agent with the same logical ID can temporarily replace the local Agent route and is restored when the plugin generation is removed.
  • Plugin Tools are only exposed to the owning plugin Agent and do not implicitly expand native Agents.
  • hidden controls presentation visibility while preserving explicit runtime routing.
  • temperature is applied to a per-turn AI client clone and does not mutate the shared model client cache.
  • Existing untracked workspace files were not included in this change.
  • Rollback can be performed by reverting this commit; no user data migration is required.

Checklist

  • This PR is focused and does not include secrets, temporary prompts, generated scratch files, or unrelated artifacts.
  • Relevant verification is recorded above, or skipped checks are explained.
  • User-facing strings, docs, and locales are updated where applicable.

Integrate the managed OpenCode Plugin Host with BitFun's hook and agent
runtime across CLI, desktop, and app-server surfaces.

- add framed Plugin Host RPC, lifecycle supervision, and tool invocation
- add the shared HookRegistry/AgentHookEngine path for native and plugin hooks
- project plugin Config Hook agents, permissions, tools, and skills into the
  existing BitFun registries with workspace and generation isolation
- preserve external agent routing, model binding, steering, and session
  compatibility across runtime surfaces
- update protocol schemas, examples, and focused integration contracts
@JohnLee1243
JohnLee1243 force-pushed the lzh/hooks-1.0.0-explore branch from 09afe6d to 8c33404 Compare August 26, 2026 06:59

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

结论:Request Changes。本次复审基于精确 head 8c3340483c859f190366d5b5ac351056d7e7a589。下面只保留了本 PR 引入、能够稳定复现或从生产调用链闭合证明的合并阻断问题。

1. CLI 启用可执行 Plugin Host 前缺少来源授权

问题: src/apps/cli/src/main.rs:54-55 将策略从 Disabled 改为 Enabled,而 plugin_host_activation.rs:38-49 只检查 GlobalConfig.plugin 是否非空。随后 workspace ensure 会直接 prepare/open/import 插件,没有查询 External Source Control Plane 的来源审批、内容版本、执行域、safe mode 或组织策略。

风险: 用户已有的 OpenCode 插件配置会在 BitFun 升级后直接获得当前用户权限下的 Bun 代码执行能力。用户在 OpenCode 中配置插件,不能自动等同于批准它在 BitFun 的执行域和权限范围中运行。

建议: 在 prepare/import 前接入现有执行授权 owner。批准键至少绑定来源限定身份、插件身份、内容摘要、入口类型、workspace/execution domain 和权限摘要;未批准、摘要变化或 safe mode 下必须 fail closed。

2. 最小 feature 和标准测试目标无法编译

问题: agent-runtime/src/native_hooks/mod.rs:19-42 无条件编译并导出执行模块,破坏 native-hook-settingsnative-hook-runtime 的依赖闭包。同时,测试仍引用已删除 API、缺失测试文件和旧 Registry 构造方式。

已稳定复现:

  • pnpm run check:core-boundaries 失败;
  • native-hook-settings check 失败 42 个错误;
  • native-hook-runtime check 失败 23 个错误;
  • Agent interaction、SDK smoke、Agent Runtime lib tests、Plugin Host tests 均在编译阶段失败。

风险: 轻量 consumer 无法按声明的 feature 使用 crate,CI 也无法编译现有回归目标;完整 feature union 的成功编译掩盖了这些问题。

建议: 恢复 settings/runtime 模块和 export 的 feature gate,让依赖跟随真实 owner feature;完整迁移测试调用方,保留启动超时、process reaping、generation fencing、SDK 注册和 session route 回归。

3. 新执行路径绕过既有 Plugin Runtime owner

问题: assembly/core/src/agentic/tools/plugin_host_tool.rsplugin_hook_bridge.rs 直接持有 PluginHostClient、generation lease、RPC route、取消和 wire Value,Tool 在 plugin_host_tool.rs:205 直接调用 Host。与此同时,portable agent-runtimenative_hooks/kind.rs:12-40 内置 OpenCodePlugin 和原始字符串 Hook,并在通用 Registry 中维护 OpenCode 专属代际状态。

风险: 形成第二套插件执行与生命周期状态机,既有 PluginRuntimeClient 的串行化、幂等结果、响应校验和故障状态无法覆盖这条生产路径。以后增加其他插件生态还需要继续修改 portable runtime 并复制 mux、lease 和取消逻辑。

建议: OpenCode wire DTO、Host client 和 lease 留在 adapter;通过既有 PluginRuntimeClient 扩展最小类型化 Tool/Hook 调用,或提供同等窄且生态中立的 owner port。Assembly 只选择 provider、发布类型化贡献并保存不透明绑定。

4. generation 更新、撤销和并发 ensure 无法可靠收敛

问题: plugin_host.rs:311-333 的实例键只包含目录和全局插件声明摘要,workspace 配置内容没有进入 desired generation。插件列表变化时,代码先打开新实例,发布后才退休旧实例;extension-host/src/host.ts:249-255 又禁止同一目录存在两个实例。同 workspace 的 absence check 与 opening insert 也不在一个临界区,失败清理没有 instance-id CAS。

风险: workspace 中 Agent、permission、Skill 等配置变化可能继续复用旧结果;[A,B] -> [A] 会因 directory_exists 失败而让旧插件继续运行;并发 mode/session bootstrap 还可能覆盖 opening state,留下没有生命周期 owner 的 Hook/Tool generation。

建议: desired generation 纳入 workspace 配置摘要、插件内容摘要和有效授权摘要;对 (workspace, generation) 使用 single-flight,插入、发布和删除都做 instance-id CAS。更新时停止旧调用、排空/取消、确认旧 Host 进程树退出,再加载当前批准图并原子发布。

5. Host 崩溃和撤销失败后仍会保留失效状态

问题: plugin_host.rs:154-163 只要全局 slot 为 Some 就返回 AlreadyStarted,生产代码没有使用 adapter 已提供的 is_connected()。workspace withdraw 又忽略 close_instance 失败并删除实例跟踪;插件 dispose() 没有期限。

风险: Bun OOM、process.exit、协议损坏或 disposer 挂起后,Hook/Tool/Agent 仍显示 Ready,代码或后台任务可能继续存在,而 Rust 已失去可恢复句柄。权限撤销和更新会表现为 fail-open。

建议: 由唯一生命周期 owner 监听 child exit/peer close。失联或 close 超时时原子撤下共享贡献、标记有副作用调用为 OutcomeUnknown、保留故障状态直至完整进程树退出,并按有界进程级预算重启和重载批准图。

6. tool.execute.before/after 没有进入生产 ToolPipeline

问题: assembly/core/src/native_hooks.rs:84:131 新增的两个 dispatch helper 全仓只有定义,没有生产调用。实际插件工具在 plugin_host_tool.rs:205 直接进入 execute_tool。完整 Core check 通过时,编译器也明确报告 before/after helper、after output 和 generation lookup 均未使用。

风险: Host 和 Registry 会显示 Hook 已注册/Ready,但参数修改、阻断和结果变换从不执行,PR 声明的 operational Hook 端到端能力实际未交付。

建议: 在唯一 Tool 执行 owner 中接入 before/after,使 builtin、MCP 和插件工具遵循相同时序。before 之后重新做 schema、权限和副作用校验;after 在结果提交给模型前执行并重新校验。增加真实 Extension Host + ToolPipeline 的端到端测试。

7. 启动和 Tool deadline 没有形成确定的停止语义

问题: opencode-plugin-host/src/lib.rs:250-254 的 startup timeout 只包住 listener.accept(),连接后的完整握手没有 deadline。Tool 的 120 秒 RPC timeout 又只删除 Rust pending request;只有用户 cancellation token 分支才发送 host.tool.cancel

风险: 子进程连接后不发送首帧可以永久卡住 CLI 初始化;Tool 调用者收到失败并重试时,第一次执行仍可能继续写文件、发网络请求或启动进程,造成重复且结果未知的副作用。

建议: 使用一个总 startup deadline 覆盖 accept、完整首帧读取、校验和应答,失败时 terminate/wait/reap。Tool request 增加 deadline/drop cancellation guard;超时发送 generation-fenced cancel 并有界确认,无法确认停止时 fault Host,并返回 OutcomeUnknown,禁止自动重放。

验证说明

  • cargo check -p bitfun-core --no-default-features --features opencode-plugin-host 通过,但产生的 unused warning直接印证 operational Hook 未接线;
  • git diff --check 通过;
  • 当前 PR 没有 GitHub Checks;
  • 本地缺少 Bun,因此 TypeScript Host 测试未运行,这部分仍是验证缺口。

- enforce external-source authorization before CLI plugin execution\n- restore feature-gated native hook consumers and unify plugin runtime invocation ownership\n- fence plugin generations, lifecycle cleanup, startup handshakes, and tool cancellation\n- fix CLI external policy boolean parsing and keep OpenCode plugin resources recoverable\n\nThe tool.execute.before/after pipeline integration remains intentionally deferred.

@limityan limityan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

结论:Request Changes。本次复审基于精确 HEAD e73587bca8b2ada74030960bf6c2bf38f45180a5,重点核对上一轮 7 组阻断问题在修复提交后的真实状态。startup deadline 和部分 feature 闭包已经修复,但 7 组问题均未整体关闭,当前分支还存在可复现的编译、行为测试和架构门禁失败。

1. AskBeforeUse 仍会直接执行第三方插件

问题: plugin_host.rs:332-354AutoAskBeforeUse 都视为允许执行;OpenCode 工具默认正是 AskBeforeUse。CLI 初始化又会在正式授权前执行 prepare_plugins,经 Bun loader 触发 bun add、网络访问和缓存写入。

风险: 产品显示“调用时需要确认”,实际没有确认记录就会安装、导入并执行第三方代码。当前授权也没有绑定 plugin identity、内容 digest、workspace/execution domain、权限摘要或依赖图。

建议: AskBeforeUse 必须保持 pending,直到获得持久化的激活决定。授权应绑定 canonical source、插件身份、完整 prepared digest、workspace/execution domain、权限摘要及 policy revision;package 解析、安装和 import 全部放在授权之后,safe mode 在 prewarm 前 fail closed。

2. 新 InvocationPort 仍绕过 PluginRuntimeClient,并破坏错误语义

问题: runtime-ports/src/plugin.rs:65-117 新增的端口暴露原始 serde_json::Value 和 Host instance/generation 信息。Core 在 plugin_host.rs:618-626 仍以裸 PluginHostClient 创建 invoker,随后直接进入 Host RPC,整条生产链没有经过既有 PluginRuntimeClient

风险: 既有 owner 的串行化、幂等缓存、disposed domain、诊断和 quarantine 无法覆盖新链路。adapter 已识别出的 OutcomeUnknown 又在 plugin_host_tool.rs:247-251 被统一转换为可重试的 Service 错误;配置 max_retries > 0 时,结果未知的副作用调用可能被重复执行。

建议: 由 execution 层的 PluginRuntimeClient 或同层可靠性 owner 承担调用;OpenCode adapter 只负责 Host binding。保留类型化错误映射,OutcomeUnknown 必须终止自动重试。Assembly 只接收不透明 binding,不保存和逐字段转发 lease。

3. generation 切换没有证明旧代码已经停止

问题: 新代码增加了 fingerprint、workspace lock 和 close-before-open,但 extension-host/src/host.ts:896-915 在 abort 后立即清空 active tools,没有等待各执行的 done。忽略 AbortSignal 的旧工具可在新 generation 发布后继续运行。loader 仍使用相同模块 URL,进程内 reopen 会复用模块缓存;当前 content hash 也只覆盖入口和 package.json,没有覆盖真实依赖图。

风险: 更新或撤销返回成功后,旧代码仍可能继续产生文件、网络或进程副作用,新旧 generation 可以并发运行。

建议: close 时冻结新调用,取消并有界 drain 全部活动执行;无法确认停止时由生命周期 owner 终止并等待整个 Host 进程树,确认停止前禁止发布新 generation。generation digest 应覆盖解析后的完整可执行依赖图。

4. ensure、撤销和进程丢失没有统一生命周期 fencing

问题: ensure 在取得 workspace lock 前读取全局配置和执行策略;withdraw 没有取得同一把锁;policy 更新不会主动撤销运行中的实例。health monitor 断连后只撤销 contributions,没有接管、终止或重启 Host。实例缓存复用也没有检查 ready 和当前 Host connection generation。

风险: 旧 ensure 可以覆盖较新的更新或撤销;Host 重建后可能复用仅存在于旧连接里的 lease;断连、OOM 或 close 失败后,缓存与真实 Host 状态长期不一致。

建议: ensure、withdraw、policy revoke 共用同一 workspace 生命周期临界区,并在 import、原子 publish 前重新比较 authority revision。实例绑定 Host connection generation,仅允许复用 ready && host_generation == current_connected_generation 的记录;连接丢失时 fence 全部旧实例并完成进程级恢复或进入明确 paused 状态。

5. tool.execute.before/after 仍未进入生产 ToolPipeline

问题: assembly/core/src/native_hooks.rs 只新增了 before/after helper,全仓没有生产调用点。实际路径仍是 ToolPipeline::execute_with_retry -> tool.call() -> plugin mux -> invoke_tool。现有测试直接调用 Hook engine,只证明 Registry 行为,不能证明 ToolPipeline 接线。Hook 错误和超时还会被降为 warning 后继续原操作。

风险: Host 和 Registry 显示 Hook Ready,但参数修改、阻断和结果变换不会作用于真实工具调用;失败时还可能静默放行原始副作用。

建议: 在唯一 ToolPipeline owner 接入 before/after。before 在最终 schema、permission intent 和副作用校验前运行;after 在模型可见结果提交前运行并保留原始审计结果。Hook 超时或失败应终止当前操作,不得静默放行或重放底层工具。补充真实 Extension Host → ToolPipeline 端到端测试。

6. Tool deadline/cancel 仍不能保证停止

问题: startup 的 accept、完整 handshake deadline 和失败子进程清理已经修复。但 Tool timeout 或显式 cancellation 无法确认 cancel 时只关闭 RPC client,没有终止 Host 进程树;调用侧丢弃 execute future 后也缺少 cancellation-safe guard。

风险: 调用方收到失败或取消后,插件仍可能继续文件、网络或进程副作用;结合错误降级和 retry,会产生重复执行。

建议: cancel 无法在 deadline 内确认时,将当前 connection generation 标为 faulted,撤销实例并由进程 owner 终止、等待进程树;保留 OutcomeUnknown 到产品错误层并禁止自动重试,同时为 pending request 增加 drop-safe 清理。

7. 当前 HEAD 仍未通过必要门禁

已复现:

  • cargo test -p bitfun-opencode-plugin-host:27 passed / 1 failed。tests.rs:216 期望超大 frame 请求被钳制到 64 MiB,lib.rs:553-557 实际先限制为 16 MiB;
  • Agent Runtime --lib --tests --no-run:5 处初始化未补新增的 agent_route_key
  • agent_session_contracts --no-run:测试仍使用旧 RuntimeHookPlan API;
  • pnpm run check:core-boundaries:13 条源码违规,包括 raw JSON plugin ABI、公共符号未预算、native-hook feature owner coverage 不完整,以及未经审核的 opencode-plugin-host -> runtime-ports 依赖边。

两个最小 native-hook feature check、bitfun-core --features opencode-plugin-hostgit diff --check 通过。当前环境缺少 Bun,Extension Host 的 Bun 测试未运行。

此外,PR 描述声称已端到端覆盖 CLI、Desktop 和 app-server,但权威架构文档仍声明 package plugin execution 尚未形成生产闭环,Desktop launch policy 也仍为 Disabled。请同步收敛 PR 范围和说明,或补齐生产 owner、生命周期、验证与文档契约后再合入。

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.

2 participants