nkds

导航

 

MonkeyCode 插件生态与扩展机制:构建可插拔的 AI 编程助手架构实践指南

引言

"好的软件不是写出来的,而是生长出来的。"

在 AI 编程助手领域,单一产品无法满足所有开发者的需求。有人需要与特定框架深度集成,有人需要企业级合规检查,还有人希望将 AI 能力嵌入到自定义工作流中。这就是为什么 MonkeyCode 从设计之初就采用了插件化架构——让社区的力量成为产品进化的核心引擎。

作为完全开源的 AI 编程助手(Apache License 2.0),MonkeyCode 不仅开放了核心代码,更通过精心设计的插件 API 让每个人都能参与生态建设。本文将深入解析 MonkeyCode 的插件架构设计、开发实战、以及如何通过开源协作打造繁荣的开发者生态。

🎯 核心信息


一、为什么选择插件化架构?

1.1 插件化的核心价值

┌─────────────────────────────────────────────────────────────┐
│         MonkeyCode 插件化架构的核心价值                       │
│                                                             │
│  ┌─────────────────┐    ┌─────────────────┐                │
│  │   核心稳定性     │◄──►│   扩展灵活性     │                │
│  │                 │    │                 │                │
│  │ • AI 引擎稳定   │    │ • 社区创新       │                │
│  │ • 基础功能可靠  │    │ • 快速迭代       │                │
│  │ • 向后兼容      │    │ • 定制化需求     │                │
│  │ • 安全基线      │    │ • 长尾场景覆盖   │                │
│  └────────┬────────┘    └────────┬────────┘                │
│           │                      │                          │
│           └──────────┬───────────┘                          │
│                      ▼                                      │
│           ┌─────────────────────┐                           │
│           │   用户价值最大化     │                           │
│           │                     │                           │
│           │ 稳定 + 灵活 = 满意度  │                           │
│           └─────────────────────┘                           │
│                                                             │
│  💡 关键洞察: 核心做减法(聚焦),插件做加法(扩展)          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 架构选型对比

维度 单体架构 微服务架构 插件化架构 混合架构
部署复杂度 ⭐ 简单 ⭐⭐⭐ 复杂 ⭐⭐ 中等 ⭐⭐⭐ 复杂
扩展性 ❌ 差 ✅ 好 ✅✅ 优秀 ✅ 好
定制能力 ❌ 差 ✅ 中等 ✅✅ 优秀 ✅ 好
性能开销 ✅ 低 ⚠️ 中等 ✅ 低 ⚠️ 中等
隔离性 ❌ 无 ✅ 强 ⚠️ 部分 ✅ 强
社区参与 ❌ 困难 ⚠️ 中等 ✅✅ 容易 ⚠️ 中等
适用场景 小型工具 大型平台 桌面/IDE 工具 企业系统

MonkeyCode 选择插件化架构的理由:

  1. IDE 插件的天然属性: 本身就是 VSCode/JetBrains 的插件,用户对"插件"概念熟悉
  2. 本地运行优先: 大部分计算在本地完成,不需要微服务的网络开销
  3. 开发者友好: 降低贡献门槛,一个插件文件即可扩展功能
  4. 安全可控: 插件运行在沙箱中,不影响核心功能稳定性

二、MonkeyCode 插件架构总览

2.1 整体架构图

┌─────────────────────────────────────────────────────────────────────────┐
│                    MonkeyCode 插件架构全景图                              │
│                                                                         │
│  ══════════════════════════════════════════════════════════════════    │
│                                                                         │
│  【用户层】                                                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │ VSCode   │  │JetBrains │  │  Vim/    │  │  CLI /   │              │
│  │  插件    │  │  插件    │  │ Neovim   │  │  Headless │              │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘              │
│       └──────────────┴────────────┴──────────────┘                     │
│                            │                                           │
│  ═════════════════════════╧═══════════════════════════════════════    │
│                                                                         │
│  【宿主层 — Host Layer】                                                  │
│  ┌──────────────────────────────────────────────────────────────┐      │
│  │                    MonkeyCode Core                           │      │
│  │                                                              │      │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐          │      │
│  │  │ Plugin Host │  │  LLM Engine │  │ Config Mgr  │          │      │
│  │  │  (管理器)   │  │  (AI 核心)  │  │ (配置中心)  │          │      │
│  │  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘          │      │
│  │         │                │                │                  │      │
│  │  ┌──────┴────────────────┴────────────────┴──────┐          │      │
│  │  │            Event Bus (事件总线)               │          │      │
│  │  └───────────────────────────────────────────────┘          │      │
│  └──────────────────────────────────────────────────────────────┘      │
│                            │                                           │
│  ═════════════════════════╧═══════════════════════════════════════    │
│                                                                         │
│  【插件层 — Plugin Layer】                                                │
│  ┌──────────────────────────────────────────────────────────────┐      │
│  │                                                              │      │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐             │      │
│  │  │ Language   │  │ Framework  │  │ Compliance │             │      │
│  │  │ Server     │  │ Adapter    │  │ Checker    │             │      │
│  │  │ (语言服务) │  │ (框架适配) │  │ (合规检查) │             │      │
│  │  └────────────┘  └────────────┘  └────────────┘             │      │
│  │                                                              │      │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐             │      │
│  │  │ Code Style │  │ Custom     │  │ Analytics  │             │      │
│  │  │ Enforcer   │  │ Command    │  │ Reporter   │             │      │
│  │  │ (代码风格) │  │ (自定义命令)│  │ (分析报告) │             │      │
│  │  └────────────┘  └────────────┘  └────────────┘             │      │
│  │                                                              │      │
│  │  ┌────────────┐  ┌────────────┐                             │      │
│  │  │ Integration│  │ Theme / UI │                             │      │
│  │  │ Bridge     │  │ Extension  │                             │      │
│  │  │ (集成桥接) │  │ (主题/UI)  │                             │      │
│  │  └────────────┘  └────────────┘                             │      │
│  │                                                              │      │
│  └──────────────────────────────────────────────────────────────┘      │
│                                                                         │
│  ══════════════════════════════════════════════════════════════════    │
│                                                                         │
│  【基础设施层】                                                           │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐              │
│  │ Plugin   │  │ Sandbox  │  │ Version  │  │ Hot      │              │
│  │ Registry │  │ Runtime  │  │ Resolver │  │ Reload   │              │
│  │ (注册中心)│  │ (沙箱)   │  │ (版本解析)│  │ (热加载) │              │
│  └──────────┘  └──────────┘  └──────────┘  └──────────┘              │
│                                                                         │
╚═══════════════════════════════════════════════════════════════════════╝

