Finch

Finch 扩展系统设计

Finch 扩展系统设计

状态:随 Finch 演进 定位:Finch 小工具(mini tools / extensions)系统的正式设计文档。回答三个问题:是什么、为什么这样设计、往哪走。 读者:小工具作者、Finch 开发者、以及对扩展系统设计感兴趣的外部读者。 事实标注:代码路径 + 行号指向本仓库当前实现;论文引用指向《A Programming Paradigm for Spatiotemporal Composability》(北大 & DeepSeek-AI,2026-08-13 草案,github.com/cordiverse/paper)。


1. 愿景与设计原则

1.1 愿景

Finch 是一个桌面 Agent 客户端。Agent 的能力来自工具、记忆、自动化与外部服务的组合,而这些能力不可能也不应该全部由宿主内置——模型在演进、服务在增多、每个人的工作流不同。因此 Finch 把"扩展"当作一等公民:任何能力都可以由一个小工具提供,小工具与内置能力走同一条执行管线。

对比参照:DeepSeek Harness 的口号是 "Everything is a Plugin"(github.com/deepseek-ai/deepseek-harness),其底层框架 Cordis 的设计理念与 Finch 的扩展系统有大量共鸣(见第 4 章)。区别在于 Finch 的扩展系统是在桌面应用场景里独立演化出来的,形态更贴近"应用插件",而 Cordis 是通用"动态组合元框架"。

1.2 四条设计原则

  1. 进程隔离优先。每个小工具运行在独立的宿主子进程中,不共享进程、不信任对方的内存。小工具崩溃不应影响宿主或其他小工具;恶意或有缺陷的代码被限制在自身进程内。
  2. 声明优于执行。小工具能静态声明的东西尽量静态声明:id、版本、最低 Finch 版本、权限、能力提供/依赖、贡献点(工具/按钮/设置项/会话容器)。声明是安装时审查与运行时门控的共同基础。
  3. 生命周期纪律。小工具的每个注册动作返回一个可清理的句柄(Disposable),停用时宿主统一回收。作者无需理解清理顺序,宿主按登记逆序执行。
  4. 可恢复性。破坏性操作优先选择可逆路径:卸载进废纸篓而不是直接删除、更新保留回滚可能、禁用不丢数据。

2. 核心抽象

2.1 清单(Manifest)

一个小工具是一个 npm 风格包目录,携带 package.json#finch 或独立 finch.json 清单(src/main/services/extension/scanner.ts)。清单声明:

  • 身份id(npm 包名派生,见 3.7)、name(支持本地化)、version
  • 兼容性manifestVersion(当前支持 = 1,scanner.ts:28)、minVersion(低于当前 Finch 版本则拒绝加载)
  • 权限permissions.filesystem / network / shell / secrets / oauth / sessions / sessionInteractionssrc/shared/types.ts:55
  • 能力provides.capabilities / requires.capabilities(跨扩展依赖的静态声明)
  • 贡献点contributes):toolscomposerActions(Composer 工具栏按钮)、settingsMenuiconPacks/iconsskills(随包携带技能)、mcpServers(注入官方 MCP bridge 的服务器)、sessionContainers(会话容器)、agentProfiles(角色提示词)
  • 设置项settings 声明式 schema,宿主原生渲染编辑表单,值存入扩展私有数据目录

2.2 运行模型

┌────────────────────────── Electron Main Process ─────────────────────────┐
│  ExtensionService                                                         │
│   ├─ scanner(扫描 global + personal 两级目录)                            │
│   ├─ CapabilityBroker(跨进程能力路由)                                    │
│   ├─ runner(工具注册/调度/权限管线)                                      │
│   └─ 每个小工具对应一个 ActiveExtension 记录(disposers / toolDisposers)  │
└──────────────┬──────────────────────────────────────────┬────────────────┘
        fork 子进程                                    fork 子进程
