Skip to content

Latest commit

 

History

History
296 lines (211 loc) · 14.1 KB

plugins.md

File metadata and controls

296 lines (211 loc) · 14.1 KB

插件系统

插件是一个可安装、可启用并可组合多种扩展能力的目录。它可以同时提供 Commands、Agents、Skills、Hooks、Output Styles、MCP Server、LSP Server 和受限的默认设置。

范围说明:本文描述当前源码中的加载器、Marketplace 和安装状态模型。具体可用插件取决于构建内容、Marketplace、组织策略和当前项目设置。

1. Plugin、Skill 与 Marketplace

概念 作用 是否独立安装单元
Plugin 扩展能力的容器和版本边界 是
Skill 带说明、资源和按需加载规则的能力包 可以单独存在,也可由 Plugin 提供
Marketplace 描述 Plugin 名称、版本、来源和元数据的目录 不是运行时能力本身

Plugin 与 Skill 不是同义词。一个 Plugin 可以没有 Skill,也可以包含多个 Skills;同一个 Plugin 还可以同时注册 Hook、Agent 和 MCP Server。Skills 的独立加载流程见 Skills 机制。

2. 目录结构

加载器支持约定目录,也支持在 Manifest 中追加自定义相对路径:

example-plugin/
├── .claude-plugin/
│   └── plugin.json
├── commands/
│   └── inspect.md
├── agents/
│   └── reviewer.md
├── skills/
│   └── refactor/
│       └── SKILL.md
├── hooks/
│   └── hooks.json
├── output-styles/
│   └── concise.md
├── .mcp.json
└── .lsp.json

这里是结构示例,不表示仓库必须存在这些文件。

Manifest 的规范位置是 .claude-plugin/plugin.json。Manifest 缺失时,loadPluginManifest() 会创建最小内存 Manifest,因此约定目录仍可被发现。Manifest 中的组件路径必须是以 ./ 开头、位于 Plugin 根目录内的相对路径;加载时还会校验真实路径,避免通过符号链接或 .. 越界。

3. Manifest

一个精简示例:

{
  "name": "example-plugin",
  "version": "1.2.0",
  "description": "Repository review helpers",
  "commands": ["./extra/inspect.md"],
  "agents": ["./extra/reviewer.md"],
  "skills": ["./extra/refactor"],
  "hooks": "./config/hooks.json",
  "mcpServers": {
    "helper": {
      "type": "stdio",
      "command": "node",
      "args": ["${CLAUDE_PLUGIN_ROOT}/server.mjs"]
    }
  }
}

示例名称和文件路径仅用于说明 Schema。

3.1 元数据字段

PluginManifestSchema 支持名称、版本、描述、作者、主页、仓库、许可证、关键词和依赖。依赖项可写完整的 plugin@marketplace,也可写裸名称;裸名称相对当前 Plugin 所属 Marketplace 解析。

3.2 组件字段

字段 支持形式
commands 单个 Markdown/Skill 路径、路径数组,或带内联内容/元数据的名称映射
agents Markdown 路径或数组
skills Skill 目录路径或数组
outputStyles 文件或目录路径,也可为数组
hooks JSON 路径、内联 Hook 配置或混合数组
mcpServers JSON 路径、MCPB 路径/URL、内联映射或混合数组
lspServers JSON 路径、内联映射或混合数组
channels 把 Plugin MCP Server 声明为消息 Channel,并定义配置项
settings 合并到设置级联的默认值;加载时只保留允许字段
userConfig 启用时向用户收集的 Plugin 配置

Manifest 顶层未知字段会被剥离,以兼容未来或供应方扩展;严格的嵌套配置仍会因字段或类型错误而校验失败。开发者校验入口会提供更明确的未知字段反馈。

3.3 用户配置与变量

userConfig 支持字符串、数字、布尔、目录和文件等类型。字段名必须是可用作标识符的格式。非敏感值写入设置中的 pluginConfigs[pluginId].options,敏感值写入系统安全存储或凭据文件。

加载组件时可使用:

${CLAUDE_PLUGIN_ROOT}
${CLAUDE_PLUGIN_DATA}
${user_config.KEY}

Hook 还会收到相应的 CLAUDE_PLUGIN_OPTION_<KEY> 环境变量。敏感配置不会注入 Skill/Agent 文本,但可用于需要运行时秘密的 MCP、LSP 和 Hook 配置。

