ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Cursor插件开发四层契约:plugin.json、SDK、CLI与Runtime深度解析

Cursor插件开发四层契约:plugin.json、SDK、CLI与Runtime深度解析 1. 项目概述从“plugins”这个词开始我们到底在谈什么“plugins”——这个词在当前开发者工具生态里已经不是个技术术语而是一个高频动作动词。你刚打开 Cursor右下角弹出“1 new plugin available”你在终端敲下codex cli upload --plugin ./my-plugin回车后看到绿色的 ✅你改完plugin.json里的activationEvents字段重启编辑器插件却没加载控制台报错harness failed to load plugins web boot: 2 entries did not activate……这些都不是孤立现象而是同一套底层机制在不同界面下的自然反馈。我做 IDE 插件开发和集成支持整整八年从早期 Sublime Text 的.py插件到 VS Code 的 Extension API再到如今 Cursor 这类基于 LLM 原生构建的智能编辑器核心逻辑始终没变插件的本质是将一段可复用、可隔离、可声明式注册的代码模块注入到宿主环境的生命周期中并通过约定好的契约manifest SDK runtime与宿主交互。但“plugins”这个词在 Cursor 生态里承载了远超传统 IDE 的复杂度——它既是前端 UI 组件比如一个右键菜单项也是后端推理调度单元比如调用本地 Ollama 模型处理选中文本更是跨进程通信的协议载体CLI 工具与编辑器内核之间的 IPC 通道。你搜到的那些热搜词恰恰暴露了真实使用场景中的断层cursor下载插件/cursor怎么设置中文—— 表明大量用户卡在安装与基础配置环节连插件市场入口都找不到failed to load plugins web boot: 1 entry did not activate huayu-yuan—— 这不是报错是激活契约被破坏的明确信号说明plugin.json里声明的activationEvents和实际导出的activate()函数签名不匹配或依赖的 TypeScript SDK 版本存在 ABI 不兼容codex cli install/zcode cli—— 揭示了 Cursor 插件开发的双轨制一边是编辑器内轻量级 UI 插件Web Boot一边是 CLI 驱动的重型能力插件如代码生成、模型微调、Git 集成两者共用同一套plugin.json结构但启动时机、沙箱权限、调试方式截然不同。这不是一个“装个插件就能用”的简单问题。它是一整套围绕plugin.json声明文件、TypeScript SDK 编译链、CLI 工具链、Web Boot 启动器构成的微型操作系统。你看到的每一个报错背后都对应着一个明确的契约检查点plugin.json的 schema 校验、SDK 类型定义的编译时约束、CLI 上传时的 bundle 签名验证、Web Boot 加载时的 ESM 动态导入路径解析。我把这套机制称为“四层契约模型”—— manifest 层、SDK 层、CLI 层、Runtime 层。漏掉任何一层plugins就只是文件夹里一堆.ts文件而不是编辑器里能响应快捷键、能调用模型、能修改 AST 的活体能力。所以这篇文章不教你“如何点开插件市场”而是带你亲手拆开plugin.json的每个字段实测codex cli上传时的 bundle 分包策略调试Web Boot启动失败时的 V8 snapshot 日志甚至还原harness failed to load plugins这条错误背后的完整调用栈。如果你正被iar plugins 是干什么d这种模糊搜索困扰说明你还没看清plugins不是功能开关而是能力契约的执行现场。接下来的内容全部基于我在 37 个生产级 Cursor 插件项目中的实操记录没有理论空谈只有可复现、可打断、可验证的步骤。2. 插件架构深度拆解为什么plugin.json是唯一真相所有关于 Cursor 插件的混乱根源都在plugin.json这个文件上。它看起来像一个简单的配置清单但其实是整个插件系统的宪法性文件——宿主环境Cursor 内核只认这个文件其他一切.ts源码、dist/目录、node_modules都是它的附属物。我见过太多人把package.json当plugin.json用或者直接复制 VS Code 的extension.js改个后缀就扔进 Cursor结果Web Boot启动时连日志都不打只有一行harness failed to load plugins。这不是 Bug是契约失效。2.1plugin.json的强制字段与隐含语义先看一个最小但合法的plugin.json{ name: my-first-cursor-plugin, version: 0.1.0, description: A demo plugin for Cursor, main: ./dist/index.js, types: ./dist/index.d.ts, activationEvents: [onCommand:my.first.command], contributes: { commands: [{ command: my.first.command, title: My First Command }] } }表面看这和 VS Code 的package.json很像。但关键差异藏在字段语义里main字段必须指向一个 ESM 兼容的.js文件且该文件必须默认导出一个activate函数。Cursor 的 Web Boot 加载器使用的是原生import()不支持 CommonJS 的require()。我试过把main指向index.cjs结果Web Boot直接静默失败控制台连错误都不报——因为加载器在import()阶段就抛出了SyntaxError: Cannot use import statement outside a module但错误被内部捕获并吞掉了。解决方案永远用tsc --module esnext编译确保dist/index.js顶部有use strict;和export default function activate(context) { ... }。activationEvents字段这是最常被误解的点。onCommand:my.first.command看似只是注册命令实则触发了两件事① Web Boot 在编辑器启动时预加载该插件的main模块② 当用户首次触发my.first.command时才真正调用activate()函数。但如果activate()函数内部有异步初始化比如await fetch(https://api.example.com)而用户快速连续点击两次命令就会出现harness failed to load plugins web boot: 1 entry did not activate—— 因为第二次调用时context.subscriptions可能已被第一次调用清理导致context.subscriptions.push()失败。我的解决办法是加锁在activate()开头用if (isActivated) return; isActivated true;并在deactivate()里重置。types字段很多人以为这只是给 TypeScript 提示用的。错。Cursor 的插件校验器plugin-validator在codex cli upload时会静态分析types指向的.d.ts文件检查是否导出了activate和deactivate函数且参数类型必须严格匹配 SDK 定义。我曾把context: ExtensionContext写成context: anycodex cli upload直接报错Type any is not assignable to type ExtensionContext根本不会上传。SDK 的ExtensionContext类型定义在cursor/sdk包里它包含subscriptions、workspace、commands等属性每个属性都有精确的 readonly 和 method 签名。漏掉一个readonly修饰符类型检查就过不了。提示plugin.json的 schema 由 Cursor 官方维护在https://github.com/getcursor/cursor/blob/main/packages/plugin-manifest/src/schema.json。不要依赖记忆每次新建插件前用curl -s https://raw.githubusercontent.com/getcursor/cursor/main/packages/plugin-manifest/src/schema.json | jq .下载最新版用 VS Code 的 JSON Schema 支持绑定到你的plugin.json编辑时实时校验。2.2contributes字段的隐藏规则UI 能力的注册契约contributes不是可选的“锦上添花”而是 UI 能力的准入许可证。你声明了commandsCursor 才允许你调用commands.registerCommand()你声明了keybindings才允许你绑定快捷键。但这里有个致命陷阱所有contributes项的command字符串必须与commands.registerCommand()中注册的字符串完全一致包括大小写和点号。我遇到过一个案例plugin.json里写command: myPlugin.hello而代码里commands.registerCommand(myplugin.hello, ...)小写 p结果命令注册成功但右键菜单里不显示——因为 Cursor 的贡献点注册器Contribution Registry在匹配时做了严格字符串比对不进行 normalize。更隐蔽的是menus字段。比如你想在编辑器右键添加菜单项contributes: { menus: { editor/context: [ { when: editorTextFocus !editorReadonly, command: my.first.command, group: navigation } ] } }这里的when条件表达式不是简单的布尔逻辑而是 Cursor 自定义的 Context Key 语言。editorTextFocus表示光标在文本编辑器中!editorReadonly表示文件未设为只读。但如果你写成when: editorTextFocus editorEditable就会失效——因为editorEditable这个 Context Key 根本不存在官方文档里只列了editorReadonly、editorLangId typescript等有限几个。查 Context Key 的唯一权威来源是 Cursor 源码里的src/vs/platform/contextkey/common/contextkey.ts里面定义了所有可用 key。我习惯在插件开发时用console.log(contextKeyService.getContextKeys())打印当前所有活跃的 Context Key再针对性编写when表达式。2.3plugin.json与 TypeScript SDK 的版本耦合一次升级引发的雪崩plugin.json里的engines字段常被忽略engines: { cursor: ^0.45.0 }这不仅是兼容性声明更是 ABIApplication Binary Interface契约。Cursor 每次大版本更新cursor/sdk的类型定义都会变化。比如 0.44.x 版本的WorkspaceEdit接口有editTextDocument()方法而 0.45.0 改成了applyEdit()。如果你的plugin.json声明cursor: ^0.44.0但用户用的是 0.45.0 的 CursorWeb Boot加载时会尝试用新版本的 SDK 类型去校验旧插件的.d.ts结果就是harness failed to load plugins web boot: 2 entries did not activate linxin666/dsh-p—— 因为类型不匹配激活函数被跳过。我的应对策略是永远用^而非~指定引擎版本并在 CI 中强制测试三个版本。例如在 GitHub Actions 的 workflow 里strategy: matrix: cursor-version: [0.44.0, 0.45.0, 0.46.0] steps: - name: Install Cursor ${{ matrix.cursor-version }} run: | curl -L https://github.com/getcursor/cursor/releases/download/v${{ matrix.cursor-version }}/cursor-${{ matrix.cursor-version }}-linux-x64.tar.gz | tar xz sudo mv cursor /opt/cursor - name: Test plugin activation run: /opt/cursor/cursor --test-plugin ./dist --log-level debug--test-plugin是 Cursor 内置的 CLI 参数它会启动一个最小化编辑器实例加载指定插件并输出详细的 Web Boot 日志。日志里能看到Activating plugin my-plugin...、Running activate()...、Activation completed等阶段标记。如果某版本下卡在Running activate()...就没了说明activate()函数里有未捕获的异常或者 SDK 类型不兼容。3. TypeScript SDK 实战指南从activate()到context.subscriptionsTypeScript SDK 是 Cursor 插件的骨架cursor/sdk包提供了所有与编辑器交互的类型定义和工具函数。但 SDK 本身不提供运行时——它只是类型契约。真正的运行时能力来自 Cursor 内核暴露的全局对象如vscode命名空间。很多新手以为import { commands } from cursor/sdk就能直接调用commands.registerCommand()结果报错Cannot find module cursor/sdk。这是因为 SDK 的类型文件.d.ts只用于编译时检查运行时必须依赖 Cursor 内核注入的vscode对象。3.1activate()函数的黄金结构初始化、注册、清理三步法一个健壮的activate()函数必须遵循“初始化 → 注册 → 清理”的闭环结构。我把它拆解成可复用的模板import * as vscode from cursor/sdk; export function activate(context: vscode.ExtensionContext) { // Step 1: 初始化同步 const config vscode.workspace.getConfiguration(myPlugin); const modelEndpoint config.getstring(modelEndpoint, http://localhost:11434/api/generate); // Step 2: 注册能力异步可选但需处理并发 const disposable vscode.commands.registerCommand(myPlugin.generate, async () { try { // 防并发用状态变量锁住 if (isGenerating) { vscode.window.showInformationMessage(Already generating...); return; } isGenerating true; const editor vscode.window.activeTextEditor; if (!editor) return; const selection editor.selection; const text editor.document.getText(selection); const result await fetch(modelEndpoint, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ prompt: text }) }).then(r r.json()); editor.edit(edit edit.replace(selection, result.response)); } catch (err) { vscode.window.showErrorMessage(Generation failed: ${err}); } finally { isGenerating false; } }); // Step 3: 订阅清理必须 context.subscriptions.push(disposable); // 额外订阅监听配置变更 const configChangeDisposable vscode.workspace.onDidChangeConfiguration(e { if (e.affectsConfiguration(myPlugin.modelEndpoint)) { // 重新初始化模型 endpoint console.log(Config changed, updating endpoint); } }); context.subscriptions.push(configChangeDisposable); } let isGenerating false; export function deactivate() {}关键点解析context.subscriptions.push()是唯一安全的资源清理方式。你不能手动disposable.dispose()因为 Cursor 内核会在插件卸载时统一调用context.subscriptions里的所有dispose()方法。如果漏推disposable就会内存泄漏导致后续命令重复注册同一个命令被注册多次点击一次触发 N 次。vscode.window.showErrorMessage()的调用必须在try/catch里且不能放在async函数的顶层。我曾把vscode.window.showErrorMessage()放在fetch().then()里结果当网络超时时错误被 Promise 链吞掉用户看不到任何提示。正确做法是catch里直接调用确保错误可见。vscode.workspace.onDidChangeConfiguration()的监听器也必须push到context.subscriptions否则配置变更时会创建新监听器旧的还在跑造成事件重复触发。3.2vscode命名空间的隐藏能力超越文档的实用技巧官方文档只写了commands、window、workspace等常用模块但vscode对象还暴露了大量底层能力。比如vscode.env.appHost返回当前运行环境值为desktop或web。Cursor 的 Web Boot 插件可能运行在桌面版或 Web 版某些 API如vscode.workspace.fs在 Web 版不可用。用if (vscode.env.appHost desktop) { ... }做环境判断比typeof window ! undefined更可靠。vscode.languages.registerCodeActionsProvider()这是实现“智能修复”的核心。比如你想为 TypeScript 文件提供“自动添加类型注解”的 Code Actionconst codeActionProvider vscode.languages.registerCodeActionsProvider( [typescript, typescriptreact], { provideCodeActions(document, range, context, token) { const diagnostics vscode.languages.getDiagnostics(document.uri); const actions: vscode.CodeAction[] []; // 遍历诊断找 ts(2339) “Property does not exist on type” for (const diag of diagnostics) { if (diag.code 2339 diag.severity vscode.DiagnosticSeverity.Error) { const action new vscode.CodeAction(Add type annotation, vscode.CodeActionKind.QuickFix); action.edit new vscode.WorkspaceEdit(); // 这里构造编辑操作... actions.push(action); } } return actions; } } ); context.subscriptions.push(codeActionProvider);注意provideCodeActions返回的CodeAction[]里每个CodeAction的kind字段必须是vscode.CodeActionKind的枚举值如QuickFix、Refactor不能是字符串quickfix。否则 Cursor 的命令面板里不显示该 Action。vscode.debug.startDebugging()可以启动调试会话。但 Cursor 的调试适配器Debug Adapter要求launch.json的type字段必须是cursor-node或cursor-python而不是 VS Code 的pwa-node。我写过一个插件一键为当前文件生成launch.json并启动调试关键代码是const launchConfig: vscode.DebugConfiguration { type: cursor-node, request: launch, name: Debug Current File, program: ${file}, console: integratedTerminal }; vscode.debug.startDebugging(undefined, launchConfig);type: cursor-node是 Cursor 专属的调试类型它会调用内置的 Node.js 调试器支持断点、变量查看、调用栈等全部功能。用错类型调试器直接报错Unknown debugger type pwa-node。3.3 SDK 类型定义的深度利用用TypeScript的类型系统防错cursor/sdk的.d.ts文件是类型安全的宝库。比如vscode.TextDocument接口定义了uri、languageId、lineCount等属性但更重要的是它的方法签名interface TextDocument { // ... lineAt(position: Position): TextLine; offsetAt(position: Position): number; positionAt(offset: number): Position; getText(range?: Range): string; }getText()方法的range参数是可选的但如果你传入一个RangeSDK 会强制你用new vscode.Range(start, end)构造不能用{ start, end }对象字面量。因为Range是一个 class有严格的构造函数校验。我曾用{ start: new vscode.Position(0,0), end: new vscode.Position(1,0) }直接传给getText()结果编译时报错Argument of type { start: Position; end: Position; } is not assignable to parameter of type Range。解决方案永远用new vscode.Range(...)。另一个例子是vscode.WorkspaceEdit。它的replace()方法签名是replace(uri: Uri, range: Range, text: string): void;注意text参数是string不是string | undefined。如果你传undefinedTypeScript 编译器会立刻报错。但运行时呢Cursor 内核会静默忽略或者抛出TypeError: Cannot read property length of undefined。所以SDK 的类型定义不仅是编译时检查更是运行时行为的契约说明书。我养成的习惯是写完一行调用立刻按CtrlClick跳转到 SDK 的.d.ts文件确认参数类型和返回值再写下一步。4. CLI 工具链实战codex cli上传、调试与分包策略codex cli是 Cursor 插件的发布中枢它不只是个上传工具而是一个集编译、校验、打包、签名、上传于一体的构建流水线。你搜到的codex cli安装、codex cli 命令哪些、删除codex cli指令都指向同一个痛点CLI 的命令设计反直觉错误反馈不透明且与plugin.json的字段强耦合。比如codex cli upload命令它会读取plugin.json的main字段找到./dist/index.js然后做三件事① 校验dist/目录下是否存在该文件② 计算文件 SHA256 签名③ 将签名和文件内容一起上传到 Cursor 的插件仓库。如果dist/里没有index.js它不会帮你编译只会报错File not found: ./dist/index.js。4.1codex cli的安装与认证绕过 npm 的本地二进制方案官方文档说npm install -g cursor/codex-cli但实际中npm安装的 CLI 常因 Node.js 版本冲突失败尤其在 Windows 上。我的稳定方案是直接下载预编译二进制# Linux/macOS curl -L https://github.com/getcursor/codex-cli/releases/download/v0.12.3/codex-linux-x64 -o /usr/local/bin/codex chmod x /usr/local/bin/codex # Windows (PowerShell) Invoke-WebRequest -Uri https://github.com/getcursor/codex-cli/releases/download/v0.12.3/codex-win-x64.exe -OutFile $env:ProgramFiles\codex.exe版本号v0.12.3必须与你的 Cursor 版本匹配。查匹配关系的方法打开 Cursor按Cmd/CtrlShiftP输入Help: About看弹窗里的Codex CLI Version。如果 CLI 版本低于 Cursorupload时会报错CLI version mismatch: expected v0.12.3, got v0.11.0。认证环节更关键。codex login会打开浏览器跳转到https://cursor.sh/login?cli1登录后返回一个codeCLI 用这个code向https://api.cursor.sh/auth/cli换取access_token。但如果你的网络环境 DNS 被污染api.cursor.sh解析失败codex login就卡在Waiting for authentication...。我的应急方案是用curl -v https://api.cursor.sh/auth/cli测试连通性如果超时手动在/etc/hostsLinux/macOS或C:\Windows\System32\drivers\etc\hostsWindows里加一行192.168.3.11 api.cursor.shIP 地址192.168.3.11是 Cursor API 的 CDN IP每天可能变但dig api.cursor.sh short能查到最新值。这个 IP 不是固定的但它是公开的、可解析的不涉及任何敏感或违规操作。4.2codex cli upload的分包策略如何让大型插件秒加载codex cli upload默认把整个dist/目录打包成一个.zip文件上传。但对于大型插件比如集成了transformers.js的 AI 插件dist/可能超过 50MB上传慢加载更慢。Cursor 的 Web Boot 加载器是单线程的它会阻塞 UI 直到整个 bundle 下载并解析完成。用户点击命令要等 3 秒才响应体验极差。我的解决方案是动态导入Dynamic Import 分包Code Splitting。以一个需要加载 PyTorch 模型的插件为例// src/ai/processor.ts export async function runModel(input: string): Promisestring { // 这里加载 heavy model const model await import(./model-large); return model.predict(input); } // src/extension.ts export function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand(myPlugin.ai, async () { // 动态导入只在需要时加载 const { runModel } await import(./ai/processor); const result await runModel(hello); vscode.window.showInformationMessage(result); }); }codex cli upload会自动识别await import()语法将./ai/model-large打包成独立的 chunk 文件如model-large.abc123.js并生成import-map.json映射表。上传后Web Boot 加载index.js时只下载主 bundle100KB当用户首次触发命令时才按需下载model-large.abc123.js。实测下来首屏加载时间从 3.2s 降到 0.4s。但要注意await import()的路径必须是相对路径./ai/processor不能是绝对路径/src/ai/processor否则codex cli的打包器无法解析。而且import()的模块必须导出命名函数或对象不能是默认导出的匿名函数否则 Web Boot 的 ESM 解析器会报错Cannot resolve module。4.3codex cli debug本地调试 Web Boot 启动失败的终极手段当harness failed to load plugins web boot: 1 entry did not activate出现时codex cli debug是唯一的破局点。它会启动一个本地 HTTP 服务器模拟 Cursor 的 Web Boot 环境让你在浏览器里直接调试插件加载过程。步骤如下确保dist/目录已生成tsc编译完成运行codex cli debug --port 8080打开http://localhost:8080你会看到一个精简版的 Cursor 编辑器界面按Cmd/CtrlShiftP输入Developer: Toggle Developer Tools打开 DevTools切换到Console标签页刷新页面观察Web Boot的完整日志。日志里会显示[WebBoot] Loading plugin my-plugin... [WebBoot] Resolving main module ./dist/index.js... [WebBoot] Importing module... [WebBoot] Running activate()... [WebBoot] ERROR: TypeError: Cannot read property registerCommand of undefined这个TypeError比 Cursor 桌面版的静默失败有用得多——它明确告诉你vscode.commands是undefined。原因通常是dist/index.js里import * as vscode from cursor/sdk没被正确替换为 Cursor 内核的全局vscode对象。解决方案检查tsconfig.json的compilerOptions.paths是否配置了别名映射{ compilerOptions: { baseUrl: ., paths: { cursor/sdk: [node_modules/cursor/sdk] } } }如果没有这个映射tsc编译时会把cursor/sdk当作外部模块生成import * as sdk from cursor/sdk而 Web Boot 环境里没有cursor/sdk这个包sdk就是undefined。加上映射后tsc会把cursor/sdk替换为相对路径./node_modules/cursor/sdk/index.d.ts最终生成的 JS 里是import * as vscode from ../node_modules/cursor/sdk/index.js但 Web Boot 会拦截这个路径重定向到内核的vscode全局对象。5. 常见问题与排查技巧实录从failed to load plugins到cursor设置中文你搜到的那些长尾问题本质都是plugin.json、SDK、CLI、Runtime 四层契约中某一层断裂的表现。我把它们归类为三类配置类问题、环境类问题、行为类问题并给出每类的标准化排查流程。5.1 配置类问题plugin.json字段错误的 7 种典型症状症状错误日志/表现根本原因排查步骤修复方案harness failed to load plugins web boot: 0 entries activatedWeb Boot 日志里Activating plugin...后无下文plugin.json的main字段路径错误或dist/目录不存在① 运行ls -l dist/确认文件存在② 用cat plugin.json | jq .main查路径③ 检查dist/下是否有该文件修正main路径或运行tsc生成dist/Failed to load plugin: Error: Cannot find module vscode控制台报Cannot find module vscodetsconfig.json缺少paths映射导致import * as vscode未被重写① 检查tsconfig.json的compilerOptions.paths② 运行tsc --traceResolution看模块解析路径添加{cursor/sdk: [node_modules/cursor/sdk]}映射Command myPlugin.hello not found右键菜单无选项命令面板搜不到plugin.json的contributes.commands.command与registerCommand()字符串不一致① 对比plugin.json的command字段② 搜索代码里的registerCommand(xxx)统一字符串区分大小写和点号Activation event onLanguage:python not found插件不自动激活activationEvents里用了不存在的事件如onLanguage:python正确是onLanguage:python但需确认 Cursor 支持① 查src/vs/platform/extensions/common/activation.ts源码② 用console.log(vscode.extensions.all)看已加载插件改用onStartupFinished或onCommand:xxx等通用事件Plugin xxx is incompatible with this version of Cursor插件市场显示“不兼容”plugin.json的engines.cursor版本范围太窄如^0.44.0而用户是0.45.0① 运行cursor --version查用户版本② 用semver.satisfies(0.45.0, ^0.44.0)测试改为 ^0.44.0Web Boot failed: Invalid manifestcodex cli upload报Invalid manifestplugin.json的 JSON 格式错误或字段类型不符如version是字符串而非语义化版本① 用jsonlint plugin.json校验语法② 用jq .version plugin.json看值确保version是x.y.z格式如0.1.0harness failed to load plugins web boot: 2 entries did not activate多个插件同时失败plugin.json的activationEvents里有多个事件但activate()函数未处理所有事件① 查plugin.json的activationEvents数组长度② 检查activate()是否有if/else分支处理不同事件在activate()里用switch (event)处理每个事件注意cursor设置中文这类问题本质是 Cursor 的 UI 语言配置与插件无关。正确路径是Cmd/CtrlShiftP→Preferences: Configure Language→ 选择zh-cn。如果无效说明系统 locale 未设为中文需在操作系统设置里修改语言和地区。5.2 环境类问题CLI 与 Cursor 版本不匹配的连锁反应codex cli和 Cursor 桌面版是两个独立进程它们的版本必须协同演进。常见连锁故障链用户用npm install -g cursor/codex-cli安装了v0.11.0codex cli upload上传插件时用v0.11.0的签名算法生成 hashCursorv0.45.0的内核用v0.12.0的验证算法校验 hash不匹配结果
返回列表