┌──────────────▼──────────────────┐      ┌──────────────▼──────────────────┐
│  ExtensionHost(小工具 A)        │      │  ExtensionHost(小工具 B)        │
│  - 执行 activate(ctx)/deactivate│      │  - 执行 activate(ctx)/deactivate│
│  - ctx 能力面(tools/storage/…) │      │  - ctx 能力面                   │
│  - IPC 与主进程通信(hostProtocol)│     │  - IPC 与主进程通信             │
└──────────────────────────────────┘      └─────────────────────────────────┘
  • 每个小工具独占一个宿主进程fork(hostPath, { env: { ELECTRON_RUN_AS_NODE: "1" } })src/main/services/extension/hostClient.ts:186)。
  • 宿主与主进程通过结构化消息协议通信(hostProtocol.ts);能力调用跨进程时经主进程的 CapabilityBroker 路由(capabilities.ts)。

2.3 能力面 API(ctx)

小工具在 activate(ctx) 中获得一个 MiniToolContext(类型契约见 packages/minitool-api/finch.d.ts,零运行时依赖):

能力说明
ctx.tools.register(def)注册 Agent 工具(与一方工具同管线,autoAllow: false
ctx.composerActions.register(id, provider)Composer 工具栏按钮:badge / menu / execute
ctx.capabilities.provide/get/has跨扩展能力提供与获取(见 2.4)
ctx.storage / ctx.settings / ctx.secrets私有 KV 存储 / 声明式设置读写 / 系统加密密钥
ctx.oauth隔离的 OAuth 连接与授权(provider 需 manifest 白名单)
ctx.sessions / ctx.session会话创建与当前会话上下文(只读)
ctx.uiToast / 确认框 / 表单 / 浮动 Canvas 窗口(桌宠等)
ctx.i18n / ctx.logger / ctx.app / ctx.workspace国际化、带前缀日志、App 信息、工作区信息
ctx.eventsAgent 事件、会话状态、通知订阅
ctx.subscriptionsDisposable 登记数组,停用时宿主自动 dispose(见 3.3)

2.4 依赖路由:CapabilityBroker

小工具之间通过具名 capability 协作(capabilities.ts):

consumer host ──capabilityInvoke──▶ main (broker) ──invokeCapability──▶ provider host
  • provide(name, impl):注册一个能力对象(一组异步方法),须与 manifest provides.capabilities 一致(hostProcess.ts:820);
  • get<T>(name):取得能力对象,须与 manifest requires.capabilities 一致(hostProcess.ts:844);
  • has(name):跨宿主同步查询(主进程广播可用能力列表);
  • provider 停用时 unregister 自动清空,并广播刷新所有宿主的 has() 视图。

每个宿主进程持有跨宿主能力视图availableCapabilities),激活时播种、变化时刷新,保证 has() 可同步作答。


3. 关键设计决策

这一章是本文档的核心:每一条决策都讲"为什么这么做"。

3.1 为什么每扩展一个进程

决策:每个小工具独占一个 fork 子进程(ELECTRON_RUN_AS_NODE),而非 VSCode 式的共享"扩展宿主"进程。

理由

  1. 崩溃隔离:小工具内存错误、死循环、内存泄漏不拖垮宿主和其他小工具(宿主只需处理子进程 exit 事件并标记 crashed,hostClient.ts:197-216)。
  2. 卸载即终止:停用小工具 = 优雅 deactivate + 终止进程,进程内残留(定时器、连接、全局状态)随进程消亡,不需要逐项排查泄漏——这是"进程即垃圾回收器"。
  3. 沙箱边界:论文《时空可组合性》§6.3 明确指出:语言级访问控制拦不住恶意代码,沙箱必须外部化(SFI / 独立运行时 / 进程 / 容器)。进程隔离是其中最轻量的工程选项;Finch 已具备,权限裁决的强化是路线图(第 7 章)。
  4. 升级安全:宿主进程绝不在自己的内存空间里执行第三方代码。

代价:每扩展一个 OS 进程,重载成本高(fork + 重新 activate + 重新注册工具),内存占用随扩展数线性增长。桌面单用户场景下可接受;也因此我们选择"进程内模块级重载"作为未来的 HMR 方向(第 7 章),而不是给每个扩展再细分。

3.2 为什么声明式权限 + 少量运行时强制

决策:manifest 静态声明权限;运行时只对可白名单化的 API 强制执行(ctx.oauth provider 白名单 hostProcess.ts:775ctx.secrets key 白名单、capability provide/get 与 manifest 一致性 hostProcess.ts:820-864);filesystem/network/shell 权限目前是信任信号(安装时审查展示),而非执行期拦截。