2.2 核心组件说明

// ===== monkeycode/plugins/core/types.ts =====
/**
 * MonkeyCode 插件系统核心类型定义
 */

/** 插件元数据 */
export interface PluginManifest {
  /** 插件唯一标识符 (反向域名格式) */
  id: string;  // e.g., "com.example.my-plugin"
  
  /** 显示名称 */
  name: string;
  
  /** 版本号 (语义化版本) */
  version: string;  // e.g., "1.2.3"
  
  /** 描述 */
  description: string;
  
  /** 作者信息 */
  author: {
    name: string;
    email?: string;
    url?: string;
  };
  
  /** 许可证 */
  license: string;
  
  /** 主入口文件 */
  main: string;
  
  /** MonkeyCode 版本兼容性 */
  engines: {
    monkeycode: string;  // semver range, e.g., ">=2.0.0 <3.0.0"
  };
  
  /** 插件类别 */
  category: PluginCategory;
  
  /** 关键词 (用于搜索) */
  keywords?: string[];
  
  /** 依赖的其他插件 */
  dependencies?: string[];
  
  /** 可选依赖 */
  peerDependencies?: string[];
  
  /** 贡献点声明 */
  contributes?: {
    commands?: CommandContribution[];
    views?: ViewContribution[];
    hooks?: HookContribution[];
    configurations?: ConfigurationContribution[];
    languages?: LanguageContribution[];
    themes?: ThemeContribution[];
  };
  
  /** 插件图标 (SVG 或 URL) */
  icon?: string;
  
  /** 首页链接 */
  homepage?: string;
  
  /** 仓库地址 */
  repository?: {
    type: 'git';
    url: string;
  };
  
  /** Bug 反馈地址 */
  bugs?: {
    url: string;
    email?: string;
  };
}

/** 插件类别枚举 */
export enum PluginCategory {
  LANGUAGE_SERVER = 'language-server',       // 语言服务
  FRAMEWORK_ADAPTER = 'framework-adapter',   // 框架适配
  COMPLIANCE = 'compliance',                 // 合规检查
  CODE_STYLE = 'code-style',                 // 代码风格
  CUSTOM_COMMAND = 'custom-command',         // 自定义命令
  ANALYTICS = 'analytics',                   // 数据分析
  INTEGRATION = 'integration',               // 第三方集成
  THEME = 'theme',                           // 主题/UI
  UTILITY = 'utility'                        // 工具类
}

/** 插件上下文 — 运行时注入给插件 */
export interface PluginContext {
  /** 插件自身的元数据 */
  readonly manifest: PluginManifest;
  
  /** 日志记录器 */
  logger: PluginLogger;
  
  /** 配置访问器 */
  config: ConfigurationAccessor;
  
  /** 状态存储 */
  state: StateStorage;
  
  /** 事件总线订阅 */
  subscriptions: Disposable[];
  
  /** 访问核心 API */
  core: {
    /** AI 引擎接口 */
    ai: AIEngineAPI;
    /** 编辑器接口 */
    editor: EditorAPI;
    /** 文件系统接口 */
    filesystem: FileSystemAPI;
    /** 终端接口 */
    terminal: TerminalAPI;
    /** UI 接口 */
    ui: UIAPI;
  };
}

/** 插件激活函数类型 */
export type ActivateFunction = (
  context: PluginContext
) => Promise<PluginResult | void>;

/** 插件停用函数类型 */
export type DeactivateFunction = () => Promise<void> | void;

/** 插件入口导出 */
export interface PluginModule {
  activate: ActivateFunction;
  deactivate?: DeactivateFunction;
}

2.3 事件驱动通信模型

// ===== monkeycode/plugins/core/event-bus.ts =====
/**
 * MonkeyCode 插件事件总线
 * 
 * 所有插件间通信都通过事件总线进行,
 * 确保松耦合和可追溯性。
 */

import { EventEmitter } from 'events';

/** 定义所有可用的事件类型 */
export enum PluginEventType {
  // === 生命周期事件 ===
  PLUGIN_ACTIVATED = 'plugin:activated',
  PLUGIN_DEACTIVATED = 'plugin:deactivated',
  PLUGIN_ERROR = 'plugin:error',
  
  // === 编辑器事件 ===
  EDITOR_FILE_OPENED = 'editor:fileOpened',
  EDITOR_FILE_SAVED = 'editor:fileSaved',
  EDITOR_SELECTION_CHANGED = 'editor:selectionChanged',
  EDITOR_CURSOR_MOVED = 'editor:cursorMoved',
  
  // === AI 事件 ===
  AI_COMPLETION_REQUESTED = 'ai:completionRequested',
  AI_COMPLETION_RECEIVED = 'ai:completionReceived',
  AI_EXPLANATION_REQUESTED = 'ai:explanationRequested',
  AI_REVIEW_STARTED = 'ai:reviewStarted',
  AI_REVIEW_COMPLETED = 'ai:reviewCompleted',
  
  // === 配置事件 ===
  CONFIG_CHANGED = 'config:changed',
  
  // === 自定义事件 (前缀 'custom:') ===
  // custom:* 允许插件定义自己的事件
}

/** 事件载荷基础接口 */
export interface BaseEventPayload {
  timestamp: number;
  sourcePluginId: string;
  sourceVersion: string;
}

/** 编辑器文件打开事件 */
export interface FileOpenedEventPayload extends BaseEventPayload {
  filePath: string;
  languageId: string;
  fileSize: number;
  encoding: string;
}

/** AI 补全请求事件 */
export interface CompletionEventPayload extends BaseEventPayload {
  requestId: string;
  filePath: string;
  position: { line: number; column: number };
  prefix: string;
  suffix: string;
  modelUsed: string;
  latencyMs?: number;
  result?: string;
  error?: string;
}

class PluginEventBus extends EventEmitter {
  private eventLog: Array<{
    type: PluginEventType;
    payload: BaseEventPayload;
    timestamp: number;
  }> = [];
  
  private maxLogSize = 10000;
  
  /**
   * 发布事件
   */
  emit<T extends BaseEventPayload>(
    eventType: PluginEventType,
    payload: T
  ): boolean {
    // 记录事件日志
    this.eventLog.push({
      type: eventType,
      payload,
      timestamp: Date.now(),
    });
    
    // 防止日志无限增长
    if (this.eventLog.length > this.maxLogSize) {
      this.eventLog = this.eventLog.slice(-this.maxLogSize / 2);
    }
    
    return super.emit(eventType, payload);
  }
  
