Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ members = [
"src/crates/assembly/external-sources",
"src/crates/adapters/ai-adapters",
"src/crates/adapters/opencode-adapter",
"src/crates/adapters/claude-code-adapter",
"src/crates/adapters/codex-adapter",
"src/crates/adapters/static-hook-support",
"src/crates/adapters/webdriver",
"src/crates/adapters/transport",
"src/crates/services/services-core",
Expand Down
52 changes: 49 additions & 3 deletions docs/architecture/extensions/external-ai-work-sources-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ prompt-only Command。第二条纵向切片已让受支持的单文件 OpenCode
已把 OpenCode 用户/项目 MCP 的 local stdio 与 HTTPS remote 安全子集接入现有 MCP owner,沿用显式审批、冲突、
工作区隔离和失败回推;现有 Skill Registry 另行展示来源、用户/项目作用域和固定优先级产生的覆盖结果,不并入上述
可执行来源选择规则。完整
TypeScript/Bun、包依赖、package plugin、Codex/Claude Code 适配器、primary agent 替换和外部 Subagent 续接仍属于
后续阶段,不能因来源被识别就宣称已经可用。
TypeScript/Bun、包依赖、package plugin 执行、Codex/Claude Code 运行时适配、primary agent 替换和外部 Subagent
续接仍属于后续阶段,不能因来源被识别就宣称已经可用。OpenCode、Claude Code 与 Codex 的本地 Hook 静态目录
已作为独立只读切片接入;它只证明来源和声明能够安全展示,不证明 handler 已加载、获得权限或可以执行。

## 1. 产品判断与竞品启示

Expand Down Expand Up @@ -98,7 +99,7 @@ TypeScript/Bun、包依赖、package plugin、Codex/Claude Code 适配器、prim
| 信息 | 产品要求 |
|---|---|
| 来源 | 产品、规范化位置、用户全局/项目/工作区作用域、实际执行域;Agent 普通视图只接收 `<workspace>/…`、`~/.config/…` 或 `<remote>/…` 等安全标签,不传绝对用户路径。 |
| 内容 | 配置、Rules、Agents、Skills、Commands、MCP、插件、工具等类别与数量。 |
| 内容 | 配置、Rules、Agents、Skills、Commands、MCP、Hooks、插件、工具等类别与数量。 |
| 状态 | 已发现、已应用、可用、需确认、更新中、沿用上一版本、部分受限、暂时过期、已移除/已停用或不可用。 |
| 变化 | 最近成功读取时间、候选摘要、已应用摘要、权限或能力变化。 |
| 操作 | 查看详情、应用/启用、按项目或执行域抑制/恢复兼容来源、进入/退出 Safe Mode、停用执行 target、撤销显式导入、重新加载、低风险/代码更新改为先询问、显式导入为 BitFun 配置。 |
Expand All @@ -123,6 +124,39 @@ GUI 和 TUI 都通过同一个 `SetSafeMode` 动作请求该变化,Peer Host
显式导入完成后,已选字段由 BitFun 原生配置拥有,不再同时叠加外部值;未导入内容仍可继续作为兼容来源。
插件、Tool 和 Hook 不通过配置复制获得执行资格。

### 3.4 静态 Hook 目录

Hook 首先以独立、只读的 `ExternalHookCatalogSnapshotV1` 展示,而不进入可执行来源控制面。Desktop 设置页的
“外部 AI 应用 → Hooks”和交互式 TUI 的 `/hooks` 消费同一份 Rust 快照;`/help hooks`、`/hooks -h` 与 `/hooks --help` 提供说明,不增加快捷键、
命名空间变体或生态专用命令。`/hooks` 与其他内置命令采用同一套既有冲突策略:无冲突时使用普通命令名;发生
同名冲突时由现有命令菜单展示来源限定项,静态 Hook 目录不增加另一套保留字或路由规则。

当前目录的来源与降级边界如下:

| 生态 | 当前静态来源 | 当前可见事实 | 明确不做 |
|---|---|---|---|
| OpenCode | 用户、legacy、项目祖先 `.opencode` 与显式配置目录中的 `plugin/`、`plugins/`;相同层级的 JSON/JSONC `plugin` 声明 | 以稳定、确定的 adapter 顺序展示每个具名导出的静态对象属性、未知属性和动态注册提示;相同事件在不同具名导出中保留独立注册身份;软件包声明只显示“已声明、未解析”;显式配置目录保持原生的末级优先顺序 | 不安装依赖、不解析软件包导出、不 import JS/TS、不执行 handler;类型声明 `.d.ts` 不作为运行时插件源;不把项目根下任意 `plugin(s)/` 当成 OpenCode 目录。 |
| Claude Code | 用户 `~/.claude/settings.json`,以及从项目根到当前工作区的 `.claude/settings.json`、`.claude/settings.local.json` | Hook 事件、matcher、`command/http/mcp_tool/prompt/agent` handler 类型;先合并已观察设置层,再把有效 `disableAllHooks=true` 投影为 disabled | 不复制 managed Hook 例外或运行时信任判断;任一参与层无效或超限时不猜测有效激活状态;不传输 command、prompt、URL、server/tool 参数或其他 handler 正文。 |
| Codex | 用户与按持久 `project_root_markers` 有界的项目祖先 `hooks.json`、`config.toml`;linked worktree 的 `hooks.json` 和 `config.toml` 中整个 `[hooks]` 表均映射到主 checkout 对应目录 | 展示固定 schema 中的 Hook 事件与 command handler;非原生 prompt/agent 声明只标为 unsupported;User state/feature 仍可能被未观察的 SessionFlags 覆盖,项目声明还受 trust 约束,因此 command handler 的有效激活统一保持 unknown | 不把 Claude Code 的 matcher 或全局禁用字段套用到 Codex;不猜测插件、托管层、会话注入、state/feature 合并或 trust-gated 项目激活来源,这些未观察来源以覆盖诊断明确显示。 |

只有语义完全一致的 `PreToolUse`/`PostToolUse` 和 OpenCode `tool.execute.before`/`tool.execute.after` 分别映射到
BitFun 已有 `ToolBefore`/`ToolAfter` 契约。其他原生事件仍可见,但标为 `native_only`;静态分析不能安全确定的注册
标为 `opaque`,不得猜测映射。目录 DTO 只包含 provider 身份与稳定 adapter 顺序、来源、作用域、脱敏位置、matcher 摘要、
handler 类型、原生激活状态、覆盖投影状态和固定诊断,不包含 handler body、命令、prompt、URL、环境变量、凭据
或任意执行 payload。`content_version` 仅指纹化这些已脱敏语义事实,原始文件字节和敏感正文不进入版本值。

发现按文件、目录项、软件包声明、handler 和总目录条目设置硬上限;单个文件或 provider 失败只产生 Hook 资产诊断,
健康 provider 仍然发布。刷新失败时协调器保留该 provider 的最后有效静态结果并显式标记 stale;首次失败使用独立
provider 失败事实,避免在空目录界面中伪装成“成功但没有来源”,错误正文仍只保留在共享诊断中。Desktop 和 TUI
只按需刷新,并复用已有类型化 Discovery Lane 的 provider 级合并、超时和延后结果机制,不建立第二套 watcher、
任务调度器或状态机。同一工作区有发现仍在运行时,后续 Desktop/TUI 刷新只读取共享 pending 快照,不再排队第二代
发现;超时后的终态在既有 refresh gate 内原子完成、发布。Desktop 轮询同一缓存快照直至 pending 结束,TUI 在单次
命令内等待该快照收敛。GUI 对每个 provider 的来源、条目、诊断以及目录级诊断分别使用共享分页预算,TUI 对来源、
条目和诊断设置输出上限,避免大型目录一次挂载或打印数千项。Git/worktree 服务只提供当前 checkout 边界与主 checkout 身份;adapter
在最多 32 层的边界内解释各生态祖先规则,无法确认 Git 边界时只读取当前工作区,不向任意父目录扩散。当前只允许
本机执行域:Remote workspace 和 Peer Device Mode 显示明确不支持,绝不
回退读取控制端本地同名配置。Server、Mobile、SDK、ACP、Host 和任何 Hook Runtime 都不属于该切片。

## 4. 来源、资产与加载策略

### 4.1 来源身份与作用域
Expand Down Expand Up @@ -247,6 +281,7 @@ flowchart LR
| 外部来源目录 | 聚合来源身份、作用域、资产清单、用户处理偏好和可读状态 | 解释所有生态格式、保存凭据、授予脚本权限或管理 worker。 |
| 生态发现与解析适配器 | 发现本生态标准来源,保留真实优先级、格式、参数展开和诊断,并通过能力专属 provider 输出 | 写 BitFun 配置、依赖兄弟生态 adapter、执行其他生态语义或创建跨生态最低公分母。 |
| 能力专属 provider 契约 | 用来源限定身份交付 Command、Tool、Subagent 等类型化定义与调用/展开结果 | 携带任意 payload 的通用资产对象,或让一种能力的新增字段污染其他能力。 |
| 静态 Hook provider 与目录协调器 | 通过 runtime-free 契约聚合 OpenCode、Claude Code、Codex 的脱敏声明;隔离 provider 失败、保留最后有效结果并向 Desktop/TUI 投影 | import handler、选择脚本运行时、授予执行权限、复用可执行来源审批 DTO,或把静态映射宣称为运行时兼容。 |
| 文件观察服务 | 提供可订阅、去抖的文件变化事实 | 解释生态路径、决定优先级、提交业务状态。 |
| 本地 JSON 存储服务 | 提供跨进程锁、锁内读改写和严格同卷原子替换等通用文件能力;替换失败时保留旧文件 | 定义外部来源偏好 schema、冲突策略或生态语义。 |
| 共享生命周期协调器 | 由单一 `ExternalSourceControlPlane` 持有 Command、Tool、Subagent、MCP 四个 typed coordinator 和四条 discovery lane;按 provider 复用唯一 in-flight 请求、隔离超时和失败、以 generation fencing 拒绝迟到结果,再请求能力 owner 切换 | 按生态 ID 分支业务行为、把四类 payload 合并为通用资产、解析生态文件、直接提交配置、工具、权限或界面状态。 |
Expand Down Expand Up @@ -386,6 +421,17 @@ Command;明确缺失且未被标记失败的 Command 是稳定删除。产品
上下文的外部 runtime id;外部服务器发起的 roots、sampling 和 elicitation 请求也 fail-closed,防止跨工作区读取或借用
BitFun 宿主能力。后续若接入这些能力,必须先补独立契约、工作区路由与权限交互,不能复用全局连接绕过当前边界。

独立的静态 Hook 目录切片不依赖上述运行时阶段:

1. `product-domains` 只定义 runtime-free DTO 和 capability-specific provider port;三个生态 adapter 各自解释来源,
`assembly/external-sources` 负责 provider 聚合与 last-valid,`assembly/core` 只负责本地产品装配、Git/worktree 边界
解析,以及在既有 refresh gate 内按工作区串行完成发现与发布。
2. Desktop/Web UI 与交互式 TUI 只消费共享快照;无 Server、Remote、Peer、Mobile、SDK 或运行时投影。
3. 验收覆盖脱敏序列化、部分失败、首次失败与空目录区分、非法/过大输入、有界枚举、provider 身份冲突、刷新竞态、stale 结果、保留命令、
`/help hooks`、GUI 空/错/刷新/不支持状态,以及 Host 返回未知 v1 枚举或可执行字段时 fail closed。
4. 后续覆盖率、版本差异和冲突分析在此目录之上增加只读派生事实;Hook 执行 Host、权限、顺序、取消与故障恢复必须
另立运行时切片,不能通过扩展本目录 DTO 偷渡执行语义。

验收至少覆盖:

- 项目打开和无关会话不会因发现、解析、依赖准备或确认等待被阻塞。
Expand Down
34 changes: 20 additions & 14 deletions docs/architecture/extensions/opencode-extension-compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,23 +147,29 @@ OpenCode,和 OpenCode 配置/插件进入 BitFun 是两个独立验收方向

### 3.3 稳定服务 Hook

本节的“实现”指进入真实 OpenCode 插件运行时。BitFun 当前按插件声明与具名导出顺序,从本地插件文件静态展示
下列 Hook 属性,并把 `tool.execute.before/after` 投影到已有 Tool Hook 点;未知或动态注册保持 `opaque`。映射仅表示
BitFun 已识别等价契约覆盖,不表示外部 handler 已加载、激活或执行。目录不会 import 或执行插件,内容版本也只
指纹化脱敏后的目录事实,因此不改变任何 Hook Runtime 的“未实现”结论。`tool` 是工具注册能力,不作为 Hook
事件猜测或投影。

| Hook | BitFun 差异 | 当前状态 | 目标可实现性 | 成熟度依赖(非执行顺序) | BitFun 需要完成的工作 |
|---|---|---|---|---|---|
| `dispose` | 直接桥接 | 未实现 | 可完整适配 | OC-R3 | 调用清理并设置期限;超时回收 worker。 |
| `event` | 补扩展接口 | 未实现 | 可完整适配 | OC-R3 | 提供版本化事件代理并隔离插件异常。 |
| `config` | 补扩展接口 + 融合现有能力 | 未实现 | 可完整适配 | OC-R3 | 按插件顺序变换,最后由 Config 归属模块校验提交。 |
| `dispose` | 直接桥接 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 调用清理并设置期限;超时回收 worker。 |
| `event` | 补扩展接口 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 提供版本化事件代理并隔离插件异常。 |
| `config` | 补扩展接口 + 融合现有能力 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 按插件顺序变换,最后由 Config 归属模块校验提交。 |
| `tool` | 补基础能力 + 补扩展接口 | 未实现 | 可完整适配 | OC-R2 | 注册真实工具定义与执行函数。 |
| `auth` | 补扩展接口 | 未实现 | 可主要适配 | OC-R3 | 提供 API/OAuth 方法和脱敏凭据代理。 |
| `provider` | 补扩展接口 + 融合现有能力 | 未实现 | 可主要适配 | OC-R3 | 将动态模型列表接入 Provider 归属模块。 |
| `chat.message` | 补扩展接口 | 未实现 | 可完整适配 | OC-R3 | 依次变换消息和 parts,变换后重做结构校验。 |
| `chat.params` | 补扩展接口 + 融合现有能力 | 未实现 | 可完整适配 | OC-R3 | 依次变换模型参数,显式产品上限最后生效。 |
| `chat.headers` | 补扩展接口 | 未实现 | 可完整适配 | OC-R3 | 依次变换请求头,敏感值不进入日志。 |
| `permission.ask` | 融合现有能力 | 未实现 | 可主要适配 | OC-R3 | 默认保留 allow/deny/ask 语义;用户或组织策略可收紧。 |
| `command.execute.before` | 补扩展接口 | 未实现 | 可完整适配 | OC-R3 | 在命令执行前依次变换消息 parts。 |
| `tool.execute.before` | 补扩展接口 | 未实现 | 可完整适配 | OC-R3 | 变换最终参数,随后重做 schema 和权限判断。 |
| `shell.env` | 补扩展接口 | 未实现 | 可完整适配 | OC-R3 | 在实际执行域构造环境变量。 |
| `tool.execute.after` | 补扩展接口 | 未实现 | 可完整适配 | OC-R3 | 依次变换 title、output、metadata,保留原始结果引用。 |
| `tool.definition` | 补扩展接口 + 融合现有能力 | 未实现 | 可完整适配 | OC-R3 | 变换模型可见 JSON Schema;真实执行继续使用 worker 中原始 Zod 校验,保持 OpenCode 双表示语义。 |
| `auth` | 补扩展接口 | 静态目录可见,运行未实现 | 可主要适配 | OC-R3 | 提供 API/OAuth 方法和脱敏凭据代理。 |
| `provider` | 补扩展接口 + 融合现有能力 | 静态目录可见,运行未实现 | 可主要适配 | OC-R3 | 将动态模型列表接入 Provider 归属模块。 |
| `chat.message` | 补扩展接口 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 依次变换消息和 parts,变换后重做结构校验。 |
| `chat.params` | 补扩展接口 + 融合现有能力 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 依次变换模型参数,显式产品上限最后生效。 |
| `chat.headers` | 补扩展接口 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 依次变换请求头,敏感值不进入日志。 |
| `permission.ask` | 融合现有能力 | 静态目录可见,运行未实现 | 可主要适配 | OC-R3 | 默认保留 allow/deny/ask 语义;用户或组织策略可收紧。 |
| `command.execute.before` | 补扩展接口 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 在命令执行前依次变换消息 parts。 |
| `tool.execute.before` | 补扩展接口 | 静态映射可见,运行未实现 | 可完整适配 | OC-R3 | 变换最终参数,随后重做 schema 和权限判断。 |
| `shell.env` | 补扩展接口 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 在实际执行域构造环境变量。 |
| `tool.execute.after` | 补扩展接口 | 静态映射可见,运行未实现 | 可完整适配 | OC-R3 | 依次变换 title、output、metadata,保留原始结果引用。 |
| `tool.definition` | 补扩展接口 + 融合现有能力 | 静态目录可见,运行未实现 | 可完整适配 | OC-R3 | 变换模型可见 JSON Schema;真实执行继续使用 worker 中原始 Zod 校验,保持 OpenCode 双表示语义。 |

Hook 的共同风险是把变换误做成通知、并行调用破坏顺序或插件写入非法状态。所有 Hook 都走类型化调用、顺序执行和归属模块终检;具体调用协议见[服务插件运行时设计](opencode-plugin-runtime-adapter-design.md#6-钩子适配与权威提交)。

Expand Down
Loading