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
2 changes: 1 addition & 1 deletion docs/architecture/plugin-runtime-host-design.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ sequenceDiagram
- 主机不得伪造权限通过、工具成功、审计成功或产品状态变更。
- `HostRestarted` 是 P0-B 唯一隔离清除条件;用户可执行清除、重试、重新审核和打开日志等动作必须在具有归属接口、审计事实和真实消费方后再暴露。
- `restart(project_domain_id, workspace_id)` 是内部清理路径,用于清除对应执行域的隔离、诊断只读视图和幂等缓存。
- 后续显式停用或清理残留激活记录时,必须按项目、工作区、包和可选激活代次定位记录;包已缺失或损坏时不能要求重新读取包内容。清理激活状态不等于删除来源审核历史
- 显式停用按项目、工作区和包清除激活记录,内部回滚同时校验激活代次。停用记录先写入信任文件,再通过受限发现判断包是否可用;发现同 ID 的不同来源时,使旧来源审核记录失效。包缺失、损坏或扫描不完整时仍可停用,并保留无法安全协调的来源审核历史。后续发现问题作为诊断返回,持久化结果不确定时返回错误;重复操作和旧代次请求不改变状态

## 7. 目录与来源原则

Expand Down
5 changes: 3 additions & 2 deletions docs/architecture/product-architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,14 @@ flowchart LR
| 随产品携带包 | 未建立独立扫描根 | 由构建配置、安装器和产品组装提供来源后接入同一校验接口 |
| OpenCode 兼容内容 | 包清单可声明 `opencode_compatible`;来源模块重新校验并固定声明文件,适配器只解释该输入 | 外部目录需经独立导入流程转换为受管包 |
| 来源审核 | 工作区 `SourceApproved`、`Denied`、`Revoked`;内容变化使旧审核与激活失效 | 组织策略、签名和撤销列表 |
| 激活 | 预览后按精确内容哈希确认;激活代次与来源审核代次独立;停用或内容变化立即使既有 Binding 失效 | GUI/Web 管理入口、组织策略,以及包缺失或损坏后的显式记录清理体验 |
| 激活 | 预览后按精确内容哈希确认;激活代次与来源审核代次独立;停用或内容变化立即使既有 Binding 失效;CLI 可清理缺失或损坏包的残留激活记录 | GUI/Web 管理入口和组织策略 |
| 插件运行 | 只通过 Host 读取 custom tool 候选;候选始终需要权限;不执行 JS/TS,不注册最终工具 | 先建立受限执行单元和真实工具提供方,再接入工具快照与权限裁决;执行能力不可用时只返回诊断 |

OpenCode 适配接入规则:

- OpenCode 适配器的公开入口只接收来源服务重新校验并固定的受管包输入,不直接扫描工作区或用户 OpenCode 目录。
- 来源服务只为当前 `SourceApproved` 的包生成固定内容输入。每条激活记录保存自己的签发代次;激活授权信息只包含项目、工作区、精确来源和该代次,包内容不在授权信息中重复保存,其他包的状态变化不会使当前授权失效。
- 来源服务只为当前 `SourceApproved` 的包生成固定内容输入。每条激活记录保存自己的签发代次;激活授权信息只包含项目、工作区、精确来源和该代次,包内容不在授权信息中重复保存,其他包的状态变化不会使当前授权失效。包暂时缺失或损坏时保留来源审核记录;发现同 ID 的不同来源后,旧审核与激活失效。
- 停用按项目、工作区和包清除激活记录,内部回滚同时校验激活代次。停用记录先写入信任文件,再通过受限发现判断包是否可用;发现同 ID 的不同来源时,使旧来源审核记录失效。包缺失、损坏或扫描不完整时仍可停用,并保留无法安全协调的来源审核历史。后续发现问题作为诊断返回,持久化结果不确定时返回错误;实际清除推进一次激活代次,重复操作和旧代次请求不改变状态。
- 固定内容输入只保证结构、大小和哈希自洽,不作为审核凭据。生产组装必须从来源服务取得输入;即使其他进程内调用方构造了有效输入,适配器仍只能返回未激活状态。
- Host 来源 URI 使用来源模块生成的路径摘要区分用户级包、项目级包和后续其他来源,不暴露原始本地路径。
- 普通包输入只能产生来源与诊断视图。只有产品组装点持有来源服务生成的当前激活授权信息时,适配器才将受支持 custom tool 映射为权限候选。
Expand Down
1 change: 1 addition & 0 deletions docs/plans/core-decomposition-completed.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
- 产品组装已承接 `DeliveryProfile`、当前交付形态入口矩阵、`CapabilitySet`、feature group matrix、profile-scoped capability plan、product-full provider plan、service availability report、profile-scoped harness registry 入口与 legacy-route 行为保护,以及 `ProductAssembler` 对 explicit profile input、runtime services、harness registry 和 service requirement 的验证;core 只保留兼容 re-export。ProductFull / Desktop / CLI / ACP 保留完整能力;Server / Remote / Web / MobileWeb 不再 materialize product-full capability packs、feature groups、runtime services、tool groups 或 harness routes。
- 插件运行时边界基础已建立:`runtime-ports` 持有 `PluginRuntimeClient`、binding、availability、dispatch / response envelope、disabled stub 和 projection-only stub;产品组装输出扩展可用性事实与插件运行时绑定,并通过 Agent Runtime 内部 builder 注入该 binding;Agent Runtime SDK 门面不导出插件运行时主机 ABI。默认产品启动不运行 JS/TS、工作进程或子进程。
- OpenCode-compatible P0-C.1/P0-C.2 已建立受管包发现、完整性校验、工作区来源审核、精确内容哈希激活、CLI 管理与诊断,以及按需创建 OpenCode 适配器、插件运行时主机和 `PluginRuntimeBinding` 的唯一生产组装点。当前组装只返回需要权限的 custom tool 静态候选,不注册工具或执行插件代码。
- 插件停用已支持按工作区和包清理缺失或损坏包的残留激活记录;停用状态在扫描前提交,后续受限发现负责结果分类,并在稳定发现同 ID 不同来源时协调旧审核记录。包暂时缺失或损坏时保留来源审核记录,重复操作和旧激活代次请求保持幂等,持久化结果不确定时不报告成功。
- LSP plugin runtime target 和命令占位符解析已从 `services-core` 收口到 `core-types`;`services-core` 保留兼容 re-export、registry、current-target detection 和 filesystem / runtime service 逻辑。

- Agent session/workspace owner routing 已继续收敛:`AgentRuntime` 提供 port-backed session workspace resolution entrypoint;Cron、SessionControl、SessionMessage 和 SessionHistory 不再在工具实现中直接解析目标 session workspace,Cron 保留 target session 可见性验证,workspace identity 中的 `workspace_id` / remote connection / remote host 通过 runtime contract 传递。
Expand Down
18 changes: 4 additions & 14 deletions docs/plans/core-decomposition-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@
- `runtime-ports` 的插件主机 ABI 已有公开接口预算脚本;后续不能绕过预算新增插件、hook、event、UI 或生态兼容对象。
- `opencode-adapter` 当前解释固定内容的受管包,提供诊断只读视图和 custom tool 候选映射;来源发现归 `services-integrations/plugin_source`。
- `services-integrations/plugin_source` 提供受管包发现、完整性校验、来源审核、激活持久化和实时凭证复核;`bitfun-core/plugin_runtime` 是唯一 OpenCode 生产组装点。
- CLI 已能预览、按精确内容哈希激活和停用包。激活路径只通过 Plugin Runtime Host 返回需要权限的 custom tool 候选,不执行 JS/TS,也不依赖外部 OpenCode CLI。
- CLI 已能预览、按精确内容哈希激活和停用包,并可在包缺失或损坏后清理残留激活记录。激活路径只通过 Plugin Runtime Host 返回需要权限的 custom tool 候选,不执行 JS/TS,也不依赖外部 OpenCode CLI。

## 3. 当前差距

