跳转至

11 · Integrations 与 Plugins

Herdr 有两套“扩展”机制,但目标完全不同:Integration 让外部 Agent 更好地向 Herdr 报告自身;Plugin 让用户给 Herdr 增加动作、事件命令和工具 pane。 把二者分开,才能理解为什么前者大量编辑 Agent 配置,后者有 manifest/registry/runtime。

11.1 对照表

维度 Integration Plugin
扩展谁 外部 AI Agent Herdr 工作流/UI
安装动作 写 hook/extension/script、编辑 Agent config link 一个含 herdr-plugin.toml 的目录
主要数据流 Agent lifecycle → Herdr API Herdr context/event → 外部 command/pane
状态影响 Agent session/state authority action/log/pane,不直接成为 Agent 权威
更新判断 内嵌 asset version marker plugin manifest version/min Herdr version
风险 改用户已有 Agent 配置 执行用户信任的外部命令

11.2 Integration 目标版图

固定快照的 IntegrationTarget 有 16 个:

Pi, Omp, Claude, Codex, Copilot, Devin, Droid, Kimi,
OpenCode, Kilo, Hermes, QoderCLI, Cursor, MastraCode,
Antigravity CLI, Grok

平台可用性、命令别名和安装目录发现集中在 src/integration/registry.rs。例如 Cursor 使用 cursor-agent,Antigravity CLI 使用 agy,Kilo 可能有多个命令名。

11.3 为什么每个 Agent 都要定制安装器

Agent 的扩展模型不同:

  • 某些读取 settings.json 的 hooks;
  • 某些读取 hooks.json / TOML;
  • Pi/OMP 使用 TypeScript extension;
  • OpenCode/Kilo 使用 JavaScript plugin;
  • Hermes 使用 Python plugin manifest;
  • 不同事件名表达 start/stop/blocked/session replacement;
  • Windows 需要 PowerShell 资产和可执行处理差异。

因此 src/integration/targets.rs 不是一个通用“复制 hook.sh”循环,而是每个目标的显式 install/uninstall 流程,共享底层安全 helper。

11.4 Bundled assets 与版本标记

脚本/插件资产通过 include_str! 编进 Herdr 二进制,位于 src/integration/assets/。好处是:

  • 离线安装,不依赖运行时网络;
  • 资产与可执行文件版本一起发布;
  • updater/handoff 后可判断已安装版本是否 outdated;
  • 集成测试可以直接运行同一资产。

安装内容包含 Herdr ownership/version marker。状态检查可区分 not installed / current / outdated,而不是只看文件是否存在。

11.5 配置编辑必须保留用户内容

安装 Claude/Codex 等 integration 时,需要更新用户已有 JSON/TOML。安全要求:

  1. 解析现有配置,解析失败则停止,不覆盖;
  2. 只增删 Herdr 所拥有的命令/命名块;
  3. 安装幂等:重复运行不产生重复 hook;
  4. 卸载只删除能证明属于 Herdr 的条目;
  5. 保留用户顺序/未知字段的程度以各格式能力为准;
  6. 写回前验证生成结构;
  7. 需要时清理明确识别的 legacy 资产。

例如卸载不能“删除所有 PermissionRequest hooks”;那会破坏用户其他工具。源码中的 src/integration/config_edit.rs 用命令路径、marker 和命名 block 精确定位 Herdr-owned 项。

11.6 Integration 的运行数据流

sequenceDiagram
    participant A as Agent hook/extension
    participant Env as HERDR_* context
    participant API as Herdr local API
    participant T as TerminalState
    participant E as EventHub/UI

    A->>Env: read pane/session/socket context
    A->>API: pane.report_agent/session/metadata
    API->>T: validate identity/source/sequence
    T->>T: arbitrate hook vs screen evidence
    T-->>E: publish only effective changes

Hook 需要知道自己属于哪个 Herdr pane/terminal/session。上下文通过受控环境变量/启动环境注入,报告仍由 API 验证,不能因为请求来自本地脚本就跳过 identity 和 sequence。

11.7 完整 lifecycle 与 session-only

不同 Agent 暴露的事件能力不同:

  • 有 start/stop/blocked/session replace 的 integration 可以成为 full-lifecycle authority;
  • 只知道 session id 的 integration 主要帮助 native resume,状态继续用 screen detection;
  • 没有明确 blocked 事件时,不能用一个泛化 post-tool hook猜测 Idle;
  • process exit 会终止该 authority generation。

这也是 integration_target_available 与“状态权威能力”不能混成一个 bool 的原因:能安装不代表能完整报告。

11.8 Plugin manifest

Plugin 从本地目录的 herdr-plugin.toml 加载。固定测试 fixture 展示最小形状:

id = "example.smoke"
name = "Smoke Plugin"
version = "0.1.0"
min_herdr_version = "0.6.10"
platforms = ["linux", "macos", "windows"]

[[actions]]
id = "workspace-list"
title = "List workspaces"
contexts = ["workspace"]
command = ["herdr", "workspace", "list"]

[[events]]
on = "worktree.created"
command = ["herdr", "plugin", "log", "list", "--plugin", "example.smoke"]

[[panes]]
id = "board"
title = "Board"
placement = "overlay"
command = ["herdr", "workspace", "list"]

原 fixture 见 tests/fixtures/plugin-smoke/herdr-plugin.toml。

11.9 Manifest 六类入口

RawPluginManifest 支持:

section 何时运行 用途
build link/update 时按平台 编译/准备插件资产
startup server/plugin startup 启动伴随进程或准备环境
actions 用户/API 显式 invoke 上下文动作
events 允许的 Herdr 事件发生 低频自动化 hook
panes 用户打开工具 pane dashboard、日志、辅助 TUI
link_handlers 匹配终端中的 link/pattern 把链接映射到 action

每类 entry 都可声明 platforms,command 使用 argv 数组而不是默认 shell 字符串,减少 quoting 注入和跨平台歧义。

11.10 Manifest 验证

加载器在 src/app/api/plugins/manifest.rs 中验证:

  • plugin/action/pane/link handler ID 格式和长度;
  • name/version/command 非空;
  • min_herdr_version;
  • platform 值只允许 linux/macos/windows;
  • action id 在 plugin 内唯一;
  • event kind 在允许集合;
  • pane placement 与 width/height 组合合法;
  • link handler pattern/action 引用有效;
  • canonical manifest/root 路径。

验证后转成 API schema 中的 InstalledPluginInfo 等公开类型,避免 runtime 到处处理半合法 raw TOML。

11.11 Pane placement

PluginPanePlacement 有五种:

placement 行为
overlay 覆盖当前 UI 的全尺寸/受控层
popup 有 width/height 的浮层
split 在目标 pane 旁插入 BSP split
tab 新建 tab 承载工具进程
zoomed 以 zoomed pane 打开并聚焦

只有 popup 接受 width/height;split 需要 direction/target;zoomed 通常强制 focus。打开失败必须回滚已创建的 layout/pane/runtime,复用第 4、5 章的补偿事务边界。

11.12 Action 上下文与命名空间

Plugin action 的外部身份必须带 plugin id,例如逻辑上的:

example.smoke:workspace-list

否则两个插件都定义 open 时无法解析。invoke 时 Herdr 构造受控 context/env,可能包含:

  • plugin root/id/version;
  • 当前 workspace/tab/pane public id;
  • cwd/repo/worktree;
  • Herdr session/API socket;
  • manifest 声明和调用方额外 env(经过验证)。

Action command 是外部进程,失败应记录 exit/status/log,不应 panic server。

11.13 Plugin registry 的读写策略

全局 registry 记录 linked manifest path、source、enabled 等。它使用 lock + temp/rename 管理并发和原子写。

一个细致的策略是:

  • 启动读取可宽容:坏 registry 不应阻止 Herdr 启动,可警告并跳过;
  • 显式 mutation 前严格读取:用户执行 link/unlink/enable 时,若原文件坏,必须停止,不能把“宽容读出的空列表”写回覆盖证据;
  • 每次加载重解析 manifest:路径下内容可更新;
  • 保留 registry 的 enabled/source:manifest 自身不拥有用户开关。

实现位于 src/persist/plugin_registry.rs。这是一种很实用的“可用性读 vs 破坏性写”差异化严格度。

11.14 Event hook 的隔离

Plugin event command 以 detached/background 方式运行,日志有界保存。运行时必须避免:

  • 阻塞 App event loop 等 child;
  • 一个 hook 失败阻断其他插件;
  • 无限 stdout/stderr 占内存;
  • 高频 event 触发进程风暴;
  • plugin 产生相同事件形成无界反馈;
  • server shutdown 遗留失控 child(按 startup/event 语义区分)。

因此允许的 event 集合会排除 output/scroll 等高频种类,runtime 只把完成结果/日志摘要送回主循环。

11.15 信任模型

Plugin 是本地代码执行扩展,不是强沙箱:manifest command 可以读取用户权限可访问的文件。Herdr 能做的是:

  • 只运行用户显式 link/enable 的目录;
  • 展示 canonical source path 和命令;
  • 不经 shell 解释 argv;
  • 严格校验 manifest;
  • 约束 Herdr 注入的上下文;
  • 以进程/日志/事件隔离保护 server 可用性。

这与“远程市场安装后安全运行不受信代码”是不同产品。如果未来引入远程来源,需要签名、权限声明或 sandbox 等额外层,不能把当前本地信任模型误当供应链安全。

11.16 测试版图

  • integration config edit 单测:保留未知用户项、幂等、精确卸载、legacy migration;
  • bundled JS/TS asset 用 Bun 测试真实 lifecycle payload;
  • plugin manifest 表驱动测试:ID、platform、placement、version、command;
  • CLI/API plugin 集成测试:link/list/enable/action/log/pane;
  • Live Handoff 测试:plugin registry/伴随行为跨 server replacement;
  • 三平台 fixture:路径、PowerShell/shell、可执行权限差异。

11.17 本章结论

  1. Integration 是 Agent 观测适配层,Plugin 是 Herdr 工作流扩展层;
  2. 修改用户配置必须以 ownership marker 做可逆、幂等编辑;
  3. hook authority 取决于 lifecycle 完整度,不取决于是否安装;
  4. Plugin manifest 先完整验证,再转成 runtime 可依赖的 typed model;
  5. 外部命令要隔离、日志有界,高频事件不能直接映射为进程 spawn;
  6. 宽容启动读取不能演变成破坏性写回。

下一章回到 Herdr 的核心工作流:一个 Agent 一个 Git worktree。我们会看 Git 命令如何从 UI/API 移出主循环,operation id 怎样拒绝乱序结果,强制删除又如何证明目标确实属于该 repo。