  /**
   * 订阅事件 (带自动清理)
   */
  subscribe<T extends BaseEventPayload>(
    eventType: PluginEventType,
    handler: (payload: T) => void,
    pluginId: string
  ): () => void {
    const wrappedHandler = (payload: T) => {
      try {
        handler(payload);
      } catch (error) {
        console.error(
          `[EventBus] Error in handler for ${eventType} ` +
          `from plugin ${pluginId}:`,
          error
        );
        // 通知错误
        this.emit(PluginEventType.PLUGIN_ERROR, {
          timestamp: Date.now(),
          sourcePluginId: pluginId,
          sourceVersion: 'unknown',
          error: error instanceof Error ? error.message : String(error),
          eventType,
        } as any);
      }
    };
    
    super.on(eventType, wrappedHandler);
    
    // 返回取消订阅函数
    return () => super.off(eventType, wrappedHandler);
  }
  
  /**
   * 获取事件历史 (用于调试)
   */
  getRecentEvents(count = 50): typeof this.eventLog {
    return this.eventLog.slice(-count);
  }
  
  /**
   * 获取特定插件的事件统计
   */
  getPluginStats(pluginId: string): {
    emitted: number;
    subscribed: string[];
  } {
    const emitted = this.eventLog.filter(
      e => e.payload.sourcePluginId === pluginId
    ).length;
    
    return { emitted, subscribed: [] }; // 简化实现
  }
}

// 全局单例
export const globalEventBus = new PluginEventBus();
export default globalEventBus;

三、插件开发实战指南

3.1 最小可行插件 (MVP)

// ===== my-first-plugin/package.json =====
{
  "name": "@monkeycode/hello-world",
  "version": "1.0.0",
  "description": "我的第一个 MonkeyCode 插件 — Hello World 示例",
  "main": "index.js",
  "monkeyCode": {
    "id": "dev.example.hello-world",
    "displayName": "Hello World",
    "description": "一个简单的示例插件,展示插件开发的基本流程",
    "category": "utility",
    "engines": {
      "monkeyCode": ">=2.0.0"
    },
    "contributes": {
      "commands": [
        {
          "command": "helloWorld.sayHello",
          "title": "Say Hello",
          "category": "Hello World"
        },
        {
          "command": "helloWorld.showInfo",
          "title": "Show Plugin Info",
          "category": "Hello World"
        }
      ]
    }
  },
  "keywords": ["hello-world", "example", "tutorial"],
  "author": {
    "name": "Your Name",
    "email": "your@email.com"
  },
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/yourname/my-first-plugin.git"
  }
}
// ===== my-first-plugin/index.js =====
/**
 * MonkeyCode Hello World 插件
 * 
 * 这是一个最小可行的插件示例,
 * 展示了插件的基本结构和生命周期。
 */

// 插件激活函数 — 当插件被加载时调用
async function activate(context) {
  const { logger, core, subscriptions } = context;
  
  // ========== 1. 注册命令 ==========
  
  // 注册 "Say Hello" 命令
  const helloDisposable = core.ui.registerCommand(
    'helloWorld.sayHello',
    async () => {
      // 使用 AI 引擎生成个性化问候
      const greeting = await core.ai.chatCompletion({
        messages: [
          {
            role: 'system',
            content: '你是一个友好的编程助手。用温暖的方式问候开发者。'
          },
          {
            role: 'user',
            content: '请用一种有趣的方式向开发者打招呼!'
          }
        ],
        temperature: 0.8,
        maxTokens: 100
      });
      
      // 在编辑器中显示问候语
      core.ui.showInformationMessage(
        `🐵 ${greeting.choices[0].message.content}\n\n` +
        `— 来自 Hello World 插件 v${context.manifest.version}`
      );
      
      logger.info('Hello command executed');
    }
  );
  subscriptions.push(helloDisposable);
  
  // 注册 "Show Info" 命令
  const infoDisposable = core.ui.registerCommand(
    'helloWorld.showInfo',
    async () => {
      const info = [
        `📦 插件名称: ${context.manifest.name}`,
        `🆔 插件 ID: ${context.manifest.id}`,
        `📌 版本: ${context.manifest.version}`,
        `👤 作者: ${context.manifest.author.name}`,
        `📄 许可证: ${context.manifest.license}`,
        '',
        '感谢您使用 MonkeyCode 插件系统!',
        '',
        '💡 提示: 访问 https://github.com/monkeycode-ai/monkeycode ' +
        '了解更多插件开发信息'
      ].join('\n');
      
      core.ui.showInformationMessage(info);
    }
  );
  subscriptions.push(infoDisposable);
  
  // ========== 2. 监听事件 ==========
  
  // 监听文件保存事件
  const saveSubscription = context.subscribe(
    'editor:fileSaved',
    async (payload) => {
      logger.debug(`File saved: ${payload.filePath}`);
      
      // 可选: 对保存的文件做一些处理
      // 例如: 自动添加文件头注释、格式检查等
    }
  );
  subscriptions.push(saveSubscription);
  
  // ========== 3. 初始化状态 ==========
  
  // 读取或初始化插件状态
  let usageCount = await context.state.get('usageCount') || 0;
  await context.state.set('usageCount', usageCount);
  
  logger.info(`Plugin "${context.manifest.name}" activated successfully`);
  logger.info(`Usage count so far: ${usageCount}`);
  
  // 返回插件结果 (可选)
  return {
    status: 'ok',
    message: 'Hello World plugin is ready to use!',
  };
}

// 插件停用函数 — 当插件被卸载时调用
async function deactivate() {
  // 清理资源 (subscriptions 会由框架自动清理)
  console.log('Hello World plugin deactivated');
}

// 导出插件模块
module.exports = {
  activate,
  deactivate
};

3.2 进阶:语言服务插件

// ===== monkeycode-plugin-rust/index.ts =====
/**
 * MonkeyCode Rust 语言支持插件
 * 
 * 为 Rust 语言提供增强的 AI 编程支持:
 * - Rust 特有的代码补全优化
 * - Cargo.toml 依赖智能感知
 * - Macro 展开辅助
 * - 生命周期标注建议
 */

import {
  PluginContext,
  PluginResult,
  LanguageServerPlugin,
  CompletionItem,
  Diagnostic,
} from '@monkeycode/plugin-api';

interface RustPluginConfig {
  enableMacroExpansion: boolean;
  suggestLifetimeAnnotations: boolean;
  cargoIntegrationEnabled: boolean;
  rustAnalyzerPath?: string;
}