| 差距 | 影响 | 收敛要求 |
|---|---|---|
| 激活记录依赖当前包内容清理 | 包缺失或损坏后,普通停用路径无法读取目标来源,可能留下用户无法清理的激活记录 | 增加按工作区、包和可选激活代次清理记录的产品操作;清理不依赖重新读取包内容,也不删除来源审核历史 |
| 激活写入在跨进程锁内执行稳定性复核 | 操作受统一期限约束,慢文件系统可能延长同一工作区的授权检查等待,但当前没有等待时间基线 | 先增加锁等待与慢文件系统测试;只有数据证明存在问题时再调整锁范围,同时保持来源、优先级、内容摘要和审核代次在提交点一致 |
| custom tool 只有静态候选,没有执行实现 | 候选不能形成可调用工具;直接注册会向模型暴露无法执行的伪工具 | 先完成一种明确制品的受限执行单元和真实工具提供方,再复用现有工具 ABI、权限与陈旧快照保护;执行不可用时只返回诊断 |
| 运行时插件没有安装和卸载流程 | 用户只能手工放置包,无法形成完整的动态插件体验 | 安装、卸载和状态清理作为独立产品流程;安装不自动审核或激活,也不复制外部生态凭据和配置批准 |
Expand All @@ -46,21 +45,12 @@
| 插件运行时主机 | `availability`、`read_plugins`、`dispatch`,以及期限、代次、幂等、隔离、诊断和重启清理 |
| P0-C.1 | 受管包发现、完整性校验、工作区来源审核、CLI 管理和诊断 |
| P0-C.2 | 精确内容哈希激活、生产组装、OpenCode custom tool 静态候选和权限提示 |
| 停用恢复 | 按工作区和包清理缺失或损坏包的残留激活记录;保留来源审核历史并提供幂等、代次和持久化保护 |

上述基线不包含插件代码执行、工具注册、安装卸载、产品内置来源或外部 OpenCode 目录导入。详细完成事实归档在 [`core-decomposition-completed.md`](core-decomposition-completed.md)。

## 5. 后续 PR 顺序与范围

### PR1:残留激活记录清理

范围:

- 包缺失或损坏时,按工作区、包和可选激活代次清理残留激活记录;不要求重新读取包内容。
- CLI 停用和诊断明确区分“包已停用”“残留记录已清理”和“持久化结果不确定”。
- 只增加上述流程真实消费的最小操作,不增加通用注册中心、管理器或新的插件状态模型。

完成条件:缺失、损坏、旧激活代次、重复清理和持久化失败均有测试;失败时不误报停用成功,不删除来源审核历史。

### PR2:首个可执行 custom tool

范围:
Expand Down Expand Up @@ -99,13 +89,13 @@

完成条件:先确认目标用户和一个实际 CLI 任务,再验证构建产物中的真实内置扩展可完成该任务;Manifest 摘要、签名凭据和产品策略均通过校验。缺失、摘要或签名不匹配、同 ID 冲突和运行期隔离均产生可观察降级,且不会读取用户插件审核或激活状态。演示工具不能作为阶段完成依据。

以上四个 PR 均不包含在线插件仓库、隐式 npm 安装、原始 OpenCode 目录批量导入、可写钩子、GUI/TUI 通用界面接口、Server/Remote 执行或 Codex/Claude 插件运行时。这些能力必须在出现独立产品场景和真实消费方后重新排期。
以上三个后续 PR 均不包含在线插件仓库、隐式 npm 安装、原始 OpenCode 目录批量导入、可写钩子、GUI/TUI 通用界面接口、Server/Remote 执行或 Codex/Claude 插件运行时。这些能力必须在出现独立产品场景和真实消费方后重新排期。

代码合入不等于产品能力已经发布。只有执行路径与对应来源路径都形成完整闭环后,产品入口才能显示“可用插件”;仅完成候选、安装或内置来源时,入口必须保持候选预览或 `projection-only`,并明确显示执行能力不可用。

## 6. 待确认决策