理由

  1. 桌面场景的信任模型:Finch 是用户在场的桌面应用,安装小工具本身就是一个信任决策;工具调用层面还有权限卡兜底(见 5.2)。声明式权限的短期价值是"可审查、可追溯、可展示",而不是"可执行"。
  2. 诚实:在 Node 子进程里对 fs/net 做执行期拦截,要么包一层薄 API(作者可用 require('fs') 绕过),要么上 seccomp/utilityProcess sandbox——都是大工程。与其假装有强制,不如明确声明边界,把真实强制列入路线图(P1-6)。
  3. 论文印证:论文 §6.3 承认"语言级访问控制不足,需要外部机制"——进程边界已有,进程内裁决是下一步。

3.3 为什么 Disposable 登记制(而不是自动追踪)

决策:小工具把需要清理的资源 push 进 ctx.subscriptions(或直接使用各注册 API 返回的 Disposable);宿主在 deactivate 时统一 dispose(packages/minitool-api/finch.d.ts;主进程侧 record.disposersservice.ts:1063 起)。

理由

  1. 简单且可审计:作者看得见自己在清理什么;宿主停用逻辑只是一遍 dispose(),不依赖对第三方代码的静态分析或魔法代理。
  2. 作者可控:有些资源生命周期长于 activate(如全局单例、跨会话连接),作者可以选择不登记或自行管理。
  3. 诚实承认边界:自动追踪(论文"revertible effects"——每个上下文变换携带逆函数、运行时 LIFO 恢复,§3.1)更强大,但要求"一切状态变更都经过 ctx",这是对 API 形态的重塑,不是增量改动。

代价与路线图:漏登记即泄漏(进程终止可兜底,但运行期内仍可能累积)。P0-1(第 7 章)计划在宿主内部状态(storage/settings/secrets)上先做"写时快照 + 停用回滚",把"作者自觉"升级为"宿主兜底"。

3.4 为什么幂等 reconcile + 按 id 独立重启

决策reload()幂等 reconcile——只停"不再 enabled 或已从磁盘消失"的扩展、激活新 enabled 的扩展,已运行的扩展保持运行(service.ts:672-680);restartActive(ids?) 支持按 id 单扩展重启service.ts:1248),IPC extensions:reload(ids?) 透传(src/main/ipc/extensions/index.ts:58)。

理由

  1. 最小影响:改一个小工具的配置/代码,只影响它自己;宿主和其他小工具的运行状态(会话、连接、缓存)不受扰动。这与论文 §5.2.2 的"stale entries 最小集合"精神一致。
  2. 声明式目标状态enabled 集合就是"期望状态",reload() 只是把现实收敛到期望——幂等、可重复、失败可重试。这比指令式"先停 A 再起 B"更不容易出错。
  3. 代价:每次重启仍是"停旧→起新"裸切换:无备份、activate 失败不回滚、子进程内存状态丢失。事务化是 P0-3(第 7 章)。

3.5 为什么安装直下 tarball、不跑安装脚本

决策:CLI(packages/minitools/bin/minitools.mjs)从 npm registry 直接下载 dist.tarball 解压安装,不经 npm install第三方安装脚本永远不会执行(minitools.mjs 头注释)。

理由:npm 包安装脚本(preinstall/postinstall)是供应链攻击的经典载体。小工具是"要装进宿主生态的可执行代码",其安装过程本身必须是确定、可审计的。直下 tarball 同时带来:无依赖树(不装第三方依赖,小工具自包含)、快速、可缓存(cache/minitools/)。

3.6 为什么默认禁用 + 信任状态持久化

决策:发现小工具 ≠ 启用小工具。安装后默认 disabled,用户显式 enable 后其工具才会注册(src/main/services/extension/state.ts 头注释:"discovery alone never registers an extension's tools")。信任状态(enabled / grantedPermissions / autoUpdate)持久化在 extensions.json

理由

  1. 安装与授权分离:把"下载了文件"与"赋予了能力"分成两个动作,符合最小权限直觉;也避免了"装了个包就默默生效"的惊吓。
  2. 可审计enabled 集合 + 权限授予时间戳(grantedAt)构成可回溯的信任记录。
  3. 对比:多数插件市场"安装即启用",Finch 选择多一步显式授权,代价是用户多一次点击,收益是心智模型清晰。