4. 发现与加载顺序

pluginLoader.ts 明确区分两类发现来源:

  1. 设置中以 plugin@marketplace 标识的 Marketplace Plugin。
  2. --plugin-dir 或 SDK Plugin 选项注入的当前会话目录。

此外,构建内可注册 name@builtin Plugin。Builtin 可以包含 Skills、Hooks 和 MCP Server,并按运行环境决定是否可见以及默认是否启用。

整体生命周期为:

flowchart TD
    A["设置、Builtin 或 --plugin-dir"] --> B["解析 Plugin ID 和作用域"]
    B --> C["解析 Marketplace 与安装记录"]
    C --> D["定位版本化缓存或会话目录"]
    D --> E["读取并校验 Manifest"]
    E --> F["校验依赖、策略和启用状态"]
    F --> G["解析约定目录与自定义路径"]
    G --> H["加载 Commands / Agents / Skills / Hooks"]
    G --> I["提取 MCP / LSP / Settings"]
    H --> J["加入当前应用能力集合"]
    I --> J
Loading

加载器收集错误而不是在第一个坏 Plugin 处终止全部加载。最终结果分为 enabled、disabled 和 errors,各组件加载器只消费已启用项。

5. Plugin ID、命名空间与冲突

Marketplace Plugin 的稳定标识为:

<plugin-name>@<marketplace-name>

Commands、Agents 和 Output Styles 会使用 Plugin 名称建立命名空间,例如:

example-plugin:inspect
example-plugin:reviewer

嵌套目录会继续追加命名空间片段。Plugin MCP Server 使用 plugin:<plugin>:<server> 作为 Server 名,再由 MCP 层生成 mcp__...__... Tool 名称。

加载器会检测重复 Plugin 名、同一 Plugin 内重复文件路径以及 MCP 连接签名重复。对于 MCP,手动配置优先于 Plugin,多个 Plugin 之间按加载顺序保留第一个。

6. Marketplace

6.1 来源类型

MarketplaceSourceSchema 支持:

  • 直接 URL 指向 marketplace.json。
  • GitHub owner/repo,可指定 Ref、Manifest 路径和 Sparse Checkout 路径。
  • 任意 Git URL。
  • npm 包。
  • 本地文件或本地目录。
  • 设置内联的 Marketplace 定义。

hostPattern 和 pathPattern 用于组织策略匹配,不是普通 Marketplace 内容来源。

6.2 意图、缓存与安装记录

Marketplace 状态分成三层:

层 代表什么 典型位置
声明意图 用户或项目希望使用哪些 Marketplace 设置中的 extraKnownMarketplaces
本地缓存 Marketplace Manifest 或克隆仓库 Plugin 目录下的 marketplaces/
已知状态 来源、缓存位置和更新时间 known_marketplaces.json

marketplaceManager.ts 会协调这三层,并支持离线读取缓存。Plugin 安装内容放入版本化 Cache,安装元数据则独立记录在 installed_plugins.json。

6.3 来源策略

组织策略可以:

  • 明确阻止某些 Marketplace。
  • 只允许严格已知的来源。
  • 按 Host 或本地路径模式放行来源。
  • 阻止特定 Plugin 的安装或启用。

受保护的官方 Marketplace 名称还会校验来源组织和 Unicode 同形字符,避免第三方来源冒用保留名称。

7. 安装作用域与状态

可持久化作用域定义在 PluginScopeSchema:

作用域 可见范围 设置来源
user 所有项目 用户设置
project 当前项目,适合共享 项目设置
local 当前项目,仅本地覆盖 本地设置
managed 组织管理 托管设置;普通安装命令不写入

--plugin-dir 属于额外的 flag 会话作用域,不写入安装记录。

installed_plugins.json 当前使用 V2 结构:一个 Plugin ID 可以同时拥有多条不同 Scope、项目路径和版本的安装记录。project 与 local 记录只有在 projectPath 匹配当前原始工作目录时才生效;user 和 managed 全局生效。

安装状态与启用状态有意分离:

  • installed_plugins.json 记录版本、安装路径、时间和 Git SHA。
  • 各级设置中的 enabledPlugins 表示当前项目是否启用。

因此,“已经下载到磁盘”和“当前会话已加载”是两个不同结论。

8. 安装、启用、更新和卸载