PR1 不依赖以下决策。技术依赖为:PR3 依赖 PR1 的残留记录清理,并在作为可用插件体验发布前依赖 PR2;PR4 依赖 PR2 以及独立交付的 Customization-C0/C2 最小前置能力,PR3 不是其前置。开始 PR2 前必须确认执行载体、主机调用入口和首个真实工具场景。
残留激活记录清理已完成,不依赖以下决策。技术依赖为:PR3 在作为可用插件体验发布前依赖 PR2;PR4 依赖 PR2 以及独立交付的 Customization-C0/C2 最小前置能力,PR3 不是其前置。开始 PR2 前必须确认执行载体、主机调用入口和首个真实工具场景。

| 决策 | 方案 | 主要影响 | 建议 |
|---|---|---|---|
Expand Down
4 changes: 2 additions & 2 deletions scripts/core-boundaries/rules/source/forbidden-rules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const forbiddenContentRules = [
patterns: [
{
regex:
/\bpub\s+(?:async\s+)?fn\s+(?!(?:new|refresh|set_trust|load_package|set_activation|load_activated_package|has_activation_authority)\b)[A-Za-z_][A-Za-z0-9_]*\b/,
/\bpub\s+(?:async\s+)?fn\s+(?!(?:new|refresh|set_trust|load_package|activate|deactivate|load_activated_package|has_activation_authority)\b)[A-Za-z_][A-Za-z0-9_]*\b/,
message:
'unexpected public ManagedPluginSourceService method; update the reviewed method budget before exposing more API',
},
Expand All @@ -45,7 +45,7 @@ export const forbiddenContentRules = [
patterns: [
{
regex:
/\bpub\s+(?:const\s+)?fn\s+(?!(?:parse_json|validate|content_hash|new|into_parts|epoch|activation_epoch|trust_level_for|apply_decision|reconcile_sources|is_activated|activation_authority|is_activation_current|set_activation)\b)[A-Za-z_][A-Za-z0-9_]*\b/,
/\bpub\s+(?:const\s+)?fn\s+(?!(?:parse_json|validate|content_hash|new|into_parts|epoch|activation_epoch|activation_sources|trust_level_for|apply_decision|reconcile_sources|is_activated|activation_authority|is_activation_current|activate|clear_activation_record)\b)[A-Za-z_][A-Za-z0-9_]*\b/,
message:
'unexpected public plugin source contract method; update the reviewed method budget before exposing more API',
},
Expand Down
6 changes: 4 additions & 2 deletions scripts/core-boundaries/rules/source/public-api-rules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,10 @@ export const managedPluginSourcePublicApiEntries = [
export const managedPluginActivationPublicApiEntries = [
'ManagedPluginCandidateView',
'ManagedPluginActivationView',
'ManagedPluginDeactivationResult',
'preview_managed_plugin_activation',
'set_managed_plugin_activation',
'activate_managed_plugin',
'deactivate_managed_plugin',
].map((symbol) =>
pluginSourceEntry(
symbol,
Expand Down Expand Up @@ -308,7 +310,7 @@ export const publicApiAllowlistRules = [
{
path: 'src/crates/assembly/core/src/plugin_runtime.rs',
reason:
'core managed plugin activation API must stay limited to product status projection and one state transition',
'core managed plugin activation API must stay limited to product status projection and explicit activation or deactivation transitions',
allowedSymbolEntries: managedPluginActivationPublicApiEntries,
},
];
4 changes: 2 additions & 2 deletions scripts/core-boundaries/self-test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -980,9 +980,9 @@ export function runManifestParserSelfTest({
(managedPluginActivationPublicApiRule?.allowedSymbolEntries || [])
.map((entry) => entry.symbol)
.join(',') !==
'ManagedPluginCandidateView,ManagedPluginActivationView,preview_managed_plugin_activation,set_managed_plugin_activation'
'ManagedPluginCandidateView,ManagedPluginActivationView,ManagedPluginDeactivationResult,preview_managed_plugin_activation,activate_managed_plugin,deactivate_managed_plugin'
) {
throw new Error('managed plugin activation API budget must stay limited to four product-facing symbols');
throw new Error('managed plugin activation API budget must stay limited to six product-facing symbols');
}
const appHostAbiRule = forbiddenContentUnderRules.find((rule) => rule.path === 'src/apps');
if (!appHostAbiRule) {
Expand Down
Loading
Loading