第129章 发布扩展与许可证要求
发布扩展的步骤如下:
扩展发布后,请参考更新扩展了解如何发布更新,并查阅常见问题解答获取关于维护和过时扩展的一般信息。
扩展许可证要求
自 2025 年 10 月 1 日起,扩展仓库必须包含许可证。 接受的许可证如下:
这使我们能够将基于你的扩展代码生成的二进制文件分发给用户。 如果没有有效的许可证,用于添加或更新扩展的 Pull Request 将无法通过 CI 检查。
许可证文件应位于扩展的根目录,但不一定需要在仓库根目录。如果扩展位于仓库的某个子目录中,许可证必须放置在该子目录内,仓库根目录的许可证无效。你可以将现有许可证符号链接到扩展目录,或为扩展代码选择其他可接受的许可证。
任何文件名以 LICENCE 或 LICENSE 作为前缀(不区分大小写)的文件,都会被检查以确保其符合获认可的许可证之一。请参见 许可证验证源代码。
请注意:
- 此许可证要求仅适用于扩展代码本身(即编译到扩展二进制文件中的代码)。
- 它不适用于扩展可能下载或交互的任何工具,例如语言服务器或其他外部依赖项。
- 如果你的仓库同时包含扩展代码和其他项目(如语言服务器),你无需重新许可这些其他项目;只有扩展代码必须采用上述获认可的许可证之一。
发布扩展的前置条件
在提交扩展以供发布之前,请确保其满足以下要求。
请注意,维护者将在发布过程中指出不合规之处。如果你选择忽略这些要求,发布将被延迟,甚至可能被直接拒绝。
通用要求
- 手动在 Zed 中测试你在提交时所在的子模块 commit 下的扩展。
- 发布扩展注册表中尚不具备的功能。
- 如果遇到现有扩展的问题,请优先尝试为现有扩展做出贡献。有关此要求的更多详情,请参见 常见问题解答。
- 不要滥用扩展 API 来规避其当前的局限性。
- 在极少数情况下,我们可能会接受合理的变通方案。
- 是否接受变通方案由维护者自行决定。
- 为你的扩展使用合适的 ID。ID 必须:
- 具有唯一性
- 使用 kebab-case 格式
- 不包含
zed或extension字样 - 能很好地表明你的扩展提供了什么功能(详见下文)
- 仅包含扩展运行所需的资源。
- 以 允许的许可证 之一为扩展授予许可。
- 将所有面向用户的文本用英文编写。
语言扩展
- 只为你扩展所针对的语言及其直接相关的方言提供支持。
- 在扩展的
extension.toml中为你提供的每种语言定义一个 grammar。 - 你也可以为该语言提供 language server、debugger 和代码片段。
- 扩展 ID 和名称应与你要添加的主要语言的名称相同或相近。
- 如果扩展不提供 language server,就不要包含任何 Rust 代码。
Language Server 扩展
- 如果你的扩展只提供 language server,请确保扩展 ID 能体现这一点(例如加上
-language-server或-lsp后缀)。 - 不要把 language server 打包进扩展。应通过 Zed Rust Extension API 下载它,或在用户环境中检查是否已存在。
Debugger 扩展
- 如果你的扩展只提供 debugger,请确保扩展 ID 能体现这一点(例如加上
-debugger后缀)。 - 不要把 debug adapter 打包进扩展。应通过 Zed Rust Extension API 下载它,或在用户环境中检查是否已存在。
主题扩展
- 只提供主题,不要包含其他内容。
- 确保扩展 ID 能表明它是一个主题(例如加上
-theme后缀)。
图标主题扩展
- 只提供图标主题,不要包含其他内容。
- 确保扩展 ID 能表明它是一个图标主题(例如加上
-icon-theme或-icons后缀)。
代码片段扩展
- 如果扩展仅包含代码片段,扩展 ID 应体现这一点(例如加上
-snippets后缀)。 - 仅在必要时将代码片段设为全局作用域,语言相关的代码片段应限定在对应语言中。
MCP Server Extensions
MCP 服务器扩展未来将被废弃,取而代之的是 MCP 注册表;相关进展详见 #59351。为确保兼容 Zed 后续版本,请务必将服务器发布到注册表。
- 扩展内仅提供一个 MCP 服务器,不要包含其他内容。
- 扩展 ID 需表明其为 MCP 服务器(例如加上
mcp-server-前缀或-mcp-server后缀)。 - 不要在扩展中捆绑 MCP 服务器,应通过 Zed Rust Extension API 下载或检测用户环境中是否已存在。
Agent 服务器和 Slash 命令扩展
Agent 服务器和 slash 命令扩展已废弃,不再接受提交。若希望在 Zed 中提供 Agent 服务器,请将其发布至 ACP 注册表。
若扩展符合以上所有要求,可以着手发布了!
Publishing Guide
开始发布流程前,请确认扩展已满足所有发布前提及许可证要求。未满足上述要求,请勿继续执行以下步骤,否则发布可能被延迟或直接拒绝。
请仔细执行每一步,以确保发布流程顺利进行。
Pull request rules {#pull-request-rules}
为控制代码评审队列规模,针对 zed-industries/extensions 仓库的所有 PR 均需遵守以下规则:
- 每个 PR 必须新增或更新且仅涉及一个扩展。
- 任意时刻,你最多可以有三个未合并的 PR。
- 需在3 周内响应维护者的反馈,否则你的 PR 将被关闭。
不符合上述规则的 PR 将直接关闭,不再提供额外反馈。若反复违反这些规则,可能导致被临时禁止或永久禁止向扩展仓库提交内容。
Fork 和克隆仓库
- Fork
zed-industries/extensions仓库。
提示:建议将
zed-industries/extensions仓库 fork 到个人 GitHub 账号而非 GitHub 组织,这样 Zed 团队可以向你 fork 的仓库推送必要变更,从而加快发布流程。
- 将仓库克隆到本地机器。
# 将此处替换为你自己 fork 仓库的 URL:
git clone https://github.com/your-username/extensions
cd extensions
git submodule init
git submodule update
提交你的扩展 {#submitting-your-extension}
要发布扩展,需向 zed-industries/extensions 仓库 提交 PR。
在你的 PR 中,执行以下操作:
- 将你的扩展作为 Git 子模块添加至
extensions/目录下,路径为extensions/{extension-id}。 - 子模块必须使用 HTTPS URL,而非 SSH URL(git@github.com)。 - 你的扩展仓库必须是公开的。 - 子模块检出的提交必须位于某个分支上,不能是 detached commit。
git submodule add https://github.com/your-username/foobar-zed.git extensions/my-extension
git add extensions/my-extension
- 在顶层
extensions.toml文件中新增一条包含你扩展信息的条目: - 确保version与特定提交下extension.toml中设置的版本一致。
[my-extension]
submodule = "extensions/my-extension"
version = "0.0.1"
如果你的扩展位于子模块的子目录中,可以用 path 字段指定扩展所在的位置:
[my-extension]
submodule = "extensions/my-extension"
path = "packages/zed"
version = "0.0.1"
- 运行
pnpm sort-extensions,确保extensions.toml和.gitmodules的条目已排序。
这样就完成了!PR 被合并后,扩展会自动打包并发布到 Zed 扩展注册表。
审核流程 {#review-process}
PR 提交后,维护者会进行审核,并可能要求修改。请牢记PR 规则:对维护者反馈超过 3 周无响应,提交将被关闭。
关于审核需要多久、为什么设置时间限制、PR 被关闭后该怎么办等问题,请参阅FAQ。
更新扩展
要更新扩展,请向zed-industries/extensions 仓库提交 PR。
更新类的 PR 同样需要遵守PR 规则。
在 PR 中需要做以下几件事:
- 将扩展的子模块更新到新版本对应的 commit。可以运行:
# 从仓库根目录执行:
git submodule update --remote extensions/your-extension-name
这样即可将扩展更新到远程仓库中最新的 commit。
- 更新
extensions.toml中该扩展的version字段。 - 确保此处的version与对应 commit 中extension.toml里设置的版本一致。
如果想自动化这一流程,可以使用一个社区 GitHub Action。
如需了解扩展的维护或终止维护相关问题,请参阅常见问题。
常见问题
在发布扩展之前、期间和之后,常会遇到各种问题。以下是我们收到最多的几类。
提交审核需要多长时间? {#review-duration}
我们会尽力在合理时间内回复。但我们也清楚,目前并非总能做到——对此我们深表歉意!我们正不断迭代流程,以期更快地为每个提交提供反馈,并带来更好的贡献体验。
通常情况下,大多数提交会在几周内收到初步反馈;部分扩展可能需要更久,甚至一两个月。我们知道这既非最优体验,也不令人愉悦,我们正在努力改进(实际上,本文档正是我们提供背景信息、改善这一流程的一部分)。
但请注意,我们目前无法给出具体承诺。由于当前积压量较大等多种原因,审核时间可能进一步延长,对此我们深表遗憾。
为什么我的 PR 被关闭了? {#pr-closed}
如果你的 PR 在缺乏太多反馈的情况下被直接关闭,说明它严重违反了发布前置条件。由于提交量巨大,这类情况下我们通常不再提供额外说明。请务必重新仔细阅读前置条件。
此外,正如拉取请求规则所述,如果在维护者反馈后 **3 周内无任何响应**,我们会认为该提交已停滞并将其关闭。
因停滞而被关闭的 PR 并不意味着终结:你随时可以重新开启一个新 PR,我们会再次审查。
为什么对我的响应有期限,而你们却不受限制? {#response-timeframe}
我们明白这看起来似乎不太公平,尤其是考虑到我们自身的响应速度——对此我们也感到遗憾。但为了大家的利益,我们需要关闭那些长期停滞的提交,以保持审查队列处于可控状态,从而让我们能更快地处理每一个提交,包括您接下来的提交。
为什么要求我新建 PR,而不是继续我那个已关闭的? {#fresh-prs}
由于积压任务较多,在某些情况下我们更倾向于处理新的 PR,因为它们能保持队列更短。经验表明,新的 PR 往往处于更容易审查的状态;而更新后的 PR 虽然声称已处理所有反馈,实际上却常常处于损坏且无法合并的状态。这既浪费了审查者,也浪费了贡献者的宝贵时间。
从这个意义上说,新的 PR 处理起来更快,通常合并过程也更简单、更迅速。
为什么要强制规定这么多严格的前置条件? {#why-prerequisites}
我们设定扩展前置条件的目标,是在开放扩展生态与一定的标准和质量水平之间寻求平衡:当用户安装一个扩展时,应当能放心它能在一定程度上良好工作,而不必自己先去检验。
这些前置条件也有助于集中力量。如果多人维护多个几乎相同的扩展,用户分散在各处,这会让所有相关方都陷入巨大的混乱。将力量引导到统一的地方,对拥有者、贡献者和用户都有益——每个用例只保留一个扩展,你也不用费心去猜哪个才是对的。
当然,我们深知这些条件无法涵盖所有情况,但它们设定了大家都能依赖的基线。如果某个扩展最终确实无法工作或无人维护,这正是本页面下方那些政策所应对的场景。
已发布的扩展是否也需遵守这些前置条件? {#prerequisites-for-existing-extensions}
是的。已发布的扩展并不豁免这些前置条件,其更新将与新提交遵循相同的标准。
唯一的例外是 ID 限制:由于扩展一旦发布,其 ID 便不可更改,因此现有的 ID 将保持原样。
我必须维护我的扩展吗? {#do-i-have-to-maintain-my-extension}
不需要。扩展发布后,我们这边没有任何后续要求。感谢你为 Zed 扩展生态做出的贡献,我们非常感激!
话虽如此,没有哪个扩展第一天就完美无缺——bug 可能会出现,改进需求也可能随之而来。维护虽非义务,但如果你能在合理时间内回应这些问题报告,对所有人都有帮助。
我发现某个扩展有 bug,或者想改进它,该怎么做? {#reporting-issues-and-improvements}
请先在扩展的原仓库中提交问题或提出改进建议,而不是发布一个竞争性的扩展。大多数作者都欢迎反馈和贡献,把力量集中在一处,既免去了用户在几乎相同的扩展之间做选择的困扰,也让维护者不用重复审核。
如果作者长期没有回应,请参阅 扩展作者停止回应会发生什么?
我不想再维护我的扩展了,怎么办? {#stepping-back}
完全没问题——优先级会变化,放弃维护某个扩展不必感到愧疚。作为当前作者,你可以:
- 把仓库所有权转让给新的维护者,或者
- 向
zed-industries/extensions提交 issue 或 pull request,请求下架你的扩展。
你也可以选择继续保留这个扩展——很多扩展很少甚至从未更新过,却依然拥有大量满意的用户。
扩展作者对问题报告不再回应会发生什么? {#unresponsive-owner}
我们不希望已发布的扩展被弃之不管,那会给用户带来糟糕的体验。所以当一个扩展的作者联系不上时:
- 贡献者可以 fork 该扩展,并提议用自己的 fork 替代现有扩展;或者
- Zed 官方可以将扩展 fork 到
zed-extensions组织下,由社区和 Zed 官方共同继续维护。
只有满足以下条件之一时,我们才会采取上述行动:
- 当前作者已给出书面许可;或
- 有书面证据表明曾尝试与所有者建立联系,且所有者在至少 6 周内未予回应。
若缺少上述任一条件,该扩展仍将保留给当前所有者。
这种归属权的变更也不一定是永久性的:如果原所有者恢复响应,该扩展可以切换回原仓库。
为什么我的语言不能复用内置语法或其他扩展中的语法? {#grammar-reuse}
如果某语言依赖于非其自身拥有的语法,该语法的更新可能会改变 Tree-sitter 解析生成的节点结构,从而导致该语言静默失效。为避免此类问题,每种语言必须使用在其自身扩展的 extension.toml 中定义的语法。
我对这些政策有疑问或持反对意见,应该去哪里反馈? {#policy-discussion}
首先,感谢通读这些内容!
虽然这些政策的制定都有充分理由,但并非所有条款都不可更改——我们非常重视围绕这些议题的开放讨论。
如果其中有任何内容让您觉得不妥,或者您有任何疑问,欢迎在 zed-industries/zed 仓库中发起讨论并 @MrSubidubi ——我们更希望通过沟通解决问题,而不是让您感到困扰。