第13章:插件开发与扩展
概述
Claude Code 提供了灵活的插件架构,允许开发者扩展其核心功能。通过开发自定义插件,你可以将团队的工作流自动化、集成内部工具、或添加特定的代码分析规则。本章将从架构设计到发布部署,完整讲解 Claude Code 插件开发的各个环节。
Claude Code 插件架构概述
Claude Code 的插件系统基于事件驱动架构,插件可以在 Claude Code 生命周期的各个阶段注入自定义逻辑。
插件核心架构
┌─────────────────────────────────┐
│ Claude Code CLI │
│ ┌───────────┐ ┌──────────────┐ │
│ │ 核心引擎 │ │ 插件管理器 │ │
│ └─────┬─────┘ └──────┬───────┘ │
│ │ │ │
│ ┌─────▼───────────────▼───────┐ │
│ │ 插件注册表 │ │
│ │ ┌──────┐ ┌──────┐ ┌────┐ │ │
│ │ │插件A │ │插件B │ │... │ │ │
│ │ └──────┘ └──────┘ └────┘ │ │
│ └────────────────────────────┘ │
└─────────────────────────────────┘
插件生命周期
| 生命周期阶段 | 触发时机 | 典型用途 |
|---|---|---|
onInit | Claude Code 启动时 | 初始化配置,检查环境 |
onCommand | 用户输入命令时 | 注册自定义命令 |
onFileOpen | 文件被打开时 | 文件级分析 |
onFileSave | 文件保存时 | 自动格式化或检查 |
onResponse | AI 生成响应时 | 后处理响应内容 |
onExit | Claude Code 退出时 | 清理资源,生成报告 |
插件 API 参考(关键接口说明)
核心接口定义
// 插件核心接口
interface ClaudeCodePlugin {
// 插件元数据
name: string;
version: string;
description: string;
// 初始化方法
init(context: PluginContext): Promise<void>;
// 生命周期钩子
hooks?: PluginHooks;
// 命令注册
commands?: PluginCommand[];
}
// 插件上下文
interface PluginContext {
config: ConfigManager;
logger: Logger;
fs: FileSystemAPI;
git: GitAPI;
ai: AIAPI;
workspace: Workspace;
}
// 生命周期钩子
interface PluginHooks {
onCommand?: (cmd: string, args: string[]) => Promise<void>;
onFileOpen?: (filePath: string) => Promise<void>;
onFileSave?: (filePath: string, content: string) => Promise<string>;
onResponse?: (response: string) => Promise<string>;
onExit?: () => Promise<void>;
}
// 命令定义
interface PluginCommand {
name: string;
description: string;
handler: (args: string[], ctx: PluginContext) => Promise<void>;
}
配置管理 API
// 配置管理接口
interface ConfigManager {
get(key: string): Promise<any>;
set(key: string, value: any): Promise<void>;
delete(key: string): Promise<void>;
getAll(): Promise<Record<string, any>>;
}
// AI 交互接口
interface AIAPI {
complete(prompt: string, options?: AIOptions): Promise<string>;
streamComplete(
prompt: string,
options?: AIOptions
): AsyncIterable<string>;
}
从零开发一个插件
让我们通过开发一个实际的代码质量检查插件,完整走一遍插件开发流程。
步骤一:项目初始化
# 创建插件项目目录
mkdir claude-code-quality-plugin
cd claude-code-quality-plugin
# 初始化 npm 项目
npm init -y
# 安装类型定义
npm install --save-dev typescript @types/node
步骤二:实现插件核心逻辑
// src/index.ts
import type {
ClaudeCodePlugin,
PluginContext,
PluginHooks,
PluginCommand,
} from "@anthropic-ai/claude-code-plugin-api";
interface QualityConfig {
maxFileLength: number;
checkComplexity: boolean;
complexityThreshold: number;
bannedPatterns: RegExp[];
}
class CodeQualityPlugin implements ClaudeCodePlugin {
name = "code-quality";
version = "1.0.0";
description = "代码质量自动检查插件";
private context!: PluginContext;
private config: QualityConfig = {
maxFileLength: 500,
checkComplexity: true,
complexityThreshold: 10,
bannedPatterns: [
/console.log(/,
/debugger;/,
/TODO:/i,
/FIXME:/i,
],
};
async init(context: PluginContext): Promise<void> {
this.context = context;
this.context.logger.info("代码质量插件已初始化");
// 加载用户自定义配置
const userConfig = await this.context.config.get("quality");
if (userConfig) {
this.config = { ...this.config, ...userConfig };
}
}
get hooks(): PluginHooks {
return {
onFileSave: this.onFileSave.bind(this),
onExit: this.onExit.bind(this),
};
}
get commands(): PluginCommand[] {
return [
{
name: "quality:check",
description: "检查当前文件的代码质量",
handler: async (args: string[], ctx: PluginContext) => {
const targetFile = args[0] || ctx.workspace.currentFile;
if (targetFile) {
await this.analyzeFile(targetFile);
}
},
},
{
name: "quality:report",
description: "生成项目代码质量报告",
handler: async (_args: string[], ctx: PluginContext) => {
await this.generateQualityReport(ctx);
},
},
];
}
private async onFileSave(
filePath: string,
content: string
): Promise<string> {
const issues: string[] = [];
// 检查文件长度
const lines = content.split("\n").length;
if (lines > this.config.maxFileLength) {
issues.push(
`⚠️ 文件过长:${lines} 行(建议 ≤${this.config.maxFileLength} 行)`
);
}
// 检查禁用模式
for (const pattern of this.config.bannedPatterns) {
const matches = content.match(pattern);
if (matches) {
issues.push(
`⚠️ 发现禁用代码模式:${pattern.source}`
);
}
}
if (issues.length > 0) {
this.context.logger.warn(
`[${filePath}] 发现 ${issues.length} 个问题:\n${issues.join("\n")}`
);
}
return content; // 返回修改后的内容(可选)
}
private async analyzeFile(filePath: string): Promise<void> {
const content = await this.context.fs.readFile(filePath);
const lines = content.split("\n");
// 分析复杂度
if (this.config.checkComplexity) {
const complexPatterns = [
/ifs*(/g,
/elses+if/g,
/fors*(/g,
/whiles*(/g,
/switchs*(/g,
/&&/g,
/\|\|/g,
/?\s/,
/catchs*(/g,
];
let score = 0;
for (const pattern of complexPatterns) {
const matches = content.match(pattern);
if (matches) score += matches.length;
}
if (score > this.config.complexityThreshold) {
this.context.logger.warn(
`复杂度得分 ${score},超过阈值 ${this.config.complexityThreshold}`
);
}
}
this.context.logger.info(
`分析完成:${filePath} - ${lines.length} 行`
);
}
private async generateQualityReport(ctx: PluginContext): Promise<void> {
const files = await ctx.workspace.listFiles("src/**/*.ts");
let totalIssues = 0;
let totalFiles = 0;
for await (const file of files) {
const content = await ctx.fs.readFile(file);
const lines = content.split("\n");
totalFiles++;
const fileIssues: string[] = [];
if (lines.length > this.config.maxFileLength) {
fileIssues.push("文件过长");
}
if (fileIssues.length > 0) {
totalIssues += fileIssues.length;
}
}
this.context.logger.info(
`📊 代码质量报告:检查 ${totalFiles} 个文件,发现 ${totalIssues} 个问题`
);
}
private async onExit(): Promise<void> {
await this.context.config.set("quality.lastRun", new Date().toISOString());
this.context.logger.info("代码质量插件已卸载");
}
}
export default new CodeQualityPlugin();
步骤三:插件配置文件
// package.json
{
"name": "claude-code-quality-plugin",
"version": "1.0.0",
"description": "代码质量自动检查插件",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"claude-code": {
"plugin": true,
"minVersion": "0.1.0",
"hooks": ["onFileSave", "onExit"],
"commands": ["quality:check", "quality:report"]
},
"scripts": {
"build": "tsc",
"prepublish": "npm run build"
},
"keywords": ["claude-code", "plugin", "code-quality"],
"license": "MIT"
}
插件配置与注册
在项目中注册插件
// .claude/plugins.json
{
"plugins": [
{
"name": "code-quality",
"path": "./plugins/claude-code-quality-plugin",
"enabled": true,
"config": {
"maxFileLength": 300,
"checkComplexity": true,
"complexityThreshold": 8,
"bannedPatterns": [
"console\.log\(",
"debugger;",
"TODO:"
]
}
},
{
"name": "custom-commands",
"source": "npm:@scope/claude-code-custom-commands",
"enabled": true,
"config": {}
}
]
}
全局安装插件
# 从 npm 安装
npm install -g claude-code-quality-plugin
# 从本地源码安装
npm link ./claude-code-quality-plugin
# 验证插件是否生效
claude --plugins
# 输出示例:
# 📦 已加载插件:
# - code-quality v1.0.0 (已启用)
# - custom-commands v0.2.1 (已启用)
# - legacy-helper v0.5.0 (已禁用)
插件发布与分享
发布到 npm
# 构建项目
npm run build
# 登录 npm
npm login
# 发布包
npm publish --access public
# 发布后,用户即可通过以下方式安装
npm install -g @your-scope/claude-code-quality-plugin
发布检查清单
| 检查项 | 说明 | 重要性 |
|---|---|---|
| 类型定义 | 提供完整的 .d.ts 文件 | 必需 |
| 错误处理 | 所有异步操作有 try-catch | 必需 |
| 日志输出 | 使用 PluginContext.logger | 推荐 |
| 配置校验 | 验证用户配置的合法性 | 推荐 |
| 性能优化 | 避免阻塞主线程 | 推荐 |
| 向后兼容 | 遵循语义化版本 | 必需 |
| 文档 | 提供 README 和示例 | 必需 |
本章小结
Claude Code 的插件系统为开发者提供了强大的扩展能力。通过本章的学习,你应该掌握了:
- 插件架构的核心概念和生命周期
- 关键 API 接口的使用方法
- 从零开发一个完整插件的流程
- 插件的配置、注册和发布方法
插件的价值在于将团队的开发规范和自动化流程固化到工具层面,让每个开发者都能享受到统一的质量保证。随着你对插件 API 的深入理解,可以开发出更加智能和复杂的扩展来提升团队的整体开发效率。