Qwen Code Tauri 白标桌面端:3 字段完成换肤
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
本文走一遍 Qwen Code Tauri 桌面壳(desktop-shell)的白标品牌构建流程:一个brandId加一张 logo,内置的brand-create.mjs脚本即可完成配置、图标、启动屏替换,产出白标桌面端安装包,并拆解交叉编译与更新签名两个最容易翻车的环节。
🎯 我们要替换的到底是什么
这一节先划定工作量边界:所谓“品牌化”,到底动了仓库里的哪些东西。
假设需求是:我们自己的产品需要一个带独立名称和图标的桌面客户端,UI 底座用 Qwen Code 的 Web Shell。现在 Qwen Code 的桌面实现统一收敛在 packages/desktop-shell 这个 Tauri 壳里(更早的 Electron 实现已经移除),而品牌化的挂载点只有三处:
- tauri.conf.json:应用名、Bundle Identifier、描述、更新源端点;
src-tauri/icons/:各尺寸、各格式的应用图标全家桶;- bootstrap/ 启动 UI:应用冷启动时用户第一眼看到的标题、文案与 Logo。
这个壳本身很薄:frontendDist直接指向../bootstrap,真正的 Web Shell 跑在随包捆绑的 Node 运行时里。所以品牌面很小,真正值得做的是把这块小面板变成可重复、可校验的脚本化流程——这正是仓库里desktop-brand-builder技能在做的事:Agent 按 SKILL.md 的流程,用一个零依赖的 Node 脚本 brand-create.mjs 完成全部替换,全程不手工改配置。
📋 备什么:最小输入清单
这一节回答“用户该填什么、脚本该自己推什么”。
设计目标是让用户最多填三个字段,其余全部走确定性推导,而不是追问。输入字段速查如下:
| 字段 | 必填 | 校验 / 含义 |
|---|---|---|
brandId | 是 | 必须匹配^[a-z][a-z0-9-]*$,小写字母开头,只含小写字母、数字、短横线 |
logo | 是 | 必须存在的本地文件路径,推荐方形 PNG,尺寸 ≥ 1024px |
website | 否 | 官网地址,用于推导appId |
appName/appId/artifactPrefix | 否 | 分别覆盖派生的显示名、Bundle Identifier、安装包文件名前缀 |
updaterEndpoints | 否 | 更新源端点 JSON 数组;空数组表示禁用应用内更新 |
updaterPubkey | 条件必填 | base64 公钥;updaterEndpoints非空时必须提供,且要与签名产物所用私钥配对 |
target | 否 | mac/win/linux/all |
必填项缺失时只问一次,不反复追问;填齐后直接进入构建,没有确认环节。
派生规则由 brand-create.mjs 实现:
appName:按短横线拆词、逐词首字母大写、空格连接,acme-ai→Acme AI;artifactPrefix:同样拆词但用短横线连接,acme-ai→Acme-AI;appId:website有合法 host(先剥掉www.前缀、要求至少两段)时,反转 host 标签再追加.desktop,https://acme.ai→ai.acme.desktop;- 回退
appId:app.<brandId>.desktop; updaterEndpoints:默认空数组。
一个容易被忽略的细节:源码内置了缩写词集合(ai、api、cli、ide、sdk、ui、url),派生名称时这些词整体大写,所以acme-cli得到的是Acme CLI而不是Acme Cli。
输入就绪后,在构建目录写一份brand.json(logo 用绝对路径):
{ "brandId": "acme-ai", "logo": "/absolute/path/to/logo.png", "website": "https://acme.ai" }appName、appId这些字段都可以不写,脚本会派生;只有确实要自建更新源时才加updater*字段。
⚙️ 跑什么:从隔离克隆到三步补丁
这一节走完整命令链,并拆开脚本内部的三个补丁及其防御设计。
先在隔离克隆里干活。品牌补丁直接写进源码树,工作仓库必须保持干净,所以每个品牌用一个全新克隆:
BUILD_ROOT="$PWD/brand-builds/<brandId>-<timestamp>" mkdir -p "$BUILD_ROOT" git clone --branch main --single-branch \ https://gitcode.com/GitHub_Trending/qw/qwen-code \ "$BUILD_ROOT/qwen-code" cd "$BUILD_ROOT/qwen-code"clone 一旦失败就停下来报告,不能假装流程已经推进。
装依赖。品牌脚本本身只要求 Node ≥ 18,但打包阶段的build:runtime会调用仓库根的工具链(cross-env、esbuild 等 devDependencies),所以根部与 desktop-shell 两套依赖都要装:
npm install cd packages/desktop-shell npm install --workspaces=false cd ../..运行品牌脚本。原则是:内置脚本可用时,禁止手工编辑tauri.conf.json、图标文件或 bootstrap 品牌字符串,脚本是补丁与资源生成的唯一权威来源。
node packages/desktop-shell/.agents/skills/desktop-brand-builder/scripts/brand-create.mjs \ --shell-root /absolute/path/to/qwen-code/packages/desktop-shell \ --config /absolute/path/to/brand.json结束后脚本打印一份 JSON 报告:派生出的appName/appId/artifactPrefix、被补丁的配置路径、图标生成结果、bootstrap 补丁文件清单,后续验证全靠它。
脚本内部的三个补丁:
- 打补丁
tauri.conf.json:写入productName、identifier、bundle.shortDescription、plugins.updater.endpoints。这里有一条最重要的安全约束——品牌构建永远不许轮询官方更新源,官方更新源也永远不许更新品牌构建。因此updaterEndpoints默认为空;清空端点时脚本还会连带做两件事:把bundle.createUpdaterArtifacts置为false(别再生成没人消费的签名更新产物),并把官方pubkey置为空字符串而不是删掉字段——插件 schema 声明pubkey: String且没有 serde 默认值,删字段会导致启动时反序列化失败,而端点为空时空字符串无害。 - 重新生成图标全家桶:调用 Tauri CLI 的
icon子命令把 logo 展开成全部尺寸。值得注意的调用方式:脚本先require.resolve出 CLI 入口,再用spawnSync(process.execPath, [...])启动,让 logo 路径作为普通 argv 元素传递、不经过任何命令解释器——文件名里就算带$(...)或反引号也注入不了。CLI 不可用时走两级回退:logo 是 PNG 就只复制成icons/icon.png并警告其余尺寸仍是旧 logo;非 PNG 则不碰任何图标,提示先转 PNG 再重跑npx --yes @tauri-apps/cli icon <logo>。 - 打补丁启动屏:把 logo 复制为
bootstrap/brand-logo<ext>,替换 index.html 与 bootstrap.js 里的启动文案和旧 Logo 文件名。替换做了双语境转义:JS 侧是单引号字符串,先用JSON.stringify转义反斜杠、换行等控制字符再处理单引号(只转单引号不够——名字以反斜杠结尾会“逃逸”掉结束引号);HTML 侧按&→<→>→"→'顺序做实体转义,先转&是为了不让后续引入的实体被二次转义;替换全部使用函数式 replacer,避免$&这类模式展开把内容改坏。
还有两条护栏要记牢:
- 单次使用守卫:运行前检查
productName是否仍是默认值Qwen Code Desktop,若已变更直接拒绝——bootstrap 补丁依赖原始字面量,补丁不可逆,同一克隆不许重跑; - 失败关闭:品牌提供了更新配置(端点非空或带了 pubkey)但目标配置里没有
plugins.updater段时,脚本在写任何文件之前报错。否则会悄悄丢掉已校验的更新配置,交付一个永远无法更新的品牌构建。
同理,配置加载阶段若发现appName恰好等于Qwen Code Desktop,也会直接拒绝——否则单次使用守卫失效,第二次运行会把品牌字符串重复拼进 bootstrap 文件。
🏗️ 看什么:交叉编译为什么必须重跑运行时
这一节讲打包阶段最容易翻车的一步。
宿主平台打包是两行命令:
cd packages/desktop-shell npm run build:runtime --workspaces=false npx tauri build坑在交叉编译。build:runtime对应 prepare-runtime.js,它按QWEN_DESKTOP_TARGET环境变量(默认宿主平台)下载对应平台的 Node 运行时并捆绑到runtime/qwen-code/。源码会把变量归一化到五个受支持目标(darwin-arm64、darwin-x64、linux-arm64、linux-x64、win32-x64),不在列表内的值直接抛错。
原因在于:目标与宿主不一致却不重跑build:runtime,打出来的包里捆绑的就是宿主架构的 Node 二进制,应用一启动就是 exec format error。所以每切换一次--target,都必须带环境变量重跑一遍:
QWEN_DESKTOP_TARGET=aarch64-apple-darwin npm run build:runtime --workspaces=false npx tauri build --target aarch64-apple-darwintarget: all就是按目标逐个循环“build:runtime → tauri build”,而且只跑当前机器或 CI 真正支持的目标——文件没落盘之前,不要声称产出了跨平台产物。
产物位置:
- 宿主目标:
packages/desktop-shell/src-tauri/target/release/bundle/ - 指定 triple:
src-tauri/target/<triple>/release/bundle/
bundle 下的子目录与 tauri.conf.json 声明的打包目标一一对应:dmg/、nsis/、appimage/、deb/。
🔐 更新公钥怎么配对
这一节只在品牌方要自建更新源时才需要读。
默认状态已经是安全的:端点为空,应用不做任何更新检查。品牌构建默认不签名,官方发布流水线的 Apple / Windows 签名密钥与更新私钥只服务于官方 Qwen Code——品牌方需要签名发布或应用内更新时,必须自备独立凭据和独立更新源,绝不复用上游密钥。
自建更新源的第一步是生成密钥对:
npx @tauri-apps/cli signer generate -w ~/.tauri/my-brand.key.key是私钥,在构建 CI 里设为TAURI_SIGNING_PRIVATE_KEY;配套的.pub是 base64 公钥,写进brand.json的updaterPubkey。
脚本在配置加载阶段强制校验:updaterEndpoints非空而updaterPubkey缺失,直接报错。理由很直接——更新器用这把公钥校验每次更新的签名,若拿官方公钥配自建源(或干脆没有公钥),所有更新检查都会校验失败,应用永远无法更新。这属于“填错了不报错、只静默失效”的字段,必须在入口拦住。
🧾 验什么,现场怎么留
这一节给打包后的验证清单和失败场景速查。
打包后验证四步:
- 确认产物落在对应平台的
bundle/目录(dmg/、nsis/、appimage/或deb/,交叉编译走<triple>路径); - 对每个产物算哈希(
sha256sum,macOS 用shasum -a 256); - macOS 下对 DMG 追加
hdiutil verify; - 向用户报告:产物路径、SHA-256、应用名、appId、构建目录。
失败场景速查:
| 场景 | 处理 |
|---|---|
brandId非法 | 展示正则^[a-z][a-z0-9-]*$,请用户修正 |
| logo 路径无效 | 请提供存在的本地文件路径 |
| 内置脚本缺失 | 报告brand-create.mjs不存在,并给出预期命令 |
| shell-root 已品牌化 | 脚本拒绝运行,必须从全新克隆开始 |
| 构建失败 | 保留构建目录,取最后有用的错误行与日志路径 |
两条铁律:
- 失败时不删构建目录——它是事后排查的现场,不是“清空重试”的对象;
- 绝不在同一克隆里重跑
brand-create——脚本是单次使用的,品牌配置错了就丢弃克隆从头再来。
快速回看
- 最小输入:
brandId+ logo 路径(外加可选website),其余字段由脚本确定性派生; - 最易翻车的一步:交叉编译——每次
tauri build --target前必须带QWEN_DESKTOP_TARGET重跑build:runtime,否则产物内嵌错误架构的 Node; - 产物去哪找:
src-tauri/target[/<triple>]/release/bundle/下的dmg//nsis//appimage//deb/,报告时附哈希; - 失败留什么:构建目录 + 最后错误行;重跑时丢弃克隆,绝不在同一棵树上二次打补丁。
【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考