3.7 为什么用 npm 包名派生 id

决策:新安装小工具的 id = sanitizeExtensionId(packageName)(scoped 包如 @finchtoys/mcp-clientfinchtoys@mcp-client),安装时写入 .finch-id sentinel(scanner.ts:35 与 minitools.mjs 保持字面同步)。

理由:npm 保证包名全局唯一;而作者自由声明的 finch.id 是自由文本,两个社区扩展可能撞同一个短 id。用包名派生 id 使"身份唯一性"从约定变成结构事实,且不可被无关包伪造(npm 只允许 @ 出现在 scope 首位)。旧安装通过 sentinel 缺失保留旧解析方式,零迁移(idMigration.ts)。

3.8 为什么卸载进废纸篓、数据目录保留

决策uninstall() = deactivate → 清信任记录 → shell.trashItem(OS 废纸篓,可恢复)→ reload(service.ts:1599);extension-data/<id>/paths.ts:113不随卸载删除

理由:破坏性操作优先可逆(原则 4)。废纸篓让"误卸载"可恢复;数据目录保留让"重装即恢复"成为可能。代价是隐私残留——完全卸载选项列入路线图(P1-5)。

3.9 为什么无 project 级作用域

决策:小工具只装到 personal / global 两级,没有 <cwd>/.finch/extensions/ 项目级(CLI 对 --cwd 显式拒绝;scanner.ts 注释)。

理由:小工具是"用户级能力",绑定的是用户身份而不是某个目录;项目级能力由 Skills 承担(Skills 支持 project tier,走独立的 @finchtoys/skills CLI)。两套系统刻意分工:小工具 = 可执行代码能力,Skills = 提示词/流程资产。避免一个包同时出现在两级目录造成版本混乱。


4. 与「时空可组合性」论文的对照

论文《A Programming Paradigm for Spatiotemporal Composability》(北大 & DeepSeek-AI,2026-08-13 草案)把动态组合的两个正交维度形式化:时间可组合性(卸载时完全撤销组件副作用)与空间可组合性(依赖出现/消失/替换时自动调整),并给出两个核心机制:可逆效应(revertible effects,每个上下文变换携带运行时追踪的逆函数)与响应式共效应(reactive coeffects,上下文变化按组件依赖规范通知并驱动启停)。实现为元框架 Cordis,DeepSeek Harness 基于它构建。

本节不是学术评审,而是用论文作为一面镜子,检验 Finch 的设计直觉在形式化框架下的位置——哪些已经站住了、哪些只是骨架。

4.1 概念对照

论文概念(出处)Finch 对应物对应程度差距
可逆效应(§3.1)ctx.subscriptions + Disposable;主进程 record.disposers◐ 手工版逆函数由作者手写,未登记即泄漏;无执行期自动捕获
响应式共效应(§3.2.2)CapabilityBroker + broadcastAvailableCapabilities✗ 查询版只更新 has() 视图;消费者不被通知、不自动停用/重载
统一上下文 Γ∞(§3.3.1)每扩展一个 ctx 能力面(finch.d.ts)◐ 能力面ctx 是"能力集合"而非"可恢复状态容器";无父子上下文树
组件 = (d, p, e)(§4.1 Def 43)manifest requires/provides + activate(ctx)◐ 同构声明p 的强制仅限 capabilities API,普通副作用写入无 p 约束
fiber 状态机 + 惯性过渡(§4.3 Alg 5)enable/disable + restartActive(ids?) 独立重启✗ 无状态机无 LOADING/UNLOADING 中间态、无"卸载先等依赖者"、无 target 概念
声明式配置调和(§5.2.1 Def 74)manifest + extensions.json;reload() 幂等 reconcile◐ 目标状态无 entry 字段级 diff(id/url/isolate/intercept/config/disabled 最小化操作)
HMR 事务重载(§5.2.2 Alg 8-10)restartActive 裸切换,无备份无回滚✗ 缺activate 失败即功能缺失;无开发期文件 watch
系统边界与补偿(§6.1)shell.trashItem 卸载(service.ts:1599)◐ 补偿实例运行期副作用无边界/补偿模型
沙箱(§6.3)fork 子进程隔离(hostClient.ts:186)◐ 进程级语言级强制薄弱(见第 5 章)
interception 能力衰减(§6.3 Def 30-31)✗ 缺无法"给社区扩展只读 DB"这类运行时衰减
service broker / 多提供者(§6.2)CapabilityBroker 单 provider(后注册覆盖)✗ 缺换 provider 会扰动消费者;无负载均衡/滚动更新模式

