Motrix 开源贡献实战指南:从开发环境搭建到分层架构、实现规范与验证流程
本文基于 Motrix 仓库的官方贡献指南(CONTRIBUTING.zh-CN.md),完整梳理参与该项目的标准工作流:如何搭建可运行的开发环境、如何理解「核心层 + 双宿主」的分层架构与依赖边界、如何遵循代码/文本/提交信息规范,以及如何用一组自动化检查命令验证改动后再提交 Pull Request。读完后,你能够独立完成从 Fork 克隆到 PR 提交的完整贡献链路,并知道每一层代码该写在哪里、不该依赖什么。
选择合适的沟通渠道
贡献不只有写代码:代码、测试、文档、翻译、Issue 反馈和设计建议都在项目欢迎之列。参与项目即表示同意遵守行为准则;报告疑似安全漏洞须按安全策略私密提交,切勿在公开 Issue、Discussion 或 Pull Request 中披露漏洞信息。
沟通渠道的选择规则:
- 创建反馈前,先搜索现有及已关闭的 Issue,避免重复提交;
- 使用项目的 Issue 表单反馈可复现的问题或明确的功能建议;
- 使用 GitHub Discussions 咨询使用问题、获取帮助,或讨论尚未成熟到可以创建 Issue 的想法;
- 在投入实现之前,先讨论重要功能、架构调整、新增依赖和破坏性变更;
- 每个 Issue 和 Pull Request 只处理一个明确的问题或功能点。
准备开发环境
依赖要求
开发需要三样工具:
- Git;
- Node.js 22 或更高版本;
- package.json 中
packageManager字段指定的 pnpm 版本——当前仓库锁定为pnpm@11.22.0(带 Corepack 校验哈希),建议用corepack enable让版本与仓库声明严格一致。
克隆、安装与启动
如果你没有仓库写入权限,先 Fork 仓库,再克隆自己的 Fork 并安装依赖:
git clone https://github.com/<your-account>/Motrix.git
cd Motrix
pnpm install
pnpm start
从 package.json 的 scripts 字段可以看到,pnpm start 实际执行的是 node scripts/dev.mjs,而 prestart 钩子会先运行 ensure:electron-runtime 与 ensure-native-abi 两个脚本,确保 Electron 运行时和本机 ABI 的原生依赖(如 better-sqlite3 的重新编译)就绪。scripts/dev.mjs 的注释说明了它的完整职责:启动 Vite 渲染层 dev server(固定端口 5173)、以 watch 模式构建 main 与 preload 两个 bundle、在两者都产出首次 bundle 后携带 VITE_DEV_SERVER_URL 启动 Electron;后续 main/preload 重建会触发 Electron 重启,而渲染层热更新由 Vite HMR 直接处理,无需重启。启动前它还会打包内置插件到 dist/builtin-plugins,否则内置 URL 解析插件不会加载(表现为 B 站/YouTube 链接退化为普通 HTTP 下载)。
开发态用户数据目录:MOTRIX_USER_DATA
默认情况下,pnpm start 会使用常规 Motrix 配置目录旁独立的用户数据目录(通常为 Motrix-dev),避免开发过程修改已安装应用的数据。如需使用其他目录,请在运行 pnpm start 前将 MOTRIX_USER_DATA 设为该目录的绝对路径。
这段行为在源码中的落点在 src/main/platform/services.ts:
- 目录解析顺序为:
MOTRIX_USER_DATA环境变量 > 开发态下的默认 userData 目录 + "-dev"后缀 > 默认 userData 目录(即打包后的正式应用数据); - 若设置了
MOTRIX_USER_DATA但值是相对路径,会在创建目录前直接抛出MOTRIX_USER_DATA must be an absolute path错误; - 目录会被
mkdirSync递归创建,随后通过app.setPath('userData', ...)与app.setPath('sessionData', ...)生效,且必须在任何持久化服务或单实例锁初始化之前完成。
对应的行为验证可参考 src/main/platform/services.test.ts:其中覆盖了开发态下 MOTRIX_USER_DATA 优先级、空值忽略、打包态下仍生效、相对路径被拒绝等场景。E2E 测试(e2e/fixtures/electron-app.ts)和打包冒烟脚本(scripts/smoke-electron-package.mjs)也通过该变量注入临时用户数据目录,说明这一机制是贯穿开发、测试与打包验证的统一入口。
分支策略
- 从最新的
main创建开发分支,并将 Pull Request 提交到main; master分支仅保留旧版 v1 代码,已经冻结,请勿向该分支提交新改动;- 分支名称使用
<type>/<snake_case_topic>_<YYYYMMDD>格式;如果存在对应 Issue,可在主题前加入 Issue 编号,例如fix/1970_conduct_links_20260826。
了解项目架构
Motrix Turbo 采用宿主无关的产品核心,并在其外部提供两种应用宿主:Electron 桌面应用和 Node/Web 服务端。两种运行方式共用同一套渲染层。这样的分层可以复用产品行为,避免 Electron 相关逻辑渗透到服务端,并允许下载引擎在稳定的适配器之后独立替换。
各层职责
| 目录 | 职责 | 依赖边界 |
|---|---|---|
src/renderer/ |
Electron 与浏览器共用的渲染层 | 只导入 @shared/ 和渲染层内部模块;通过 @renderer/lib/transport 访问产品能力 |
src/preload/ |
受限的 Electron 上下文桥接层 | 使用 Electron,以及 src/shared/ 中的纯协议值或类型;不承载产品行为 |
src/main/ |
Electron 宿主、IPC、窗口、菜单和操作系统集成 | 可以组合 src/core/、src/shared/ 和 Electron 专用适配器 |
src/server/ |
Node/Docker 宿主、HTTP/WebSocket 端点和服务端平台集成 | 可以组合 src/core/、src/shared/ 和服务端库;不得导入 Electron 或 src/main/ |
src/core/ |
宿主无关的应用服务、领域行为、引擎编排和插件策略 | 可以使用 src/shared/ 和宿主无关的库;不得导入任一应用宿主 |
src/shared/ |
跨层 Schema、协议常量、类型、语言数据和纯工具函数 | 不得执行 I/O,不得使用定时器、网络、Electron API 或 Node.js 专用 API |
packages/native-host/ |
用于浏览器扩展配对的独立 Rust 原生消息宿主 | 通过已发布的桥接契约通信,不依赖系统 Node.js 或 Electron |
src/test-utils/ |
仅供测试使用的 Fixture 和辅助工具 | 生产代码不得导入此目录 |
路径别名在 tsconfig.json 中定义:@shared/* → src/shared/*、@core/* → src/core/*、@renderer/* → src/renderer/*、@main/* → src/main/*、@test-utils/* → src/test-utils/*。这也是「优先使用已配置的路径别名、不要使用层级过深的相对导入」这一规范的执行基础。
传输与协议流向
渲染层在两种宿主中使用同一套命令、查询和事件契约:
Electron: renderer -> ElectronTransport -> preload -> main IPC -> core
Browser: renderer -> HttpWsTransport -> server RPC/events -> core
仓库中可以逐一印证这条链路:
- Electron 侧的传输实现是 src/renderer/lib/transport/electron.ts 中的
ElectronTransport类(其测试 src/renderer/lib/transport/electron.test.ts 演示了invoke(Queries.GetTaskInspectorActivity, ...)、invoke(Commands.PauseTask, 'task-1')等典型调用); - 浏览器侧对应
src/renderer/lib/transport/http-ws.ts中的HttpWsTransport(见 src/renderer/lib/transport/http-ws.test.ts); - 通道名称与载荷契约集中在
src/shared/protocol/。例如 src/shared/protocol/commands.ts 导出的Commands对象定义了command:createDownload、command:pauseTask、command:restartEngine等全部通道名,同目录还有queries.ts、events.ts、bridge.ts等契约文件。
因此规范明确要求:渲染层功能代码必须使用 @renderer/lib/transport,只有 ElectronTransport 和范围严格受限的平台适配器可以直接访问 window.motrix;请使用 Commands、Queries、Events 及其 Bridge* 对应项,不要使用原始通道字符串。
引擎、桥接与插件边界
- 引擎适配器:产品层代码面向 src/core/engine/engine-adapter.ts 中定义的
EngineAdapter接口;aria2 的 RPC 类型和转换逻辑必须保留在具体的 aria2 适配器内部(src/core/engine/aria2/),引擎生命周期仅由 src/core/engine/engine-supervisor.ts 中的EngineSupervisor负责。从源码结构看,EngineSupervisor暴露getStatus(): EngineStatusSnapshot等运行态接口,将「引擎进程管理」与「引擎协议细节」做了清晰切分。 - MDXP 桥接协议:MDXP 通过 HTTP 和 WebSocket 使用 JSON-RPC 2.0。
@motrix/mdxp软件包(在 package.json 中声明为^0.5.0依赖)是线协议 Schema、方法常量、错误码和连接行为的唯一事实来源;不要在本仓库中重复定义这些契约。 - 插件体系:宿主无关的插件状态、策略、安装、能力和沙箱编排属于
src/core/plugin/;Electron 与 Node/Docker 的装配分别属于src/main/plugin/和src/server/plugin/。插件代码在独立的 QuickJS Worker 中运行(依赖quickjs-emscripten),只能通过类型化的能力桥访问宿主能力;新增宿主专用能力时,必须在两种能力宿主中完成实现和测试。 - Rust 原生消息宿主:packages/native-host/ 是用于浏览器扩展配对的独立 Rust 工程,有自己的
Cargo.toml、集成测试(tests/目录)和独立的打包脚本(如package-flatpak-companion.mjs),通过已发布的桥接契约与主程序通信。
用 check:boundaries 守护依赖方向
修改导入关系或分层职责后,请运行 pnpm run check:boundaries。自动化检查只是基线,不能替代对上述依赖方向的人工审查。
scripts/check-boundaries.mjs 的实现值得贡献者了解:它维护一组「目录 + 正则」规则,用 grep -rnE 扫描源码,任何命中即判 [FAIL] 并以非零码退出。当前规则包括:
src/core/不得import 'electron',也不得引用@fastify或fastify;src/shared/不得使用node:前缀导入、require('node:...')、process.或NodeJS.全局——这正是「shared 层不得执行 I/O、不得使用 Node.js 专用 API」边界的机器化表达;src/renderer/不得导入core/或main/路径下的模块;src/server/不得导入electron,也不得导入@main/或src/main/;- 生产源码不得引用部署暂存契约文件(
*-runtime-dependencies.json、.motrix-*-stage.json、dist/(electron|server)-app); - 还有若干更细粒度的局部规则(如 add-task UI 组件不得直接导入 transport 或协议命令常量,仅少数 IPC 感知文件例外)。
遵循实现规范
代码与文件
- 代码、注释、标识符、文件名、提交信息和 Pull Request 标题使用英文;
- JavaScript、TypeScript、TSX 和样式文件使用
kebab-case命名(新增或重命名文件后须运行pnpm run check:file-names验证); - 仅用于类型的导入使用
import type(仓库 TypeScript 配置启用了verbatimModuleSyntax,从源码结构看这一约束在类型层面是强制的),Node.js 内置模块使用node:前缀; - 优先使用已配置的路径别名,不要使用层级过深的相对导入;同时需要确认目标运行环境支持该别名;
- 行为发生变化时,请添加或更新测试;生产代码不得依赖测试辅助工具(
src/test-utils/)或生成的构建产物。
用户可见文本与文档
- 所有用户可见的应用及操作端文本都必须通过现有 i18next 资源进行本地化,不要硬编码界面字符串(i18next 为 package.json 中的正式依赖);
- 新增或修改翻译键时,需要更新所有已注册语言,并保持各语言中的占位符集合完全一致。这一条由 scripts/check-i18n.mjs 自动校验:脚本以 src/shared/constants/locales.ts 声明的语言目录为基准,扫描
src/shared/locales/下的语言资源,将每个标量键展平为点分路径,并比较各语言间的键集合差异;对复数键(_zero/_one/_two/_few/_many/_other后缀)和{{value}}形式的占位符也逐组做集合比对,任何缺失或占位符不一致都会作为错误报告; - 修改中英文文档对中的任一文件时,应在同一改动中更新另一份(标题、命令、路径和示例保持一致,正文使用符合各自语言习惯的表达)。例如贡献指南本身就成对维护:CONTRIBUTING.md 与 CONTRIBUTING.zh-CN.md;
- 不要提交凭证、私有地址、个人路径、私密计划、本地生成状态或无关改动。
提交信息
使用 Conventional Commits 格式:
<type>(<optional-scope>): <imperative summary>
允许的类型包括 feat、fix、refactor、perf、test、docs、chore、ci 和 style。摘要使用小写开头的英文祈使短语,不加句号,并控制在 72 个字符以内。如果改动理由不直观,请补充正文;如有破坏性变更,请添加 BREAKING CHANGE: 尾注。
验证改动
每次提交前都需要运行以下必要检查:
pnpm run check:boundaries
pnpm run lint
pnpm exec tsc --noEmit
其中 pnpm run lint 在 package.json 中对应 biome check .(即 Biome 的格式化 + 辅助检查),可用 pnpm run lint:fix 自动修复可修复项。
还需要根据改动内容运行对应检查:
| 改动类型 | 对应检查命令 |
|---|---|
| 行为或逻辑 | 运行相关 Vitest 测试;涉及多个模块时运行 pnpm test(即 vitest run) |
| 已有浏览器或 Electron 用户流程 | pnpm test:e2e(即 playwright test) |
| 语言资源或国际化行为 | pnpm run check:i18n |
| 新增或重命名文件 | pnpm run check:file-names |
| 插件 Manifest 契约 | pnpm run check:schema-parity |
| 依赖、捆绑资源或许可证元数据 | pnpm run check:third-party-notices |
| 原生消息宿主的 Rust 代码 | 见下方 Rust 检查命令 |
修改 packages/native-host/ 下的 Rust 代码时,请运行:
cargo fmt --manifest-path packages/native-host/Cargo.toml --all -- --check
cargo clippy --manifest-path packages/native-host/Cargo.toml --all-targets --locked -- -D warnings
cargo test --manifest-path packages/native-host/Cargo.toml --locked --all-targets
注意三条命令均带 --locked(或 --lock 语义的 --locked 锁文件约束),要求依赖解析与仓库提交的 Cargo.lock 完全一致,避免贡献引入未被评审的依赖变更。
提交前请审查最终差异,运行 git diff --check,并在 Pull Request 中记录准确的命令和结果。不要隐藏失败,也不要丢弃命令的退出状态。
提交 Pull Request
- 目标分支使用
main,关联对应 Issue,并说明问题以及选择当前方案的原因; - 完整填写 Pull Request 模板,包括准确的验证命令、环境和结果;
- 可见界面发生变化时,请提供截图或录屏;
- 生成文件和依赖改动应仅限于当前 Pull Request 所需范围;
- 使用后续 Commit 响应评审意见;维护者通常会在合并功能 Pull Request 时采用压缩合并(squash merge)。
贡献内容按照项目的 MIT License 接受;第三方资源可能适用其他条款,详情请参阅 THIRD_PARTY_NOTICES.md。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00