export async function activate(context: PluginContext): Promise<PluginResult> {
  const { logger, config, core, state } = context;
  
  // 读取配置
  const pluginConfig = config.get<RustPluginConfig>('rustSupport') ?? {
    enableMacroExpansion: true,
    suggestLifetimeAnnotations: true,
    cargoIntegrationEnabled: true,
  };
  
  logger.info('Rust support plugin activating...', pluginConfig);
  
  // ========== 1. 注册 Rust 语言特性 ==========
  
  // 注册 Rust 特定的补全提供器
  const rustCompletionProvider = core.ai.registerCompletionProvider(
    ['rust'],  // 仅对 Rust 文件生效
    {
      // 在触发补全前,先收集 Rust 上下文
      async beforeCompletion(document, position) {
        const fileContent = document.getText();
        
        // 解析当前作用域
        const scopeInfo = analyzeRustScope(fileContent, position);
        
        // 如果在 macro!() 内部,提供 macro 相关提示
        if (scopeInfo.insideMacro && pluginConfig.enableMacroExpansion) {
          return {
            contextHints: {
              insideMacro: true,
              macroName: scopeInfo.macroName,
              availableMacros: getAvailableMacros(fileContent),
            },
            promptOverride: buildMacroPrompt(scopeInfo),
          };
        }
        
        // 如果在 struct 定义附近,建议 derive 属性
        if (scopeInfo.nearStructDef) {
          return {
            contextHints: {
              nearStructDef: true,
              suggestedDerives: [
                'Debug', 'Clone', 'PartialEq', 'Eq',
                'Hash', 'Serialize', 'Deserialize',
              ],
            },
          };
        }
        
        return { contextHints: scopeInfo };
      },
      
      // 后处理 AI 生成的补全结果
      async afterCompletion(items: CompletionItem[]): Promise<CompletionItem[]> {
        return items.map(item => {
          // 给 Rust 特定补全添加额外信息
          if (item.label.startsWith('fn ') || item.label.startsWith('pub fn ')) {
            item.detail = '🦀 Rust Function';
          }
          
          // 为 lifetime 参数添加特殊标记
          if (item.label.includes("'")) {
            item.documentation = {
              value: '**Lifetime Parameter**\n\n' +
                '此补全包含 Rust 生命周期参数。\n' +
                '确保使用正确的生命周期标注以避免编译错误。',
              kind: 'markdown',
            };
          }
          
          return item;
        });
      },
    }
  );
  
  // ========== 2. Cargo.toml 集成 ==========
  
  if (pluginConfig.cargoIntegrationEnabled) {
    // 监听 Cargo.toml 变化,自动更新依赖上下文
    const cargoWatcher = core.filesystem.watchFiles(
      '**/Cargo.toml',
      async (uri) => {
        logger.info(`Cargo.toml changed: ${uri}`);
        
        const cargoContent = await core.filesystem.readFile(uri);
        const deps = parseCargoDependencies(cargoContent);
        
        // 将依赖信息存入状态供后续使用
        await state.set('cargoDependencies', deps);
        
        logger.info(`Parsed ${deps.length} dependencies from Cargo.toml`);
      }
    );
    
    context.subscriptions.push(cargoWatcher);
  }
  
  // ========== 3. 诊断增强 ==========
  
  // 注册 Rust 编译器错误增强解释器
  const diagnosticEnhancer = core.editor.registerDiagnosticEnhancer(
    ['rust'],
    async (diagnostic: Diagnostic) => {
      // 只对借用检查器和生命周期错误使用 AI 增强
      if (
        diagnostic.code === 'E0502' ||  // cannot borrow as mutable
        diagnostic.code === 'E0597' ||  // does not live long enough
        diagnostic.code.startsWith('E0') && 
        diagnostic.message.includes('lifetime')
      ) {
        // 使用 AI 解释这个 Rust 错误并提供修复建议
        const explanation = await core.ai.chatCompletion({
          messages: [
            {
              role: 'system',
              content: `你是 Rust 专家。请用中文简洁地解释以下 Rust 编译错误,
                        并给出具体的修复代码示例。`
            },
            {
              role: 'user',
              content: `错误代码: ${diagnostic.code}\n` +
                       `错误信息: ${diagnostic.message}\n` +
                       `所在行: ${diagnostic.range.start.line}`
            }
          ],
          temperature: 0.3,
          maxTokens: 500,
        });
        
        return {
          ...diagnostic,
          enhancedMessage: explanation.choices[0].message.content,
          severity: 'info',  // 降低严重程度,因为已有了解释
          actions: [
            {
              title: '查看详细解释',
              command: 'rust.showBorrowExplanation',
              arguments: [diagnostic],
            },
            {
              title: '生成修复方案',
              command: 'rust.generateFix',
              arguments: [diagnostic],
            },
          ],
        };
      }
      
      return diagnostic;
    }
  );
  
  context.subscriptions.push(diagnosticEnhancer);
  
  // ========== 4. 注册自定义命令 ==========
  
  context.subscriptions.push(
    core.ui.registerCommand('rust.expandMacro', async () => {
      const editor = core.editor.activeEditor;
      if (!editor || editor.languageId !== 'rust') {
        core.ui.showWarningMessage('请在 Rust 文件中使用此命令');
        return;
      }
      
      const selection = editor.selection;
      const selectedText = editor.document.getText(selection);
      
      // 使用 AI 展开 macro
      const expansion = await core.ai.chatCompletion({
        messages: [
          {
            role: 'system',
            content: '你是 Rust macro 展开专家。展开给定的 Rust macro 调用。'
          },
          {
            role: 'user',
            content: `请展开以下 Rust macro:\n\`\`\`rust\n${selectedText}\n\`\`\``
          }
        ],
        temperature: 0.1,
      });
      
      // 显示展开结果
      core.ui.showDiffView(selectedText, expansion.choices[0].message.content, {
        title: 'Macro Expansion Result',
      });
    })
  );
  
  logger.info('✅ Rust support plugin activated successfully');
  
  return {
    status: 'ok',
    features: [
      'Rust-aware code completion',
      'Cargo.toml integration',
      'Borrow checker error explanation',
      'Macro expansion assistant',
    ],
  };
}

// ========== 辅助函数 ==========

