第13章:插件开发与扩展

概述

Claude Code 提供了灵活的插件架构,允许开发者扩展其核心功能。通过开发自定义插件,你可以将团队的工作流自动化、集成内部工具、或添加特定的代码分析规则。本章将从架构设计到发布部署,完整讲解 Claude Code 插件开发的各个环节。

Claude Code 插件架构概述

Claude Code 的插件系统基于事件驱动架构,插件可以在 Claude Code 生命周期的各个阶段注入自定义逻辑。

插件核心架构

┌─────────────────────────────────┐
│         Claude Code CLI         │
│  ┌───────────┐ ┌──────────────┐ │
│  │ 核心引擎   │ │ 插件管理器   │ │
│  └─────┬─────┘ └──────┬───────┘ │
│        │               │        │
│  ┌─────▼───────────────▼───────┐ │
│  │       插件注册表            │ │
│  │  ┌──────┐ ┌──────┐ ┌────┐ │ │
│  │  │插件A  │ │插件B  │ │... │ │ │
│  │  └──────┘ └──────┘ └────┘ │ │
│  └────────────────────────────┘ │
└─────────────────────────────────┘

插件生命周期

生命周期阶段触发时机典型用途
onInitClaude Code 启动时初始化配置,检查环境
onCommand用户输入命令时注册自定义命令
onFileOpen文件被打开时文件级分析
onFileSave文件保存时自动格式化或检查
onResponseAI 生成响应时后处理响应内容
onExitClaude 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 的深入理解,可以开发出更加智能和复杂的扩展来提升团队的整体开发效率。