# 第五阶段 · 模块五 · 第一节:插件架构
插件系统是如何设计的?插件的入口点是什么?插件如何与主程序交互?
Claude Code 全局架构
┌─────────────────────────────────────────────────────────────────────┐
│ 插件系统 ← 本节 │
│ │
│ pluginCliCommands.ts ──> CLI 命令 │
│ pluginOperations.ts ──> 操作逻辑 │
│ pluginLoader.ts ──> 插件加载 │
└─────────────────────────────────────────────────────────────────────┘
插件 = 可扩展的功能模块
用户安装 → Claude Code 自动加载 → 提供新功能
示例插件:
- 代码格式化工具
- CI/CD 集成
- 文档生成器
- 自定义命令
| 方面 | 内置功能 | 插件 |
| 加载时机 | 启动时 | 按需或启动时 |
| 安装方式 | 随 Claude Code | 用户手动安装 |
| 更新方式 | Claude Code 更新 | 独立更新 |
| 卸载 | 不可卸载 | 可卸载 |
源码位置:`src/services/plugins/`
pluginOperations.ts ← 插件操作逻辑
pluginCliCommands.ts ← CLI 命令定义
pluginLoader.ts ← 插件加载器
src/utils/plugins/
├── pluginLoader.ts ← 核心加载逻辑
├── pluginIdentifier.ts ← 插件标识
├── marketplaceManager.ts ← 市场管理
└── validatePlugin.ts ← 插件验证
源码位置:`src/services/plugins/pluginCliCommands.ts`
type PluginCliCommand =
| 'install'
| 'uninstall'
| 'enable'
| 'disable'
| 'update'
| 'list';
// 安装插件
export async function installPlugin(
plugin: string,
scope?: PluginScope,
): Promise<void> {
// 1. 解析插件标识
const pluginId = parsePluginIdentifier(plugin);
// 2. 下载插件
await downloadPlugin(pluginId);
// 3. 验证插件
await validatePlugin(pluginId);
// 4. 启用插件
await enablePlugin(pluginId);
}
问 1:插件安装到哪里?
// 插件安装到本地目录
const PLUGIN_DIR = path.join(
process.env.HOME ?? '',
'.claude', 'plugins'
);
// 插件结构
~/.claude/plugins/
└── my-plugin/
├── manifest.json ← 插件配置
├── index.js ← 入口
└── package.json
问 2:插件如何被加载?
// 在 Claude Code 启动时加载
async function loadAllPlugins(): Promise<Plugin[]> {
const pluginDirs = readdirSync(PLUGIN_DIR);
const plugins = await Promise.all(
pluginDirs.map(async dir => {
const manifest = await readManifest(dir);
if (manifest.enabled) {
return loadPlugin(dir);
}
})
);
return plugins.filter(Boolean);
}
源码位置:`src/utils/plugins/pluginIdentifier.ts`
// 插件标识格式
type PluginIdentifier = {
name: string; // 'my-plugin'
scope: string; // 'user' | 'project' | 'marketplace'
version?: string; // '1.0.0'
};
// 示例
// user/my-plugin
// project/format-tool
// marketplace/anthropic/quick-actions
// 插件的作用域决定其可见性和优先级
// user: 当前用户可用
// project: 当前项目可用
// marketplace: 从市场安装
type PluginScope = 'user' | 'project' | 'marketplace';
// 优先级
project > user > marketplace
问 1:项目插件和用户插件的区别?
// 项目插件:只在该项目目录可用
// 存储在项目根目录 .claude/plugins/
// 用户插件:该用户所有项目都可用
// 存储在 ~/.claude/plugins/
// 加载优先级
project > user
问 2:如何指定插件版本?
// 在 manifest.json 中指定
{
"name": "my-plugin",
"version": "1.0.0",
"compatibility": {
"claude": ">=3.0.0"
}
}
// 安装流程
async function installPlugin(pluginId: string): Promise<void> {
// 1. 解析标识
const { name, scope } = parsePluginIdentifier(pluginId);
// 2. 决定安装路径
const installPath = getPluginPath(scope, name);
// 3. 下载
await downloadTo(pluginId, installPath);
// 4. 验证
await validatePluginContents(installPath);
// 5. 写入配置
await addToEnabledList(pluginId);
}
// 启用插件
export async function enablePlugin(pluginId: string): Promise<void> {
const settings = getSettings();
settings.enabledPlugins[pluginId] = true;
// 或者指定特定命令
settings.enabledPlugins[pluginId] = ['cmd1', 'cmd2'];
saveSettings(settings);
}
// 禁用插件
export async function disablePlugin(pluginId: string): Promise<void> {
const settings = getSettings();
settings.enabledPlugins[pluginId] = false;
saveSettings(settings);
}
// 卸载流程
async function uninstallPlugin(pluginId: string): Promise<void> {
// 1. 从启用列表移除
await disablePlugin(pluginId);
// 2. 删除文件
const installPath = getPluginPath(pluginId);
await rmrf(installPath); // 安全删除
}
问 1:禁用和卸载的区别?
// 禁用:保留文件,但不使用
// enabled = false
// 卸载:删除文件和配置
// enabled = undefined + files deleted
问 2:插件可以自动更新吗?
// 支持自动更新
export async function updatePlugin(pluginId: string): Promise<void> {
const currentVersion = getCurrentVersion(pluginId);
const latestVersion = await checkForUpdate(pluginId);
if (latestVersion > currentVersion) {
await downloadPlugin(pluginId, latestVersion);
}
}
答案:
// 插件运行在主进程,有完全访问权限
// 安全措施:
// 1. 插件审查(市场插件)
// 2. 权限清单(插件声明需要的权限)
// 3. 沙箱限制(部分功能)
// 用户责任:
// - 只安装可信插件
// - 定期更新插件
答案:
// 1. 查看日志
claude plugins list --verbose
// 2. 验证插件
claude plugins validate ./my-plugin
// 3. 重新加载
claude plugins reload
答案:
// 一个插件可以包含:
// - 自定义命令
// - 工具
// - 钩子
// - MCP 服务器
// - UI 组件
// 示例 manifest.json
{
"name": "my-plugin",
"commands": [{ "name": "hello", "path": "./commands/hello.ts" }],
"tools": [{ "name": "myTool", "path": "./tools/myTool.ts" }],
"mcpServers": [{ "name": "my-mcp", "command": "npx", "args": ["my-mcp-server"] }]
}
| 文件 | 核心内容 |
| `src/services/plugins/pluginCliCommands.ts` | CLI 命令 |
| `src/services/plugins/pluginOperations.ts` | 操作逻辑 |
| `src/utils/plugins/pluginLoader.ts` | 插件加载 |
下一节我们将深入 插件注册与配置:
- 插件配置存储
- 插件与命令的绑定
- 插件的权限模型
*- 第一轮:□ 事实准确性*
*- 第二轮:□ 深度与洞见*
*- 第三轮:□ 可读性与价值*