pluginOperations.ts 提供主要操作:

安装

  1. 解析 Plugin ID 和 Marketplace。
  2. 检查 Marketplace 与组织策略。
  3. 获取来源并计算版本。
  4. 写入版本化 Cache。
  5. 记录对应 Scope 的安装条目。
  6. 更新该 Scope 的 enabledPlugins 意图。

启用与禁用

启用状态以设置为先。local: false 可以覆盖共享项目中的 true,让用户只在自己环境禁用某个 Plugin。启用时还会检查组织阻止策略和依赖。

更新

更新采用非原地方式:获取新来源,计算新版本并写入新的版本化目录,然后更新磁盘安装记录。当前运行会话保留启动时快照,因此更新结果通常需要重启才能应用;旧版本在没有安装记录引用后才进入清理流程。

卸载

卸载只移除指定 Scope 的设置与安装记录。同一 Plugin 仍被其他 Scope 引用时,缓存内容继续保留;最后一个 Scope 被移除后才清理配置和孤立版本。卸载依赖项时会提示仍依赖它的 Plugin,但不会把所有相关项静默级联删除。

9. 各组件如何注入运行时

组件 加载与命名 运行时入口
Commands Markdown/Skill 转为命令,名称带 Plugin 前缀 loadPluginCommands.ts
Agents Frontmatter 转为 Agent Definition,名称带 Plugin 前缀 loadPluginAgents.ts
Skills 作为 Plugin 来源的 Skill/Command 按需加载 loadPluginCommands.ts
Hooks 转为带 pluginRoot、pluginName、pluginId 的 Hook Matcher loadPluginHooks.ts
Output Styles 文件转为带 Plugin 前缀的输出样式 loadPluginOutputStyles.ts
MCP 提取、变量替换、命名空间化后进入 MCP 配置合并 mcpPluginIntegration.ts
LSP 校验 Server 配置并加入语言服务管理 lspPluginIntegration.ts
Settings 过滤到允许键后加入设置级联 pluginLoader.ts

Plugin Agent 中部分高控制级 Frontmatter 会被忽略,因为第三方 Plugin 不应取得与用户项目内 Agent 文件相同的控制范围。具体字段以 loadPluginAgents.ts 的过滤逻辑为准。

10. 依赖与失效隔离

dependencyResolver.ts 在加载时检查依赖:

  • 依赖未启用或未找到时,依赖方会被降级到 Disabled,并记录结构化错误。
  • Bare Dependency 相对当前 Marketplace 解析。
  • 禁用或卸载被依赖项时,操作层可列出反向依赖。

错误类型覆盖 Manifest、路径、网络、Marketplace、MCP/LSP 配置、依赖、策略和缓存缺失等场景。当前部分调用点仍使用通用错误,类型文件明确记录了后续细化计划。

单个组件失败不必然破坏其他 Plugin。例如一个 MCP 配置错误会作为 Plugin Error 汇总,其他正常 Plugin 仍可继续加载。

11. 缓存与热重载

Plugin Loader、Commands、Agents、Hooks 和 Output Styles 都有独立缓存。改变设置或执行 Reload 时需要按依赖顺序清理并重新加载,不能只删除一个内存 Map。

当前行为要点:

  • 远程设置变化可触发 Plugin Hook 热重载。
  • 已禁用或卸载的 Hook 会立即从注册表裁剪。
  • 新启用 Plugin 的完整组件通常等待显式 Reload 或下一次启动。
  • MCP 管理器在 Plugin Reload 后会移除过期 Server 并连接新增 Server。
  • 后台更新只改变磁盘安装记录,不改写当前会话启动快照。

12. 故障定位

现象 优先检查
Plugin 找不到 是否使用完整 plugin@marketplace、Marketplace 是否已声明和缓存
已安装但未加载 enabledPlugins、当前 Scope、项目路径和依赖状态
Manifest 报错 字段类型、以 ./ 开头的路径、嵌套严格字段
Command/Agent 重名 Plugin 命名空间、嵌套目录和重复文件路径
MCP Server 消失 配置变量、用户配置、签名去重和 MCP 策略
修改后未生效 当前会话缓存;执行 Plugin Reload 或重启
只在某项目失效 project/local 的 projectPath 与设置覆盖关系
Marketplace 被忽略 Blocklist、Strict Known Marketplace、保留名称来源校验

13. 关键源码