4.2 三个本质分岔

分岔一:副作用追踪是"登记式"还是"捕获式"(时间维)。 Finch 的清理等价于"每个注册动作返回清理函数,作者记得 push 进 subscriptions"。论文的清理等价于"任何通过 ctx 的状态变更自动登记逆函数,卸载时按 LIFO 自动恢复"(§3.1,ctx.effect 是唯一变更通道,Alg 1)。差异后果:Finch 中扩展若绕过 ctx 改共享状态,deactivate 不感知;论文中卸载语义是结构性保证而非作者纪律(§5.3:"even an inexperienced author obtains ordered cleanup…without writing an uninstall path")。

分岔二:依赖管理是"主动查"还是"被通知"(空间维)。 Finch 的 capability 消费者激活时查 has(),provider 消失后只能等下次调用报错;论文的 notify → refresh 让上下文每次变化都按依赖规范分类,provider 进入 UNLOADING 的瞬间依赖者就开始 teardown,且 unload 会等待依赖者到达 INACTIVE(§5.1.3 Alg 5)——"依赖先于卸载被撤走"的顺序纪律。Finch 缺这整条链路。

分岔三:更新是"事务"还是"裸切换"(维护维)。 论文 HMR 三阶段(分类/检测/事务回滚)保证系统永不进入半重载状态。Finch 的重启粒度已经不错(按 id 独立、幂等 reconcile),但每次重启仍是"停旧→起新"裸切换:无备份、activate 失败不回滚。

4.3 结论

Finch 的扩展理念在"插件宿主"层面已经达到甚至超过论文所批评的行业基准(VSCode 式共宿主、无法热卸载、依赖机制形同虚设):进程隔离、逐扩展启停、Disposable 纪律、声明式依赖骨架。论文的价值在于把这些工程直觉形式化并自动化。差距不在理念,在"保证"——Finch 目前靠作者纪律和进程兜底,论文把它变成"不做就不会错"。第 7 章路线图即按此方向收敛。


5. 安全模型

5.1 分层信任

