一、Plugin开发的准备工作
在开始开发Claude Code Plugin之前,需要做好充分的准备工作。Plugin是Claude Code的扩展模块,通过Plugin API与Claude Code交互,实现自定义命令、工具、钩子等功能。本节将介绍开发环境的搭建和项目初始化。
1.1 了解Plugin框架API
Claude Code Plugin框架提供了一套完整的API,让开发者可以扩展Claude Code的功能。核心API包括:
- onCommand -- 注册斜杠命令,用户输入 / 后触发
- onFileChange -- 监听文件变化事件
- onHook -- 注册生命周期钩子(如beforeCommand、afterRead等)
- registerTool -- 注册自定义工具函数
- addContextMenuAction -- 添加上下文菜单动作
1.2 安装开发工具
开发Plugin需要Node.js环境和Claude Code CLI。以下是安装步骤:
# 确保已安装 Node.js(建议 v18 以上)
node -v
# 全局安装 Claude Code CLI
npm install -g @anthropic-ai/claude-code
# 验证安装
claude --version
1.3 创建Plugin项目
Plugin项目遵循标准的Node.js包结构。创建一个新的项目目录并初始化:
# 创建项目目录
mkdir my-claude-plugin
cd my-claude-plugin
# 初始化 npm 项目
npm init -y
# 安装 Plugin SDK(如需要)
npm install @anthropic-ai/claude-plugin-sdk
说明: Plugin项目本质上是一个npm包,需要遵循npm包的命名规范。建议使用 claude-plugin- 前缀命名,方便社区发现。
提示: 在项目根目录创建 src/ 目录管理源码,使用 src/index.js 作为入口文件,有助于保持项目结构清晰。
二、manifest.json完整配置
manifest.json是Plugin的核心配置文件,位于项目根目录。Claude Code通过读取此文件来识别和加载Plugin。下面详细讲解每一个配置项的作用。
2.1 基础配置示例
{
"name": "claude-plugin-my-plugin",
"version": "1.0.0",
"description": "我的第一个Claude Code Plugin",
"main": "src/index.js",
"commands": [
{
"name": "hello",
"description": "打招呼命令",
"usage": "/hello [name]"
}
],
"hooks": {
"beforeCommand": ["log-before"],
"afterCommand": ["log-after"]
},
"permissions": ["read", "write"],
"dependencies": {}
}
2.2 配置项详解
| 配置项 |
类型 |
必填 |
说明 |
| name |
string |
是 |
Plugin名称,建议与npm包名一致 |
| version |
string |
是 |
语义化版本号,遵循SemVer规范 |
| description |
string |
是 |
简短描述Plugin功能 |
| main |
string |
是 |
入口文件路径,相对于项目根目录 |
| commands |
array |
否 |
注册的斜杠命令列表,每个命令包含name和description |
| hooks |
object |
否 |
声明生命周期钩子及对应的处理函数名称 |
| permissions |
array |
否 |
Plugin运行所需的权限声明 |
| dependencies |
object |
否 |
Plugin内部依赖的其他Plugin |
2.3 权限声明
permissions字段用于声明Plugin需要访问的资源权限。Claude Code会在加载Plugin时检查权限声明并提示用户授权。
// 支持的权限类型
"permissions": [
"read", // 读取文件
"write", // 写入文件
"network", // 网络访问
"clipboard", // 剪贴板访问
"terminal", // 终端交互
"environment" // 环境变量访问
]
注意: 权限声明应遵循最小权限原则,只声明Plugin确实需要的权限。过多的权限声明可能降低用户对Plugin的信任度。
三、核心功能开发
入口文件(如 src/index.js)是Plugin的核心实现。Claude Code在加载Plugin时会调用入口文件的导出函数,并将Plugin上下文(context)作为参数传入。开发者通过context对象访问所有API。
3.1 注册斜杠命令(onCommand)
通过 context.onCommand() 注册自定义斜杠命令。用户在对话中输入 / 后即可看到所有可用命令。
module.exports = function(context) {
// 注册 /hello 命令
context.onCommand('hello', async (args) => {
const name = args.trim() || 'World';
return `Hello, ${name}! 欢迎使用Claude Code Plugin开发。`;
});
// 注册 /weather 命令
context.onCommand('weather', async (args) => {
const city = args.trim() || '北京';
// 调用外部API获取天气数据
const response = await fetch(
`https://api.weather.com/${city}`
);
const data = await response.json();
return `${city}当前气温:${data.temp}°C,天气:${data.condition}`;
});
};
3.2 添加文件监听器(onFileChange)
通过 context.onFileChange() 监听文件变化,在文件修改时自动触发逻辑。
module.exports = function(context) {
// 监听当前工作区的所有 .md 文件
context.onFileChange('**/*.md', async (eventType, filePath) => {
console.log(`[Plugin] 文件变更: ${eventType} - ${filePath}`);
if (eventType === 'change') {
// 读取文件内容
const content = context.readFile(filePath);
// 检查文件是否包含 TODO 标记
if (content.includes('TODO')) {
context.showNotification({
title: '待办事项提醒',
message: `文件 ${filePath} 中包含未完成的TODO项`
});
}
}
});
};
3.3 注册生命周期钩子
生命周期钩子允许Plugin在特定事件节点执行自定义逻辑。通过 context.onHook() 注册。
module.exports = function(context) {
// 在命令执行之前触发
context.onHook('beforeCommand', async (commandName, args) => {
console.log(`[Plugin] 即将执行命令: ${commandName}`);
return { commandName, args };
});
// 在命令执行之后触发
context.onHook('afterCommand', async (commandName, result) => {
console.log(`[Plugin] 命令执行完成: ${commandName}`);
context.setGlobalState('lastCommand', commandName);
return result;
});
// 在读取文件后触发,可修改内容
context.onHook('afterRead', async (filePath, content) => {
if (filePath.endsWith('.md')) {
return content + '\n\n---\n*由Plugin自动添加*';
}
return content;
});
};
核心要点: 生命周期钩子必须返回预期的数据结构,否则可能导致Claude Code行为异常。beforeCommand应返回 { commandName, args },afterRead应返回修改后的内容字符串。
3.4 注册上下文菜单动作
通过 context.addContextMenuAction() 在文件的上下文菜单中添加自定义操作。
module.exports = function(context) {
// 添加"统计代码行数"菜单项
context.addContextMenuAction({
id: 'count-lines',
label: '统计代码行数',
when: 'file',
action: async (filePath) => {
const content = context.readFile(filePath);
const lines = content.split('\n').length;
const codeLines = content.split('\n')
.filter(line => line.trim() !== '').length;
return `文件: ${filePath}
总行数: ${lines}
有效代码行数: ${codeLines}`;
}
});
};
四、Plugin测试和调试
测试和调试是Plugin开发中不可或缺的环节。Claude Code提供了多种方式来验证Plugin的功能是否正确。
4.1 本地加载测试
在开发过程中,可以通过两种方式加载本地Plugin进行测试:
# 方式一:使用 npm link 全局链接
cd my-claude-plugin
npm link
# 方式二:在 settings.json 中直接指定Plugin路径
// .claude/settings.json
{
"plugins": [
"file:///Users/username/projects/my-claude-plugin"
]
}
推荐: 在开发阶段推荐使用 settings.json 方式加载Plugin,这样可以快速迭代而无需频繁执行 npm link。
4.2 调试输出
使用 console.log 进行调试输出是最直接的调试方式。Claude Code会将插件的控制台输出重定向到日志文件。
module.exports = function(context) {
context.onCommand('debug-test', async (args) => {
console.log('[DEBUG] 开始执行 debug-test 命令');
console.log('[DEBUG] 接收参数:', args);
try {
const result = await someAsyncFunction(args);
console.log('[DEBUG] 执行成功:', result);
return result;
} catch (error) {
console.error('[DEBUG] 执行失败:', error.message);
return `错误: ${error.message}`;
}
});
};
注意: 发布前务必将调试日志代码移除或通过环境变量控制开启,避免日志过度输出影响性能。
4.3 单元测试编写
编写单元测试确保Plugin各模块功能正确。推荐使用 Jest 测试框架。
// 安装测试依赖
npm install --save-dev jest
// tests/plugin.test.js
const plugin = require('../src/index');
describe('Plugin命令测试', () => {
let mockContext;
beforeEach(() => {
mockContext = {
onCommand: jest.fn(),
onFileChange: jest.fn(),
onHook: jest.fn(),
readFile: jest.fn().mockReturnValue(''),
setGlobalState: jest.fn(),
getGlobalState: jest.fn().mockReturnValue(null)
};
});
test('应该正确注册hello命令', () => {
plugin(mockContext);
expect(mockContext.onCommand).toHaveBeenCalledWith(
'hello', expect.any(Function)
);
});
test('hello命令应返回问候语', async () => {
plugin(mockContext);
const helloHandler = mockContext.onCommand.mock.calls
.find(call => call[0] === 'hello')[1];
const result = await helloHandler('Claude');
expect(result).toBe(
'Hello, Claude! 欢迎使用Claude Code Plugin开发。'
);
});
});
4.4 常见问题排查
| 问题 |
可能原因 |
解决方案 |
| Plugin未加载 |
manifest.json路径或格式错误 |
检查manifest.json是否在项目根目录,JSON格式是否正确 |
| 命令不显示 |
onCommand未正确注册 |
确认入口文件是否正确导出函数,onCommand是否被调用 |
| 权限不足 |
permissions声明缺失 |
在manifest.json中添加相应的权限声明 |
| 钩子不触发 |
钩子名称或签名不匹配 |
检查钩子名称是否正确,回调函数签名是否符合API要求 |
五、Plugin发布和维护
完成开发和测试后,可以将Plugin发布到npm或GitHub,供其他用户安装使用。良好的版本管理和文档编写对Plugin的长期维护至关重要。
5.1 发布到npm
Plugin作为npm包发布,用户可以全局安装后直接被Claude Code发现。
# 登录npm账号
npm login
# 构建项目(如有构建步骤)
npm run build
# 发布到npm
npm publish
# 用户安装
npm install -g claude-plugin-my-plugin
# 在settings.json中启用
// .claude/settings.json
{
"plugins": ["claude-plugin-my-plugin"]
}
说明: 发布前请确保 package.json 的 name 与 manifest.json 的 name 保持一致,方便Claude Code自动关联查找。
5.2 GitHub开源和README编写
在GitHub上开源Plugin可以吸引社区贡献者,提升Plugin的质量和功能。建议的README结构:
# claude-plugin-my-plugin
## 简介
简要描述Plugin的功能和使用场景。
## 安装
```bash
npm install -g claude-plugin-my-plugin
```
## 配置
在 `.claude/settings.json` 中启用:
```json
{
"plugins": ["claude-plugin-my-plugin"]
}
```
## 命令列表
- /hello [name] -- 打招呼
- /weather [city] -- 查询天气
## 权限说明
- read: 读取文件内容
- network: 调用外部API
## 开发
```bash
git clone https://github.com/username/claude-plugin-my-plugin
cd claude-plugin-my-plugin
npm install
```
## 许可证
MIT
5.3 版本号管理(SemVer)
遵循语义化版本(SemVer)规范管理Plugin版本:
| 版本号变更 |
说明 |
示例 |
| 主版本(MAJOR) |
不兼容的API变更 |
1.0.0 → 2.0.0 |
| 次版本(MINOR) |
向下兼容的功能新增 |
1.0.0 → 1.1.0 |
| 补丁(PATCH) |
向下兼容的问题修复 |
1.0.0 → 1.0.1 |
5.4 更新日志和迁移指南
在GitHub仓库中维护 CHANGELOG.md 文件,记录每个版本的变更内容,帮助用户了解升级带来的影响。
# Changelog
## [1.1.0] - 2026-05-08
### 新增
- 新增 /weather 命令,支持查询城市天气
- 新增文件变化监听功能,自动检测TODO标记
### 修复
- 修复 /hello 命令中文参数编码问题
- 修复文件监听器在Windows平台路径分隔符错误
## [1.0.0] - 2026-04-15
### 新增
- 基础Plugin框架搭建
- /hello 问候命令
- beforeCommand/afterCommand 生命周期钩子
- 上下文菜单"统计代码行数"动作
总结: 开发一个完整的Claude Code Plugin需要经过环境搭建、manifest配置、核心功能编码、测试调试、发布维护五个阶段。遵循标准化流程和最佳实践,可以大幅提高Plugin质量和开发效率。Plugin生态正在快速发展,掌握Plugin开发技能可以极大地扩展Claude Code的能力边界。