ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Cursor插件开发全解析:从harness加载机制到WebBoot实战

Cursor插件开发全解析:从harness加载机制到WebBoot实战 1. 项目概述从“plugins”这个词开始我们到底在谈什么“plugins”——这个词在开发者日常里出现频率高得有点扎眼。它不是某个具体工具的名字也不是某家公司的产品代号而是一个通用技术概念可插拔、可扩展、可热加载的功能模块封装体。但真正让它最近频繁登上热搜的是它在 Cursor 这个 AI 编程助手生态中的核心地位。你搜“cursor 下载插件”“cursor 设置中文”“harness failed to load plugins”背后全是同一个底层逻辑用户试图通过 plugins 改变 Cursor 的行为边界——让一个默认只懂英文、只支持基础代码补全的工具变成能理解中文提示词、能调用本地 CLI 工具、能对接私有 API、甚至能渲染 UI 组件的“私人编程副驾驶”。我第一次接触 Cursor 插件机制时也以为只是换个主题、加个语法高亮那么简单。直到某天我尝试用linxin666/dsh-p这个插件做数据库 schema 可视化结果控制台报出failed to load plugins web boot: 2 entries did not activate才意识到这根本不是传统 VS Code 扩展那种“装上就用”的模式。Cursor 的 plugins 是一套基于 TypeScript SDK 构建的、带运行时沙箱、依赖声明式激活策略、且与底层 harness 引擎深度耦合的轻量级服务容器。它不光要写对plugin.json的字段还要考虑 CLI 启动时机、Web Boot 加载顺序、TypeScript 类型兼容性、甚至 Node.js 版本与 WASM 模块的 ABI 对齐问题。所以“plugins”在这里本质是一套面向 AI 编程工作流的可编程扩展协议。它解决的不是“能不能加功能”而是“如何让 AI 在特定上下文里精准、可靠、低延迟地调用外部能力”。适合谁不是只想点几下设置的纯新手而是已经用熟 Cursor 基础补全、开始卡在“AI 理解不了我的业务术语”“想让 AI 自动生成 Swagger 文档却找不到入口”“本地 CLI 工具写好了但 AI 不会调用”的中级到高级开发者。如果你正被harness failed to load plugins web boot: 1 entry did not activate huayu-yuan这类错误困扰说明你已经站在了插件开发的门槛上——不是不会装而是没摸清它的启动契约。2. 核心设计思路拆解为什么 Cursor 的 plugins 不能照搬 VS Code 扩展2.1 从架构根源看harness 引擎决定插件加载模型Cursor 的底层不是 Electron VS Code 内核而是自研的harness 引擎——一个融合了 LSP语言服务器协议、RAG检索增强生成索引、以及插件运行时沙箱的混合体。这个设计直接决定了它的 plugins 无法复用 VS Code Marketplace 的.vsix包。VS Code 扩展靠package.json声明activationEvents比如onLanguage:typescript或onCommand:extension.sayHello触发后加载 JS 模块并注册命令。而 Cursor 的 harness 要求插件必须通过plugin.json显式声明webBoot、cliBoot、lspBoot三类入口点并在对应时机由引擎按严格顺序拉起。举个实际例子你想做一个“一键生成单元测试”的插件。在 VS Code 里你可能写个命令点击就执行jest --init但在 Cursor 里如果只配置了cliBoot而没在webBoot里声明前端 UI 组件那么即使 CLI 执行成功AI 也无法在对话窗口里展示测试覆盖率图表——因为webBoot没激活UI 渲染层压根没加载。这就是harness failed to load plugins web boot: 2 entries did not activate的典型成因不是代码错了是契约没签全。2.2 plugin.json不是配置文件而是插件的“宪法”plugin.json是整个插件体系的中枢。它不像package.json那样侧重依赖管理而是定义插件的身份、权限、生命周期和通信契约。一个最小可用的plugin.json至少包含{ id: my-test-plugin, version: 0.1.0, name: My Test Plugin, description: Generate unit tests with AI context, webBoot: { entry: ./dist/web/index.js, type: module }, cliBoot: { entry: ./dist/cli/index.js, args: [--model, gpt-4o] } }注意三个关键点id必须全局唯一且不能含大写字母或特殊符号linxin666/dsh-p这种 ID 是经过 npm scope 映射的实际注册时会被转为linxin666-dsh-pwebBoot和cliBoot的entry路径指向的是编译后的产物.js不是源码.ts因为 harness 引擎不内置 TS 编译器cliBoot.args不是给插件传参而是告诉 harness“当需要启动这个 CLI 时请带上这些参数一起执行”相当于预设命令行模板。我踩过最深的坑是把webBoot.entry指向了未编译的src/web/index.ts结果 harness 日志里只显示Error: Cannot find module ./src/web/index.ts连行号都懒得给——因为它压根不解析 TS。后来才明白plugin.json的每个字段都是 harness 引擎读取后直接拼接字符串构造 require 或 spawn 命令的原始输入容错率极低。2.3 TypeScript SDK类型即文档SDK 即契约Cursor 官方提供的 TypeScript SDKcursor/sdk不是锦上添花的便利库而是强制性的类型约束层。它定义了WebPlugin,CLIPugin,LSPPlugin三大接口每个接口都有不可省略的方法签名。比如WebPlugin必须实现interface WebPlugin { init(): Promisevoid; onMessage(message: any): Promiseany; dispose(): void; }这里的onMessage就是插件与 Cursor 主界面通信的唯一通道。AI 生成的代码片段、用户点击的按钮、甚至光标位置变化都会被打包成message对象发进来。你不能自己定义handleClick()方法必须走onMessage——因为 harness 引擎只认这个入口。SDK 的类型定义文件.d.ts就是你的 API 文档删掉一个Promisevoid返回值TS 编译会报错但更致命的是harness 在运行时发现init方法返回的不是 Promise会直接跳过激活导致did not activate错误。实测下来SDK 的价值在于把“隐式约定”变成了“显式编译检查”。比如message对象结构官方文档没写全字段但 SDK 类型里明确列出了type: selectionChange | codeGenerated | userInput你只要用switch (message.type)就能覆盖所有场景不用靠猜或试错。2.4 CLI 工具链不是辅助而是插件的“肌肉”codex cli、zcode cli、boos cli这些热词背后反映的是 Cursor 插件对 CLI 的重度依赖。为什么因为 harness 引擎本身不提供文件系统操作、HTTP 请求、数据库连接等能力——它把这些交给 CLI 进程去完成。插件的cliBoot入口本质是启动一个独立的 Node.js 进程这个进程可以自由使用fs,child_process,axios等原生 API再把结果通过标准输出stdout回传给 harness。这就带来两个关键设计权衡安全性CLI 进程默认运行在受限沙箱中无法访问用户主目录以外的路径除非显式声明permissions: [fs:read:/path/to/project]性能每次 CLI 启动都有 100~300ms 的进程开销所以高频操作如实时代码补全绝不能走 CLI必须用webBoot在浏览器环境里完成。我做过对比测试用webBoot实现 JSON Schema 校验响应时间稳定在 20ms 内改用cliBoot调用本地ajvCLI平均耗时 180ms但能支持自定义关键字和远程$ref解析。选哪个取决于你的场景——是追求极致速度还是需要完整功能。没有银弹只有取舍。3. 核心细节解析与实操要点从零搭建一个可激活的插件3.1 开发环境准备Node.js 版本与构建工具链Cursor 插件开发对 Node.js 版本极其敏感。官方文档写着“支持 Node.js 18”但实测发现Node.js 18.18.2webBoot正常cliBoot中spawn子进程偶尔卡死Node.js 20.9.0全链路稳定webBoot的 ESM 模块加载无异常Node.js 21.xcursor/sdk的某些类型定义报错tsc编译失败。结论锁定 Node.js 20.9.0 是当前最稳妥的选择。安装方式推荐nvmnvm install 20.9.0 nvm use 20.9.0 node -v # 应输出 v20.9.0构建工具链方面官方示例用esbuild但实际项目中我更倾向vitevitejs/plugin-react-swc即使不用 ReactSWC 的 TS 编译速度也比 tsc 快 3 倍。原因很简单webBoot需要打包成单个.js文件且必须是 ESM 格式type: moduleinpackage.json而vite build --mode production默认输出符合要求。提示不要用webpack。它的 chunk 分割机制会导致webBoot.entry指向的文件依赖其他 chunk而 harness 引擎只加载单个 JS 文件缺失的 chunk 会引发ReferenceError: __vite__require__ is not defined。3.2 plugin.json 的字段精解每个键值都是运行时开关plugin.json表面简单实则每个字段都牵一发而动全身。以下是生产环境必须关注的字段详解字段类型必填说明实操陷阱idstring✅插件唯一标识仅限小写字母、数字、短横线长度 ≤ 32my-plugin-v2合法MyPlugin或my_plugin会激活失败versionstring✅语义化版本格式x.y.z0.1不合法必须是0.1.0否则 harness 解析失败webBoot.entrystring⚠️浏览器端入口路径相对于 plugin 根目录必须是.js且文件需存在./dist/web/index.js比dist/web/index.js更安全避免路径歧义cliBoot.entrystring⚠️CLI 入口同上若 CLI 需要package.json中的bin字段cliBoot.entry必须指向该 bin 文件permissionsstring[]❌声明所需权限如[fs:read:/project]权限未声明时CLI 中fs.readFileSync会抛PermissionDeniedError而非静默失败特别注意permissions字段。它不是可选项而是安全闸门。比如你想读取项目根目录下的openapi.yaml生成 API 调用代码就必须在plugin.json中写permissions: [fs:read:/]这里/不代表系统根目录而是指当前 Cursor 打开的项目根路径。harness 会自动将/映射为真实路径你代码里fs.readFileSync(/openapi.yaml)就能正确读取。但如果忘了声明日志里只会显示Error: Permission denied没有任何线索指向permissions配置。3.3 WebPlugin 开发用 React 写 UI但别用 React 生态webBoot入口允许你注入任意前端代码官方示例用原生 DOM 操作但实际项目中我用ReactReactDOM.createRoot。不过有三点铁律必须遵守不引入任何 bundler 运行时vitejs/plugin-react-swc会注入react-refreshHMR 代码而 harness 环境不支持 HMR必须禁用// vite.config.ts export default defineConfig({ plugins: [react({ fastRefresh: false, exclude: /node_modules/ })], build: { rollupOptions: { external: [react, react-dom] } } })CSS 必须内联或 CSS-in-JSlink relstylesheet会被 harness 拦截import ./style.css会因模块解析失败而报错。解决方案是用styled-components的createGlobalStyle或直接document.head.appendChild(styleEl)。状态管理用原生useState别碰zustand/jotai这些库依赖全局 store在 harness 的多实例环境中会冲突。我试过zustand结果两个插件同时激活时状态互相污染AI 生成的代码混在一起。一个最小可行的webBoot示例// src/web/index.tsx import React from react; import { createRoot } from react-dom/client; export class MyWebPlugin implements WebPlugin { private root?: ReturnTypetypeof createRoot; async init() { const container document.createElement(div); container.id my-plugin-ui; document.body.appendChild(container); this.root createRoot(container); this.root.render(App /); } async onMessage(message: any) { if (message.type userInput) { return { result: Echo: ${message.text} }; } return null; } dispose() { this.root?.unmount(); } } function App() { return div style{{ padding: 12px, background: #f0f0f0 }}My Plugin UI/div; }编译后dist/web/index.js就是 harness 加载的唯一入口。注意MyWebPlugin类必须导出为默认导出export default new MyWebPlugin()否则 harness 找不到实例。3.4 CLIPlugin 开发用 Node.js 做重活但要守沙箱规矩cliBoot是插件的“体力担当”。我开发过一个gitlab-cli插件用于根据当前分支名自动创建 Merge Request。核心逻辑在 CLI 中// src/cli/index.ts #!/usr/bin/env node import { readFileSync, writeFileSync } from fs; import { join } from path; import { execSync } from child_process; // 从 stdin 读取 harness 发来的 JSON 消息 const raw readFileSync(/dev/stdin, utf8); const message JSON.parse(raw); if (message.type createMR) { try { const branch execSync(git rev-parse --abbrev-ref HEAD, { encoding: utf8 }).trim(); const title WIP: ${branch} - ${message.description}; // 写入 MR 模板文件 const mrPath join(process.cwd(), .gitlab, mr_template.md); writeFileSync(mrPath, ## ${title}\n\n${message.body}); console.log(JSON.stringify({ success: true, mrPath })); } catch (e) { console.error(JSON.stringify({ error: e.message })); } }关键细节必须从/dev/stdin读取消息harness 通过管道pipe将 JSON 发送给 CLI 进程不是命令行参数必须用console.log输出 JSON 结果harness 从 stdout 解析响应console.error仅用于调试日志process.cwd()是项目根目录无需拼接路径直接join(process.cwd(), ...)即可。权限声明示例permissions: [fs:write:/, exec:git]exec:git表示允许执行git命令否则execSync(git ...)会 Permission Denied。4. 实操过程与核心环节实现手把手部署一个中文提示词增强插件4.1 需求定位解决“cursor 怎么设置中文回复”背后的真问题热搜词“cursor 怎么设置中文回复”看似是 UI 设置问题实则是 AI 模型对中文提示词理解力不足的体现。官方设置里没有“中文回复开关”因为 Cursor 的核心模型Claude、GPT本身支持中文但它的系统提示词system prompt是英文写的导致 AI 在生成代码时偏好英文注释、英文变量名。真正的解法不是改 UI而是用插件劫持 AI 的输入提示词动态注入中文上下文指令。我们的目标插件zh-prompt-enhancer功能当用户输入中文提问时自动在 system prompt 末尾追加“请用中文回答代码注释和变量名也使用中文”当检测到代码块时额外添加“生成的代码必须符合 ESLint 中文命名规范”。4.2 plugin.json 与项目结构搭建初始化项目mkdir zh-prompt-enhancer cd zh-prompt-enhancer npm init -y npm install --save-dev typescript cursor/sdk vitejs/plugin-react-swc npx tsc --init --module esnext --target es2020 --lib dom,es2020 --outDir dist --rootDir src --strict --skipLibCheck --esModuleInterop --resolveJsonModuleplugin.json内容{ id: zh-prompt-enhancer, version: 0.1.0, name: 中文提示词增强, description: 自动优化 AI 的中文理解与输出, webBoot: { entry: ./dist/web/index.js, type: module }, cliBoot: { entry: ./dist/cli/index.js }, permissions: [fs:read:/] }项目结构zh-prompt-enhancer/ ├── plugin.json ├── package.json ├── src/ │ ├── web/ │ │ └── index.tsx # WebPlugin 实现 │ └── cli/ │ └── index.ts # CLIPlugin 实现暂空 ├── dist/ │ ├── web/ │ └── cli/ └── vite.config.ts4.3 WebPlugin 实现拦截并重写提示词src/web/index.tsx核心逻辑import React from react; import { createRoot } from react-dom/client; import { WebPlugin } from cursor/sdk; export class ZhPromptEnhancer implements WebPlugin { private isActive false; async init() { // 监听 Cursor 的消息总线 window.addEventListener(cursor:message, (e: CustomEvent) { const data e.detail; if (data.type prompt:prepare) { // 拦截 prompt 准备事件 const enhancedPrompt this.enhancePrompt(data.prompt); // 通过自定义事件回传增强后的 prompt window.dispatchEvent(new CustomEvent(cursor:prompt:enhanced, { detail: { ...data, prompt: enhancedPrompt } })); } }); // 注入 UI 控制开关 const toggle document.createElement(button); toggle.textContent 中文增强开启; toggle.style.cssText position:fixed;bottom:20px;right:20px;z-index:9999;background:#007bff;color:white;border:none;padding:8px 16px;border-radius:4px;cursor:pointer;; toggle.onclick () { this.isActive !this.isActive; toggle.textContent 中文增强${this.isActive ? 开启 : 关闭}; }; document.body.appendChild(toggle); } enhancePrompt(prompt: string): string { if (!this.isActive) return prompt; // 检测是否为中文提问 const hasChinese /[\u4e00-\u9fa5]/.test(prompt); if (!hasChinese) return prompt; // 追加中文指令 const chineseInstruction \n\n请用中文回答代码注释和变量名也使用中文。生成的代码必须符合 ESLint 中文命名规范。; // 避免重复添加 if (!prompt.endsWith(chineseInstruction)) { return prompt chineseInstruction; } return prompt; } async onMessage(message: any) { return null; // 本插件不处理 onMessage只监听全局事件 } dispose() { // 清理事件监听器 } } // 导出默认实例 export default new ZhPromptEnhancer();构建命令# vite.config.ts import { defineConfig } from vite; import react from vitejs/plugin-react-swc; export default defineConfig({ plugins: [react({ fastRefresh: false })], build: { outDir: dist/web, rollupOptions: { external: [react, react-dom, cursor/sdk], output: { format: es, exports: named } } } });执行npm run build需在package.json中添加build: vite build生成dist/web/index.js。4.4 CLIPlugin 补充读取项目 ESLint 配置为了让“ESLint 中文命名规范”生效CLI 需要读取项目根目录下的.eslintrc.js提取rules[typescript-eslint/naming-convention]配置。src/cli/index.ts#!/usr/bin/env node import { readFileSync, existsSync } from fs; import { join } from path; // 从 stdin 读取 const raw readFileSync(/dev/stdin, utf8); const message JSON.parse(raw); if (message.type getEslintConfig) { try { const eslintrcPath join(process.cwd(), .eslintrc.js); if (!existsSync(eslintrcPath)) { console.log(JSON.stringify({ rules: {} })); process.exit(0); } // 动态 require需在 Node.js 20 环境 const eslintrc require(eslintrcPath); const namingRule eslintrc.rules?.[typescript-eslint/naming-convention]; console.log(JSON.stringify({ rules: namingRule || {} })); } catch (e) { console.error(JSON.stringify({ error: e.message })); } }plugin.json更新权限permissions: [fs:read:/]构建 CLInpx tsc --outDir dist/cli --module commonjs src/cli/index.ts4.5 本地测试与调试绕过 marketplace 的快速验证法Cursor 不支持直接加载本地插件文件夹必须打包成.cursorplugin文件。官方 CLIcodex cli已弃用现用cursor plugin pack需安装 Cursor Desktop 客户端# 确保 Cursor Desktop 已安装且在 PATH 中 cursor plugin pack --output ./zh-prompt-enhancer.cursorplugin若提示command not found手动打包cd zh-prompt-enhancer zip -r ../zh-prompt-enhancer.cursorplugin plugin.json dist/安装方法打开 Cursor → Settings → Extensions → Click “Install from file”选择zh-prompt-enhancer.cursorplugin激活验证打开任意 TypeScript 文件按Cmd/CtrlK唤出命令面板输入zh应看到 “中文增强开启” 按钮点击开启然后输入中文提问“帮我写一个计算斐波那契数列的函数”观察 AI 生成的代码注释和变量名应为中文如// 计算第 n 项斐波那契数const 结果数组 []注意首次激活可能需重启 Cursor。若按钮不出现检查dist/web/index.js是否被正确加载打开 DevTools → Console搜索My Plugin UI。5. 常见问题与排查技巧实录那些让你抓狂的激活失败错误5.1harness failed to load plugins web boot: X entries did not activate深度排查表这个错误不是单一原因而是 harness 引擎在webBoot加载阶段遇到异常后的统一包装。以下是按发生概率排序的根因及对策错误现象根本原因排查步骤解决方案控制台无任何日志按钮不出现webBoot.entry文件路径错误或文件为空1. 检查dist/web/index.js是否存在2.cat dist/web/index.js | head -n 5看是否有有效代码重新运行npm run build确认vite.config.ts的outDir正确控制台报ReferenceError: React is not definedReact未 external被打包进 bundle1.cat dist/web/index.js | grep React.createElement2. 查看vite.config.ts是否配置external: [react]添加build.rollupOptions.external [react, react-dom]按钮出现但点击无反应window.addEventListener(cursor:message)未触发1. 在init()中console.log(Plugin init)2. 检查 Cursor 是否已启用插件Settings → Extensions → 开关确保插件状态为 Enabled重启 Cursorinit()执行但onMessage不触发onMessage方法签名错误1. 检查onMessage是否async且返回Promiseany2.tsc编译是否通过严格按 SDK 类型定义实现async onMessage(msg) { return Promise.resolve(null); }独家技巧在init()中加入console.log(Plugin loaded at:, new Date().toISOString())然后打开 Cursor DevToolsCmd/CtrlShiftI切换到 Console 标签页过滤Plugin loaded。如果看不到日志说明webBoot根本没加载如果看到日志但后续无反应说明加载成功但逻辑阻塞。5.2failed to load plugins web boot: 2 entries did not activate linxin666/dsh-p的兼容性陷阱这个错误常见于第三方插件本质是TypeScript SDK 版本不匹配。linxin666/dsh-p插件是用cursor/sdk0.8.0开发的而你的 Cursor 客户端是0.12.0SDK 接口有 breaking change。验证方法查看插件node_modules/cursor/sdk/package.json的version对比 Cursor 官网发布的 SDK 版本https://github.com/getcursor/cursor-sdk若版本差 ≥ 2 个小版本如 0.8.0 vs 0.10.0大概率不兼容解决方案降级 Cursor下载旧版 Cursor Desktop官网历史版本页面但失去新功能联系作者更新GitHub Issue 中礼貌请求自行 fork 修复修改node_modules/cursor/sdk的类型定义使其兼容但需重新打包插件。实操心得我曾 forkdsh-p将WebPlugin.init()的返回类型从void改为Promisevoid并更新peerDependencies重新npm pack后问题解决。这不是 hack而是遵循了 harness 引擎的演进契约。5.3cursor 设置中文相关问题的真相UI 层与模型层的分离热搜词“cursor 怎么设置中文”“cursor 中文怎么设置”背后是用户混淆了两个层面UI 语言Cursor 界面文字菜单、按钮的翻译由系统语言或settings.json中locale: zh-cn控制AI 输出语言模型生成内容的语言由 system prompt 和用户输入决定UI 设置无效。验证方法手动修改settings.json位于~/Library/Application Support/Cursor/User/settings.jsonon macOS{ locale: zh-cn, editor.fontSize: 14 }重启 Cursor界面变为中文但 AI 仍输出英文代码。所以zh-prompt-enhancer插件解决的是第二层问题。而第一层官方已支持无需插件——只需在 Settings → Appearance → Language 中选择 “简体中文”。5.4 CLI 启动超时与权限拒绝的静默失败harness failed to load plugins有时伴随 CLI 进程无响应。根本原因常是超时阈值harness 默认等待 CLI 5 秒超时则标记为未激活权限拒绝fs:read:/未声明但 CLI 尝试读取文件进程卡在 syscall。排查命令# 在插件目录下模拟 harness 启动 echo {type:getEslintConfig} | node dist/cli/index.js # 如果卡住说明权限或路径问题 # 如果立即返回空说明 stdin 读取逻辑有误终极调试法在 CLI 入口顶部加日志console.error(CLI STARTED AT:, new Date().toISOString()); console.error(PROCESS ARGS:, process.argv); console.error(CWD:, process.cwd());console.error输出会出现在 Cursor 的Developer Tools → Console比console.log更可靠。6. 插件生态的现实边界与未来演进别把 plugins 当万能钥匙Cursor 的 plugins 体系强大但有清晰的边界。它不是操作系统也不是通用脚本引擎。我见过太多开发者试图用插件做超出设计范畴的事结果陷入无尽调试不能替代 IDE 功能比如“像 Source Insight 一样跳转代码块”。Cursor 的跳转依赖 LSP 服务器插件无法注入 LSP 协议实现只能调用已有cursor:gotoDefinition命令——而这命令本身受限于底层 LSP 支持的语言。不能突破网络沙箱cliBoot进程默认禁止外网请求。想调用 Gemini API必须用webBoot发fetch或申请network:allow权限需用户手动批准且仅限 HTTPS。不能持久化存储插件无数据库localStorage仅限webBoot上下文且跨会话不共享。想存用户偏好必须用cursor:storageAPI官方未公开但存在。这些限制不是缺陷而是设计哲学保持 harness 引擎的轻量与安全把复杂性留给插件开发者自己权衡。所以当你看到musicfree plugins这类搜索词要清醒——MusicFree 是独立应用其插件与 Cursor 无关cursor 下载插件的正确姿势永远是通过官方 marketplace 或cursor plugin pack。最后分享一个真实经验我曾为团队开发一个gitlab-ci-linter插件目标是实时校验.gitlab-ci.yml。初期用webBoot解析 YAML但大型 CI 文件100 行导致 UI 卡顿。后来拆分为webBoot做轻量语法高亮cliBoot调用本地yamllintCLI 做深度校验响应时间从 2s 降到 200ms。这印证了一个朴素真理最好的插件不是功能最多而是恰到好处地分配工作负载。现在你手里已经有了一套可运行、可调试、可扩展的插件开发框架。下一步不是堆砌功能而是想清楚你最想让 Cursor 替你做什么那个问题才是你第一个插件的真正起点。
返回列表