机制状态
安装层manifest 权限审查(filesystem/network/shell/secrets/oauth/sessions)展示 + 持久化(grantedPermissions
执行层进程隔离(fork 子进程)强制
API 层oauth provider 白名单(hostProcess.ts:775)、secrets key 白名单、capability 与 manifest 一致性(hostProcess.ts:820-864)强制
工具调用层扩展工具与一方工具同管线,autoAllow: falserunner/extension-tools.ts强制
数据层ctx.secrets 走 Electron safeStorage 加密,明文回退被显式拒绝(secretStore.ts强制

5.2 工具调用权限

扩展工具经 extensionToolToRegistration 进入 Finch 内部工具注册表,与一方工具走完全相同的调度/权限管线:模型调用工具时按用户设置的权限模式裁决(默认模式逐次确认;acceptCalls 模式下普通扩展工具放行、高风险工具仍要求确认)。来源(provenance)通过 ToolSource 与规范化名 extension:<id>.<name> 携带,权限与 UI 分组都跟随来源。

5.3 已知薄弱点与边界

  1. fs/network/shell 权限未执行期强制:子进程是普通 Node 环境,require('fs') 可直接读写任意路径。对可信小工具这是可接受的信任模型;对社区生态,需要 P1-6(fs 路径白名单)乃至 utilityProcess sandbox。
  2. 无 interception:无法对同一依赖按调用方衰减能力(论文 §6.3 的 interception 表)。安全路线是声明式权限 → 白名单强制 → interception 的渐进路径。
  3. 卸载数据残留extension-data/<id> 不随卸载删除(隐私权衡,P1-5 提供选项)。
  4. 依赖链风险:小工具自包含(不装第三方依赖树),但其内部 npm 依赖由作者自己构建进产物——供应链审查范围 = 包产物本身,这也正是"直下 tarball + doctor 检查"流程存在的原因。

6. 运维与发布

6.1 安装

  • CLInpx @finchtoys/minitools add <pkg>(或本地 zip / 目录)。直接从 npm registry 下载 dist.tarball,写 .finch-id sentinel(npm 包名派生 id)与 .plugins-lock.json(source / installedAt 记录)。
  • GUI:Toolcase 中从目录安装(installFromDirectory,service.ts:1286)或从社区目录搜索安装。
  • 作用域:personal(默认,<FINCH_AGENT_HOME>/.finch/extensions/)与 global(~/.finch/extensions/);无 project 级(见 3.9)。
  • 官方 bundled 扩展:随 App 打包,bundledSeededVersion 门控在新安装或 App 升级时(重新)部署——同一 App 版本内卸载官方扩展保持卸载状态,不会被重启覆盖(state.ts)。

6.2 启停

  • 默认禁用;enable 后 reload() 激活。disable 只 deactivate,保留信任记录与数据。
  • 停用流程(deactivate,service.ts:1223):宿主优雅 deactivate(5s 超时)→ 终止子进程 → 逐个跑 disposers → 注销工具/搜索提供者/图标包/capabilities → 关闭扩展的 Canvas 窗口 → 广播能力视图刷新。
  • 重启:restartActive(ids?) 按 id 独立重启;MiniTool reload 省略 id 时重启全部活跃扩展。

6.3 更新与回滚

  • 检查:主进程后台轮询 npm registry(按 locale 选官方/镜像源),autoUpdate 开关控制是否自动安装。
  • 更新:CLI update 或 App 内更新:下载新 tarball → 覆盖目录 → 重载该扩展。
  • 回滚当前无自动回滚。新版本 activate 失败时错误展示在扩展详情页,但旧版本已被 deactivate。事务化重载是 P0-3。

6.4 健康与诊断

  • 宿主子进程 stderr 统一转主进程日志与扩展控制台面板(consoleService.ts);非预期退出打 extensionHost.exitedUnexpectedly 事件。
  • npx @finchtoys/minitools doctor <dir>:发布前诊断清单(manifest 字段校验、入口存在性、权限声明、本地化完整性等)。

7. 路线图

按"收益/成本"排序。P0 直接对应第 4 章的两个本质分岔 + 事务重载;改动集中在现有模块,不需要重写架构。

P0-1 自动效应追踪:卸载即回滚(宿主内部状态)

ctx.subscriptions 的"作者自觉"升级为"宿主兜底":

  1. ctx.storage / ctx.settings / ctx.secrets写时快照:activate 时记录初始值,deactivate 时生成差异恢复函数(先覆盖最常见的隐性副作用;对应论文"任何 ctx 变更都是 effect")。
  2. 新增 ctx.effect(callback)(兼容层):执行 callback,把每次返回的 dispose/逆函数按 LIFO 折叠进上下文级 accumulator;deactivate 时自动执行。现有 ctx.subscriptions 保留并等价为 accumulator 的一部分,老扩展零迁移
  3. 主进程侧 record.disposers / toolDisposers 清理顺序改为严格 LIFO 并记录日志,使停用顺序可审计。

边界:只承诺"宿主内部状态";文件系统/网络等外部位置只能补偿不能真回滚(论文 §6.1)。

P0-2 响应式 capability 通知:provider 变化联动消费者

  1. CapabilityBroker 维护 consumers: Map<capability, Set<extensionId>>(信息来自 manifest requires.capabilities,已在 hostProcess.ts:844 门控处存在)。
  2. provider 注册/注销时通知相关消费者宿主:消费者执行 refresh()——所有 requires 满足则激活,缺失则停用(或降级)。对应论文 Alg 3 notify + Alg 5 refresh
  3. 卸载顺序纪律:deactivate provider 时先通知依赖者、等其完成 teardown,再执行 provider 自身清理(论文 §5.1.3 "unload 先 drain dependents")。

P0-3 事务化重载/更新:备份 + 失败回滚

在现有按 id 独立重启(restartActive([id]))之上补事务包装:

  1. 更新前把旧目录复制到临时备份(cache/minitools/ 已存在);
  2. activate 失败时恢复备份目录 + 清理失败残留 + 重载;
  3. 多扩展更新逐个提交,成功才继续下一个(对应论文 Alg 10 的 backup/restore_caches 语义);
  4. 开发期 HMR(可选):fs.watch 监听 dist/ 变化 → 对该扩展执行同样的单扩展事务重载。论文 §5.2.2 指出:fiber 模型下 HMR 无需作者标注 accept 边界——Finch 的 Disposable 模型同理。

P1-4 引入 provider 身份

给每次 capability provider 注册分配单调递增 uid,随能力视图广播;消费者缓存"我依赖的 provider uid",变化时即使值相等也触发 refresh。解决"换了 provider 但值相等"的误判(论文 §4.1 fiber uid 思想),为"换实现不扰动消费者"铺路。

P1-5 数据清理选项

卸载对话框增加"同时删除该小工具的本地数据(storage/settings/secrets)"选项,默认保留(恢复友好)。若 P0-1 落地,可顺带输出"本扩展曾修改的宿主状态清单"。

P1-6 权限强制化(渐进式)

优先做 fs 路径白名单(宿主进程入口包装 fs 访问,限定 storagePath 与授权目录),网络/壳命令留待后续;或评估 Electron utilityProcess + sandbox。让"声明式权限"从展示变成约束。

P2-7 声明式配置调和(远期)

把"当前加载了哪些小工具、各自配置"收敛为可 diff 的声明式状态(论文 Def 74 entry + 字段级最小化操作:id/url 变→重建,config 变→仅重载配置,disabled 变→仅启停),取代"开关 + 幂等 reconcile"。建议在 P0-3 的单扩展事务重载落地后自然演进。

明确不做的部分

  • 统一上下文 Γ∞ 的完整复刻(论文 §3.3):ctx 是能力面,"一切状态都经 ctx 且可逆"会伤及桌面宿主灵活性;只采纳其可逆性纪律(P0-1)。
  • 全量形式化/元理论(论文 §4.4):工程系统按需借鉴机制,不引入演算证明。
  • fiber 级多实例:Finch 每扩展一进程,多实例成本高且桌面单用户场景少,保留单实例。

8. 附录:主要事实来源

  • packages/minitool-api/finch.d.ts — MiniToolContext / ExtensionContext 类型契约(subscriptions、tools、composerActions、capabilities、storage、secrets、oauth、sessions、ui、i18n、settingsMenu、canvas)
  • src/main/services/extension/scanner.ts — 清单解析:manifestVersion=1(28 行)、.finch-id sentinel(35 行)、id 策略(65 行)、finch.json 优先级、minVersion 门控、personal 覆盖 global
  • src/main/services/extension/service.tsreload() 幂等 reconcile(672 行)、激活(902 行起)、deactivate(1223 行)、restartActive(ids?)(1248 行)、installFromDirectory(1286 行)、setSettings 单扩展重载(1586 行)、uninstall→trash(1599 行)
  • src/main/services/extension/hostClient.ts — fork 子进程(186 行)、deactivate→terminateGracefully、executeTool 超时
  • src/main/services/extension/hostProcess.ts — oauth 白名单(775 行)、capability provide/get 门控(820-864 行)、storage.json/settings.json(711/731 行)
  • src/main/services/extension/capabilities.ts — CapabilityBroker(register/unregister/has/getVersion/invoke)
  • src/main/services/extension/state.ts — 默认禁用、extensions.json、autoUpdate、grantedPermissions
  • src/main/services/extension/secretStore.tssettings.tspaths.ts(extension-data,113 行)
  • src/main/services/runner/extension-tools.ts — 扩展工具 autoAllow: false、与一方工具同管线
  • packages/minitools/bin/minitools.mjs — CLI:tarball 直下不跑脚本、.finch-idcmdRemovecmdEnable 权限提示、doctor
  • 对照论文:《A Programming Paradigm for Spatiotemporal Composability》,北大 & DeepSeek-AI,2026-08-13 草案(github.com/cordiverse/paper);Cordis 实现见论文 §5;DeepSeek Harness 见 github.com/deepseek-ai/deepseek-harness
  • 配套对比分析:docs/analysis/spatiotemporal-composability-vs-finch-minitools.md(含逐项差距与更细的事实行号)

相关日志

评论

暂无评论,来抢沙发吧。 登录 后发表评论。