function analyzeRustScope(content: string, position: { line: number; column: number }) {
  // 简化的 Rust 作用域分析
  const lines = content.split('\n');
  const currentLine = lines[position.line] || '';
  
  return {
    insideMacro: /(\w+)!\s*\(/.test(currentLine),
    macroName: currentLine.match(/(\w+)!/)?.[1],
    nearStructDef: /\bstruct\s+\w+/.test(currentLine),
    insideImpl: /^\s*(pub\s+)?(unsafe\s+)?(async\s+)?fn\s+/.test(currentLine),
  };
}

function getAvailableMacros(content: string): string[] {
  const macroRegex = /macro_rules!\s+(\w+)/g;
  const macros: string[] = [];
  let match;
  while ((match = macroRegex.exec(content)) !== null) {
    macros.push(match[1]);
  }
  return macros;
}

function buildMacroPrompt(scope: any): string {
  return `You are completing Rust code inside the macro "${scope.macroName}".
Available macros in scope: ${scope.availableMacros.join(', ')}.`;
}

function parseCargoDependencies(content: string): Array<{name: string, version: string}> {
  // 简化的 Cargo.toml 解析
  const deps: Array<{name: string, version: string}> = [];
  const depRegex = /^(\w+)\s*=\s*["']([^"']+)["']/gm;
  let match;
  while ((match = depRegex.exec(content)) !== null) {
    deps.push({ name: match[1], version: match[2] });
  }
  return deps;
}

export async function deactivate() {
  console.log('Rust support plugin deactivated');
}

3.3 企业级合规检查插件

# ===== monkeycode_plugin_compliance/compliance_checker.py =====
"""
MonkeyCode 企业级合规检查插件

功能:
- 代码安全扫描 (SQL注入/XSS/硬编码密钥等)
- 许可证兼容性检查
- PII (个人隐私数据) 检测
- 编码规范强制执行
- 自定义规则引擎
"""

import re
import json
import hashlib
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from enum import Enum


class Severity(Enum):
    INFO = "info"
    WARNING = "warning"
    ERROR = "error"
    CRITICAL = "critical"


class RuleCategory(Enum):
    SECURITY = "security"
    PRIVACY = "privacy"
    LICENSE = "license"
    CODE_STYLE = "code_style"
    PERFORMANCE = "performance"
    CUSTOM = "custom"


@dataclass
class ComplianceRule:
    """合规规则定义"""
    rule_id: str
    name: str
    description: str
    category: RuleCategory
    severity: Severity
    pattern: re.Pattern  # 正则表达式模式
    suggestion: str
    enabled: bool = True
    languages: List[str] = field(default_factory=lambda: ["*"])
    tags: List[str] = field(default_factory=list)


@dataclass
class ComplianceIssue:
    """合规问题"""
    rule_id: str
    file_path: str
    line_number: int
    column: int
    severity: Severity
    message: str
    suggestion: str
    snippet: str
    category: RuleCategory
    auto_fix_available: bool = False
    fix_suggestion: Optional[str] = None


# 内置规则库
BUILTIN_RULES = [
    # 安全类规则
    ComplianceRule(
        rule_id="SEC001",
        name="硬编码密码检测",
        description="检测代码中的硬编码密码和密钥",
        category=RuleCategory.SECURITY,
        severity=Severity.CRITICAL,
        pattern=re.compile(
            r'(?:password|passwd|pwd|secret|api_key|apikey|token)\s*[=:]\s*["\'][^"\']{8,}["\']',
            re.IGNORECASE
        ),
        suggestion="使用环境变量或密钥管理服务存储敏感信息",
        tags=["security", "credentials", "owasp"],
    ),
    ComplianceRule(
        rule_id="SEC002",
        name="SQL 注入风险检测",
        description="检测可能的 SQL 注入漏洞",
        category=RuleCategory.SECURITY,
        severity=Severity.ERROR,
        pattern=re.compile(
            r'(?:execute|query|raw)\s*\(\s*(?:f["\']|["\'].*%\s*(?:s|d)|"\s*\+)',
            re.IGNORECASE
        ),
        suggestion="使用参数化查询或 ORM 来防止 SQL 注入",
        languages=["python", "javascript", "java", "php"],
        tags=["security", "sql-injection", "owasp"],
    ),
    ComplianceRule(
        rule_id="SEC003",
        name="XSS 风险检测",
        description="检测可能的跨站脚本攻击风险",
        category=RuleCategory.SECURITY,
        severity=Severity.ERROR,
        pattern=re.compile(
            r'(?:innerHTML|document\.write|\.html\(|v-html)\s*\(',
            re.IGNORECASE
        ),
        suggestion="使用安全的 DOM 操作方法或文本内容插入",
        languages=["javascript", "typescript"],
        tags=["security", "xss", "owasp"],
    ),
    ComplianceRule(
        rule_id="SEC004",
        name="不安全的随机数生成",
        description="检测使用了不安全的伪随机数生成器",
        category=RuleCategory.SECURITY,
        severity=Severity.WARNING,
        pattern=re.compile(
            r'\b(?:random|Math\.random)\s*\(',
            re.IGNORECASE
        ),
        suggestion="对于安全敏感的场景,使用加密安全的随机数生成器",
        tags=["security", "cryptography"],
    ),
    
    # 隐私类规则
    ComplianceRule(
        rule_id="PRV001",
        name="个人身份信息 (PII) 检测",
        description="检测代码中可能包含的个人隐私数据",
        category=RuleCategory.PRIVACY,
        severity=Severity.WARNING,
        pattern=re.compile(
            r'(?:email|phone|id_card|ssn|credit_card|身份证|手机号|邮箱)\s*[=:]\s*["\']',
            re.IGNORECASE
        ),
        suggestion="确保 PII 数据经过脱敏处理后再使用或存储",
        tags=["privacy", "gdpr", "pii"],
    ),
    ComplianceRule(
        rule_id="PRV002",
        name="日志中的敏感数据",
        description="检测可能将敏感数据写入日志的代码",
        category=RuleCategory.PRIVACY,
        severity=Severity.WARNING,
        pattern=re.compile(
            r'(?:logger|log|console\.(log|debug|info))\s*\([^)]*(?:password|token|secret)',
            re.IGNORECASE
        ),
        suggestion="不要在日志中输出敏感信息",
        tags=["privacy", "logging"],
    ),
    
    # 许可证类规则
    ComplianceRule(
        rule_id="LIC001",
        name="许可证头缺失检测",
        description="检测源文件是否缺少许可证声明",
        category=RuleCategory.LICENSE,
        severity=Severity.INFO,
        pattern=re.compile(r'^$', re.MULTILINE),  # 特殊处理
        suggestion="在每个源文件头部添加 SPDX 许可证标识",
        languages=["python", "javascript", "java", "go", "rust"],
        tags=["license", "spdx", "compliance"],
    ),
    
    # 代码质量规则
    ComplianceRule(
        rule_id="STY001",
        name="TODO/FIXME/HACK 检测",
        description="检测代码中的技术债务标记",
        category=RuleCategory.CODE_STYLE,
        severity=Severity.INFO,
        pattern=re.compile(
            r'#?\s*(TODO|FIXME|HACK|XXX|BUG|TEMP)\s*[:\-]?',
            re.IGNORECASE
        ),
        suggestion="为每个 TODO 创建 Issue 并设置截止日期",
        tags=["tech-debt", "code-quality"],
    ),
    ComplianceRule(
        rule_id="STY002",
        name="调试代码残留检测",
        description="检测可能遗留的调试代码",
        category=RuleCategory.CODE_STYLE,
        severity=Severity.WARNING,
        pattern=re.compile(
            r'(?:console\.(log|debug|warn)|print\s*\(|debugger|pdb\.set_trace)',
            re.IGNORECASE
        ),
        suggestion="移除调试代码后再提交到生产分支",
        languages=["python", "javascript", "typescript"],
        tags=["debugging", "code-quality"],
    ),
]


class ComplianceChecker:
    """MonkeyCode 合规检查引擎"""
    
    def __init__(self):
        self.rules: Dict[str, ComplianceRule] = {}
        self.custom_rules: List[ComplianceRule] = []
        self._load_builtin_rules()
    
    def _load_builtin_rules(self):
        """加载内置规则"""
        for rule in BUILTIN_RULES:
            self.rules[rule.rule_id] = rule
    
    def add_custom_rule(self, rule: ComplianceRule):
        """添加自定义规则"""
        self.custom_rules.append(rule)
        self.rules[rule.rule_id] = rule
    
    def remove_rule(self, rule_id: str):
        """移除规则"""
        if rule_id in self.rules:
            del self.rules[rule_id]
    
    def scan_file(
        self,
        file_path: str,
        content: str,
        language: str = "text",
        enabled_categories: Optional[List[RuleCategory]] = None,
        min_severity: Severity = Severity.INFO,
    ) -> List[ComplianceIssue]:
        """
        扫描单个文件
        
        Args:
            file_path: 文件路径
            content: 文件内容
            language: 编程语言
            enabled_categories: 启用的规则类别 (None 表示全部启用)
            min_severity: 最低报告级别
            
        Returns:
            发现的问题列表
        """
        issues: List[ComplianceIssue] = []
        lines = content.split('\n')
        
        for rule_id, rule in self.rules.items():
            if not rule.enabled:
                continue
            
            # 类别过滤
            if enabled_categories and rule.category not in enabled_categories:
                continue
            
            # 严重级别过滤
            severity_order = {
                Severity.INFO: 0,
                Severity.WARNING: 1,
                Severity.ERROR: 2,
                Severity.CRITICAL: 3,
            }
            if severity_order.get(rule.severity, 0) < severity_order.get(min_severity, 0):
                continue
            
            # 语言过滤
            if "*" not in rule.languages and language.lower() not in [l.lower() for l in rule.languages]:
                continue
            
            # 特殊处理: 许可证头检测
            if rule.rule_id == "LIC001":
                if not self._has_license_header(content[:500]):
                    issues.append(ComplianceIssue(
                        rule_id=rule.rule_id,
                        file_path=file_path,
                        line_number=1,
                        column=1,
                        severity=rule.severity,
                        message=f"{rule.name}: {rule.description}",
                        suggestion=rule.suggestion,
                        snippet=lines[0] if lines else "",
                        category=rule.category,
                    ))
                continue
            
            # 正则匹配
            for line_num, line in enumerate(lines, start=1):
                matches = rule.pattern.finditer(line)
                for match in matches:
                    issues.append(ComplianceIssue(
                        rule_id=rule.rule_id,
                        file_path=file_path,
                        line_number=line_num,
                        column=match.start() + 1,
                        severity=rule.severity,
                        message=f"{rule.name}: {rule.description}",
                        suggestion=rule.suggestion,
                        snippet=line.strip(),
                        category=rule.category,
                        auto_fix_available=self._can_auto_fix(rule.rule_id),
                        fix_suggestion=self._get_auto_fix(rule.rule_id, match),
                    ))
        
        return issues
    
    def scan_project(
        self,
        files: Dict[str, Dict[str, str]],
        enabled_categories: Optional[List[RuleCategory]] = None,
        min_severity: Severity = Severity.WARNING,
    ) -> Dict[str, Any]:
        """
        扫描整个项目
        
        Args:
            files: {file_path: {"content": "...", "language": "..."}}
            enabled_categories: 启用的规则类别
            min_severity: 最低报告级别
            
        Returns:
            扫描结果摘要
        """
        all_issues: List[ComplianceIssue] = []
        file_count = len(files)
        
        for file_path, file_info in files.items():
            issues = self.scan_file(
                file_path=file_path,
                content=file_info["content"],
                language=file_info.get("language", "text"),
                enabled_categories=enabled_categories,
                min_severity=min_severity,
            )
            all_issues.extend(issues)
        
        # 统计
        stats = {
            "total_files_scanned": file_count,
            "total_issues_found": len(all_issues),
            "by_severity": {},
            "by_category": {},
            "by_file": {},
            "by_rule": {},
        }
        
        for issue in all_issues:
            # 按严重程度统计
            sev = issue.severity.value
            stats["by_severity"][sev] = stats["by_severity"].get(sev, 0) + 1
            
            # 按类别统计
            cat = issue.category.value
            stats["by_category"][cat] = stats["by_category"].get(cat, 0) + 1
            
            # 按文件统计
            if issue.file_path not in stats["by_file"]:
                stats["by_file"][issue.file_path] = []
            stats["by_file"][issue.file_path].append(issue)
            
            # 按规则统计
            if issue.rule_id not in stats["by_rule"]:
                stats["by_rule"][issue.rule_id] = 0
            stats["by_rule"][issue.rule_id] += 1
        
        # 计算合规评分
        score = self._calculate_compliance_score(stats, file_count)
        
        return {
            "summary": stats,
            "issues": [self._issue_to_dict(i) for i in all_issues],
            "compliance_score": score,
            "recommendations": self._generate_recommendations(stats),
            "scan_timestamp": __import__("datetime").datetime.now().isoformat(),
        }
    
    def _has_license_header(self, header_content: str) -> bool:
        """检查是否有许可证头"""
        license_patterns = [
            r'SPDX-License-Identifier:',
            r'Copyright\s+[©c]',
            r'Licensed under the',
            r'MIT License',
            r'Apache License',
            r'GPL',
            r'BSD',
        ]
        for pattern in license_patterns:
            if re.search(pattern, header_content, re.IGNORECASE):
                return True
        return False
    
    def _can_auto_fix(self, rule_id: str) -> bool:
        """判断是否可以自动修复"""
        auto_fixable = {"STY002"}  # 目前只支持调试代码移除
        return rule_id in auto_fixable
    
    def _get_auto_fix(self, rule_id: str, match) -> Optional[str]:
        """获取自动修复建议"""
        if rule_id == "STY002":
            return f"删除此行: {match.group(0)}"
        return None
    
    def _calculate_compliance_score(self, stats: dict, file_count: int) -> float:
        """计算合规评分 (0-100)"""
        if file_count == 0:
            return 100.0
        
        critical = stats["by_severity"].get("critical", 0)
        error = stats["by_severity"].get("error", 0)
        warning = stats["by_severity"].get("warning", 0)
        info = stats["by_severity"].get("info", 0)
        
        total = critical + error + warning + info
        if total == 0:
            return 100.0
        
        # 加权扣分
        deductions = critical * 25 + error * 10 + warning * 3 + info * 0.5
        score = max(0, 100 - deductions / max(file_count, 1))
        
        return round(score, 1)
    
    def _generate_recommendations(self, stats: dict) -> List[str]:
        """生成改进建议"""
        recommendations = []
        
        if stats["by_severity"].get("critical", 0) > 0:
            recommendations.append(
                f"🔴 发现 {stats['by_severity']['critical']} 个严重安全问题,"
                f"请立即修复!"
            )
        
        if stats["by_severity"].get("error", 0) > 0:
            recommendations.append(
                f"⚠️ 发现 {stats['by_severity']['error']} 个高危问题,"
                f"建议在本迭代内修复。"
            )
        
        if stats["by_category"].get("security", 0) > 5:
            recommendations.append(
                "📋 安全问题较多,建议安排一次安全审计。"
            )
        
        if stats["by_category"].get("privacy", 0) > 0:
            recommendations.append(
                "🔒 发现潜在的隐私数据问题,请确认符合 GDPR/PIPL 要求。"
            )
        
        if not recommendations:
            recommendations.append("✅ 未发现重大合规问题,继续保持!")
        
        return recommendations
    
    @staticmethod
    def _issue_to_dict(issue: ComplianceIssue) -> dict:
        """转换为字典"""
        return {
            "rule_id": issue.rule_id,
            "file_path": issue.file_path,
            "line": issue.line_number,
            "column": issue.column,
            "severity": issue.severity.value,
            "message": issue.message,
            "suggestion": issue.suggestion,
            "snippet": issue.snippet,
            "category": issue.category.value,
            "auto_fix_available": issue.auto_fix_available,
        }


# 使用示例
if __name__ == '__main__':
    checker = ComplianceChecker()
    
    # 扫描示例文件
    sample_code = '''
import os

def connect_db():
    password = "SuperSecret123!"  # SEC001
    query = f"SELECT * FROM users WHERE id = {user_input}"  # SEC002
    print(f"Connecting with password={password}")  # PRV002
    console.log(debug_info)  # STY002
    # TODO: Fix this later  # STY001
'''
    
    results = checker.scan_file(
        file_path="app.py",
        content=sample_code,
        language="python"
    )
    
    print(f"📊 发现 {len(results)} 个合规问题:\n")
    for issue in results:
        print(f"  [{issue.severity.value.upper()}] Line {issue.line_number}: "
              f"{issue.message}")
        print(f"    💡 建议: {issue.suggestion}")
        print()

四、插件沙箱与安全机制

4.1 多层安全防护体系

┌─────────────────────────────────────────────────────────────┐
│         MonkeyCode 插件安全防护体系                           │
│                                                             │
│  第一层: 安装前验证                                          │
│  ├── 🔍 代码签名验证                                        │
│  ├── 📋 Manifest 格式校验                                   │
│  ├── 🚫 恶意模式扫描 (已知攻击特征)                         │
│  ├── 📊 依赖项分析 (供应链安全)                              │
│  └── 👥 社区信誉评分                                        │
│                                                             │
│  第二层: 运行时隔离                                          │
│  ├── 📦 沙箱执行环境 (受限的 Node.js/V8 隔离)               │
│  ├── 🚧 文件系统访问控制 (仅允许声明的路径)                  │
│  ├── 🌐 网络访问白名单 (需显式声明)                          │
│  ├── ⏱️ CPU/内存使用限制                                    │
│  └── 🔄 API 调用频率限制                                     │
│                                                             │
│  第三层: 行为监控                                            │
│  ├── 📈 性能指标实时监控                                    │
│  ├── 🚨 异常行为检测 (异常 CPU/内存/网络)                   │
│  ├── 📝 完整操作审计日志                                    │
│  └── 🛡️ 自动熔断机制                                       │
│                                                             │
│  第四层: 用户控制                                            │
│  ├── ✅ 权限显式授权 (安装时确认)                            │
│  ├── 👁️ 权限使用透明展示                                    │
│  ├── 🗑️ 一键卸载 + 数据清除                                │
│  └── 📊 隐私影响评估报告                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4.2 沙箱配置示例

# monkeycode/plugins/sandbox-config.yaml
sandbox_configuration:

  runtime:
    type: "isolated-v8"  # 使用 V8 Isolate 进行隔离
    memory_limit_mb: 256
    cpu_limit_percent: 30
    max_execution_time_ms: 5000  # 单次操作最大执行时间
    heap_snapshot_on_oom: true
  
  filesystem:
    allowed_operations:
      - "read"    # 默认允许读
    denied_operations:
      - "write"   # 写入需要显式权限
      - "delete"  # 删除需要显式权限
      - "exec"    # 执行需要显式权限
    allowed_paths:
      - "$PLUGIN_DIR/**"     # 插件自身目录
      - "$TEMP_DIR/$PLUGIN_ID/**"  # 插件临时目录
      - "$HOME/.config/monkeyCode/plugins/$PLUGIN_ID/**"
    path_aliases:
      PLUGIN_DIR: "./plugins/{id}"
      TEMP_DIR: "/tmp/monkeyCode"
  
  network:
    default_policy: "deny-all"
    allowed_domains: []  # 默认不允许任何网络访问
    rate_limits:
      requests_per_minute: 60
      bytes_per_minute: 1048576  # 1MB/min
    requires_permission_for:
      - "http:"
      - "https:"
      - "ws:"
      - "wss:"
  
  api_access:
    core_ai:
      allowed_methods:
        - "chatCompletion"
        - "codeCompletion"
        - "explainCode"
      rate_limit: "100/hour"
      max_tokens_per_request: 2000
    
    core_editor:
      allowed_methods:
        - "getActiveEditor"
        - "getText"
        - "getSelection"
      denied_methods:
        - "writeFile"  # 需要显式权限
        - "executeCommand"
    
    core_ui:
      allowed_methods:
        - "showInformationMessage"
        - "showWarningMessage"
        - "showErrorMessage"
        - "registerCommand"
      denied_methods:
        - "openExternal"  # 打开外部链接需要权限
  
  child_process:
    allowed: false  # 默认禁止子进程
    allowlist_executables: []  # 白名单为空
  
  native_modules:
    allowed: false  # 默认禁止原生模块 (N-API 等)

五、插件市场与分发策略

5.1 插件发布流程

#!/bin/bash
# ===== scripts/publish-plugin.sh =====
# MonkeyCode 插件发布脚本

set -e

echo "🐵 MonkeyCode Plugin Publisher"
echo "=============================="

# 1. 检查必要文件
REQUIRED_FILES=("package.json" "README.md" "LICENSE")
for file in "${REQUIRED_FILES[@]}"; do
    if [ ! -f "$file" ]; then
        echo "❌ Missing required file: $file"
        exit 1
    fi
done
echo "✅ All required files present"

# 2. 验证 package.json 中的 monkeyCode 字段
if ! node -e "require('./package.json').monkeyCode" 2>/dev/null; then
    echo "❌ Invalid or missing 'monkeyCode' field in package.json"
    exit 1
fi
echo "✅ Plugin manifest valid"

# 3. 运行 lint 检查
echo "🔍 Running lint checks..."
npm run lint --if-present
echo "✅ Lint passed"

# 4. 运行测试
echo "🧪 Running tests..."
npm test --if-present
echo "✅ Tests passed"

# 5. 构建
echo "📦 Building..."
npm run build --if-present
echo "✅ Build complete"

# 6. 打包
VERSION=$(node -e "console.log(require('./package.json').version)")
NAME=$(node -e "console.log(require('./package.json').name)")
PACKAGE_NAME="${NAME}-${VERSION}.tgz"

npm pack --pack-destination ./dist
echo "📦 Package created: ${PACKAGE_NAME}"

# 7. 发布到注册表
echo "🚀 Publishing to MonkeyCode Plugin Registry..."
# 这里会调用官方 CLI 工具上传
# mcplugin publish ./dist/${PACKAGE_NAME}
echo ""
echo "==========================================="
echo "🎉 Plugin published successfully!"
echo ""
echo "Next steps:"
echo "  1. Your plugin will be reviewed by the team"
echo "  2. Once approved, it will appear in the marketplace"
echo "  3. Users can install it via: mcplugin install ${NAME}"
echo ""
echo "📖 Don't forget to promote your plugin!"
echo "   GitHub: https://github.com/monkeycode-ai/monkeycode/issues"
echo "   (tag with 'plugin')"

5.2 插件质量评分标准

维度 权重 评分标准
功能性 30% 插件是否解决了实际问题?功能是否完整?
代码质量 20% 代码是否清晰?是否有测试?是否有文档?
安全性 15% 是否遵循安全最佳实践?是否有已知漏洞?
性能 15% 是否有性能瓶颈?启动时间是否合理?
用户体验 10% UI/UX 是否直观?错误提示是否清晰?
维护性 10% 是否活跃维护?是否响应 Issue?

评分等级:

  • ⭐⭐⭐⭐⭐ (90-100): 精选推荐 (Featured)
  • ⭐⭐⭐⭐ (75-89): 推荐安装 (Recommended)
  • ⭐⭐⭐ (60-74): 合格可用 (Good)
  • ⭐⭐ (40-59): 需要改进 (Needs Work)
  • ⭐ (0-39): 不予上架 (Rejected)

六、经验总结与最佳实践

6.1 插件开发十大原则

┌─────────────────────────────────────────────────────────────┐
│         MonkeyCode 插件开发十大原则                          │
│                                                             │
│  1️⃣  做一件事情,并把它做好                                 │
│     → 单一职责原则,一个插件解决一个问题                     │
│                                                             │
│  2️⃣  尊重用户的编辑器体验                                   │
│     → 不要阻塞主线程,不要频繁弹窗,静默优先                 │
│                                                             │
│  3️⃣  优雅降级是必须的                                       │
│     → AI 服务不可用时,插件仍应能正常工作(降低功能)         │
│                                                             │
│  4️⃣  日志是你的朋友                                         │
│     → 结构化日志,合理的日志级别,帮助用户排查问题           │
│                                                             │
│  5️⃣  性能意识贯穿始终                                       │
│     → 缓存、懒加载、增量处理,避免不必要的计算               │
│                                                             │
│  6️⃣  安全第一                                              │
│     → 最小权限原则,不请求不必要的权限                       │
│                                                             │
│  7️⃣  文档即代码                                            │
│     → README 要完整,API 要有注释,示例要能跑通             │
│                                                             │
│  8️⃣  测试不是可选项                                         │
│     → 单元测试 + 集成测试,CI 必须通过才能发布               │
│                                                             │
│  9️⃣  关注兼容性                                             │
│     → 声明清晰的版本兼容范围,处理好 breaking change          │
│                                                             │
│  🔟  倾听用户反馈                                           │
│     → Issue 是最宝贵的输入,积极回应每一个反馈               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

6.2 常见陷阱与解决方案

陷阱 症状 解决方案
内存泄漏 长时间运行后 IDE 卡顿 确保所有事件监听器在 deactivate 时清理
阻塞主线程 编辑器卡顿/无响应 将耗时操作放入 Worker 或异步执行
过度请求 AI API 成本超限/速率限制 实现缓存、去重、批量请求
忽略错误处理 插件崩溃影响其他功能 try-catch 包裹所有外部调用
硬编码配置 无法适配不同团队需求 提供配置面板,支持 workspace-level 配置
缺少优雅降级 AI 服务不可用时完全不可用 设计 fallback 逻辑,逐步降级功能
全局状态污染 多个插件互相干扰 使用命名空间隔离,避免修改全局对象

结语

"插件生态的健康程度,是一个开源项目成熟度的真正标志。"

MonkeyCode 的插件系统不仅仅是一个技术架构——它是一种社区协作的理念。我们相信:

  • 🌱 每一个好想法都值得被实现 — 通过插件,任何人都可以将自己的创意变为现实
  • 🤝 协作比竞争更有力量 — 开源的本质是共建共享
  • 🎯 多样性是创新的源泉 — 不同背景的开发者带来不同视角
  • 🚀 生态系统 > 单一产品 — 一个健康的生态比任何单一功能都更有价值

如果你有一个想法,想要为 MonkeyCode 开发插件,现在就开始吧!

🛠️ 开始你的插件开发之旅:

MonkeyCode — 用开放的架构,连接每一位创造者的想象力。 🐵🔌✨

posted on 2026-06-30 12:47  MonkeyCode  阅读(12)  评论(0)    收藏  举报