feat(desktop): bridge Electron users to Tauri updates - #8392
Conversation
|
🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. Remove the 中文说明🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。移除 |
|
Thanks for the PR! Re-run after two commits landed since the last pass: the bridge review follow-ups ( Template looks good ✓ Problem: this is a real infrastructure need, not theoretical hardening. Electron Direction: aligned. The project is moving to Tauri ( Size: not applicable — no core paths touched. 382 additions / 24 deletions across 7 files, all in Approach: the scope still feels right. Each piece serves the stated goal — identity adoption in Risk: no elevated risk signals — none of the changed files match the revert-correlated high-risk paths. Moving on to code review. 🔍 中文说明感谢贡献! 这是在上次审查之后又新增了两个 commit(桥接 review 跟进修改 模板完整 ✓ 问题:这是一个真实的基础设施需求,不是理论性加固。Electron 方向:对齐。项目正在迁移到 Tauri( 规模:不适用——未触及核心路径。7 个文件,+382 / −24,全部在 方案:范围依然合理。每个部分都服务于既定目标—— 风险:无升级风险信号——变更文件均未命中与 revert 相关的高风险路径。 进入代码审查 🔍 — Qwen Code · qwen3.8-max-preview Reviewed at |
Code reviewThis pass covers the current head, including the two commits since the last review: the follow-up round (dropped the My independent proposal for this problem: adopt the legacy app identity in the Tauri config, emit Re-verified against this head:
Two non-blocking notes:
No critical blockers or AGENTS.md violations. Testing evidenceWhat this comment carries: the PR's own CI results for the reviewed commit (fetched via API), plus — clearly attributed, not re-run here — the maintainer's local verification report. The full-profile Not verified here, and why: wenshao (maintainer; approved this head) posted a local verification report for
中文说明代码审查本轮覆盖当前 head,包括上次审查后的两个 commit:跟进轮(从 manifest 脚本移除 我的独立方案:在 Tauri 配置中采用旧版应用身份、从已签名产物生成 electron-builder 格式的 针对当前 head 复核的要点:
两条非阻塞提醒:
未发现关键阻塞项或 AGENTS.md 违规。 测试证据本条评论携带的证据:被审 commit 的 PR 自身 CI 结果(通过 API 获取),以及——明确标注、未在此重新运行——维护者的本地验证报告。 完整 profile 的 未在此验证的部分及原因:wenshao(维护者,已批准此 head)针对 — Qwen Code · qwen3.8-max-preview Reviewed at |
|
Confidence: 4/5 — same picture as the last pass, now on stronger evidence: a clean, focused infrastructure PR. The two remaining items are a small CI filter gap (non-blocking, noted in Stage 2) and the signed end-to-end rehearsal, which is a release-time step by design, not a merge blocker. Stepping back: the new commits made a good PR slightly better — the manifest script got simpler (no If I have to maintain this in six months, the answer is thank the author: the bridge is a one-time opt-in flag; once the migration is done the flag stays off and the code is inert. The identity change, the fallback credentials, and the feed layout are all documented in the design doc committed with the PR. Approval guardrail does not apply (in-repo branch, 中文说明置信度:4/5——与上一轮结论一致,且证据更充分:一个干净、专注的基础设施 PR。剩余两项是小的 CI 过滤缺口(非阻塞,已在 Stage 2 指出)和签名端到端演练——后者按设计是发布时步骤,不是合并阻塞项。 退一步看:新的 commit 让一个好 PR 更好了一点——manifest 脚本更简单(移除了 如果六个月后要维护它,答案是感谢作者:桥接是一次性可选开关,迁移完成后开关保持关闭,代码即为惰性。身份变更、回退凭据和 feed 布局都记录在随 PR 提交的设计文档中。 批准护栏不适用(仓库内分支、 — Qwen Code · qwen3.8-max-preview Reviewed at |
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
doudouOUC
left a comment
There was a problem hiding this comment.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline. Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
中文说明
已审查——无阻断问题。 建议见行内评论。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
— qwen3.8-max-preview via Qwen Code /review (v0.21.3)
|
🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下: Address Review Summary — PR #8392Feedback points[rc:3699956836] Suggestion: add negative test cases for
|
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
中文说明
未发现问题。LGTM!✅
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
— qwen3.8-max-preview via Qwen Code /review (v0.21.3)
Local verification reportI built and exercised this PR in a real local environment rather than reading the diff. The short version: the bridge mechanism works end to end against the real published Environment — macOS (Darwin 25.6.0) on Apple Silicon, Node 22.23.2 (same major as the workflow's 1. The generated
|
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 145 passed · 0 failed · 145 total 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:145 通过 · 0 失败 · 145 总计 Verification reportPR 8392 Deep Verification — feat(desktop): bridge Electron users to Tauri updatesVerdict: 中文摘要
ScopeCentral claim: with Secondary claims: (1) the gate is inert for normal releases and the This is a workflow/scripts PR — no compiled package code changes — so the A/B A/B: version gate classification matrix (Harness A — 22/22)Each cell executes the
The A/B:
|
| oracle stage (shipped 6.8.2 code) | result |
|---|---|
Provider.parseUpdateInfo (js-yaml load) |
parses; version: 0.0.6; quoted ISO releaseDate ✔ |
semver.parse(info.version) + semver.gt(_, '0.0.5') (AppUpdater logic) |
0.0.5 client sees an update ✔ |
files[] content |
exactly the 4 bridge artifacts; planted decoys (extra.zip, .blockmap, stale latest-mac.yml, desktop-latest.json) excluded ✔ |
| sha512/size per entry | match recomputed SHA-512 and byte length of the real files ✔ |
top-level path/sha512 (legacy fallback shape) |
arm64 zip + its hash ✔ |
Provider.resolveFiles + MacUpdater arm64 filter + Provider.findFile(files,'zip',['pkg','dmg']) |
arm64 mac → …/desktop-latest/Qwen-Code-Desktop-arm64.zip; x64 mac → …/Qwen-Code-Desktop-x64.zip ✔ |
getChannelFilename('latest-mac') |
the generic provider fetches exactly latest-mac.yml ✔ |
Hostile cells (all fail loud with the offending name in the message): each of
the 4 artifacts missing individually; --version of 0.1, 1..0, 1.0.0-,
v1.0.0, 1.0.0; rm -rf /; missing --output/--assets; dangling flag.
Base arm: create-electron-bridge-manifest.mjs does not exist at HEAD^1
and the base publish step has no bridge branch — the capability is new.
Witness: 02-manifest-wire-oracle-electron-updater.png.
Coexistence (Harness G): running the pre-existing
create-desktop-update-manifest.mjs over a release-assets dir containing all
five bridge assets still resolves exactly one artifact per Tauri platform —
the two updater views do not collide.
Secondary claims
- Collect artifacts rename loop (Harness C — 11/11). A candidate
stale-variable bug (the new*.dmg/*.zipcase branches do not set
stem/extension) was disproved: the loop re-initialises both
variables each iteration (verified in source). The verbatim block was then
executed under threefindorders — APFS-like name-sorted, a hostile
.app.tar.gz-first order, and the realfindbinary — producing
byte-identical destination sets in all three (Qwen-Code-Desktop-arm64.dmg,
-arm64.zip,-aarch64-apple-darwin.app.tar.gz(.sig)), with a planted
.siginside the.appbundle correctly never collected. Linux passthrough
unchanged. Witness:03-collect-artifacts-three-orders.png. - Reviewer Test Plan step 1 (Harness D — 8/8).
npm run test:releasein
packages/desktop-shellpasses on the real tree. Vacuity: three single-point
mutations in scratch copies were each killed by the intended assertion with an
expected-vs-actual mismatch — sha512→sha256 (sha regex mismatch), identifier
revert (com.qwen.code.desktopvscom.alibaba.qwen-code), workflow losing
electron_bridge:. Unmutated scratch control is green. Witness:
04-test-release-vacuity-mutations.png. - smoke-packaged identifier wiring (Harness E — 2/2). A fake packaged app
that logs under the identifier read fromtauri.conf.json(as the real
bundle does) is found by head's smoke (ready + shell/bearer checks pass); a
mutant carrying the pre-PR hardcodedcom.qwen.code.desktoptimes out. The
config-derived appId is load-bearing under the adopted identity. Witness:
05-smoke-identifier-ab.png.
Gates (Harness F 55/55, Harness G 13/13)
- All 26
shell: bashrun blocks extracted verbatim from the parsed YAML:
bash -nclean, shellcheck (repo flags--enable=all --severity=style
minus the repo's exclusions) shows zero error/warning findings (161
style notes, informational — the repo's shellcheck gate lints tracked.sh
files only; actionlint runs-shellcheck=). Witness:
06-embedded-bash-gates.png. Liveness proven for both instruments (planted
syntax error / unquoted expansion caught). actionlintwith the repo's exact invocation: clean on all workflows, zero
findings indesktop-release.yml; liveness proven (plantedinputs.verson
typo flagged, exit 1).prettier --checkclean on all 7 changed files;eslintclean on the new
script, liveness proven (planted unused variable flagged).yamllintcould not run: the container has no pip
(python3 -m pip→ "No module named pip"). Environmental, proven — see Not
covered.
Findings (all nits — non-blocking)
- Nit — gate arithmetic on absurd versions is noisy but still classifies
correctly.INPUT_VERSION=99999999999999999999.0.0with
electron_bridge=truepasses the gate while printing
[: 99999999999999999999: integer expression expectedinto the job log
(measured). Since an overflowing component only ever makes an-eq/-le
test fail, the outcome is accept — which is the semantically correct
answer for any version that large, and the client-side
semver.parsein electron-updater rejects such a version anyway
(ERR_UPDATER_INVALID_VERSION). Cosmetic only; no misclassification path
found (reject requires all three tests to pass). If the log noise is
unwanted, a length guard ([ ${#patch} -le 9 ]) before the arithmetic
suffices. - Nit —
parseArgumentsin the manifest script silently accepts unknown
flags (--bogus x→ exit 0, measured). The script has exactly one
caller (the publish step); harmless, but a strictness check would be cheap. - Nit — the script's
--versionregex and the workflow's semver regex
diverge on double-suffix versions (0.1.0-rc.1+build.2: accepted by the
script, rejected by the workflow, both measured). Unreachable in CI because
the workflow validates first; recorded so nobody assumes the two regexes
are interchangeable. Related pre-existing looseness (not introduced here):
the workflow regex accepts leading zeros (00.0.6measured accepted; the
same regex exists atHEAD^1).
Not covered
- yamllint gate — unrunnable in this container (no pip module; the repo's
installerpip3 install --user yamllintfails with "Permission denied" /
missing pip). Every other repo gate ran. - Reviewer Test Plan steps 2–3 (dry-run of the Desktop Release workflow;
0.0.5 → Tauri bridge → newer Taurion real signed builds) — require
macOS runners, Apple signing/notarization secrets, and a real Electron
0.0.5 client, none of which exist in this Linux container. This round
reproduces the wire shape those steps depend on (exact bytes/format
electron-updater 6.8.2 consumes; rename/collect logic; productName pin),
not the signed end-to-end hop. The PR itself lists this hop as its remaining
risk. Create Electron bridge archivestep —dittois macOS-only; the
step'sfind -name 'Qwen Code Desktop.app'target was verified statically
against the pinnedproductName(Harness D's identity assertions), not by
producing a real bundle.packages/desktop-shellnpm testiscargo test; the container has
no Rust toolchain (command -v cargo→ absent).- Windows/pwsh blocks — no PowerShell here; actionlint covers their
expression-level correctness only. - Per-commit attribution — metadata lists 4 commits; the depth-2
merge-ref checkout reaches only 1 (git rev-list HEAD^1..HEAD^2= 1,
shallow-grafted). The aggregateHEAD^1..HEADdiff was verified. - Actual release publication (
gh release create/upload) — the sandbox
has no GitHub token by design; the publish/feed blocks were verified as
extracted bash withghnot invoked.
Methodology
Environment: the CI verify container (node:22-bookworm, node v22.23.2, npm
10.9.8), working tree at refs/pull/8392/merge. Because the PR changes only
workflow YAML and source-level node scripts (no compiled workspace output is
executed by any harness), the base arm needed no worktree or rebuild: base
cells extract the identical artifact via git show HEAD^1:…, and the
internal-workspace symlink hazard does not apply. Workflow run blocks were
extracted by parsing the YAML with the repo's own js-yaml and executed
verbatim under bash --noprofile --norc with the step's env: mapping
(harness-a, -c, -f); ${{ }} expressions were replaced by neutral
placeholders, the same treatment actionlint applies. The wire oracle
installed electron-updater@6.8.2 (the exact version pinned by
packages/desktop/bun.lock) from the npm registry into a scratch directory
and drove its compiled Provider.js/util.js exports plus the MacUpdater
filter logic read verbatim from MacUpdater.js. Harnesses live in
harness/*.mjs (rerunnable), raw logs in logs/, per-harness counts in
logs/*.counts.json; evidence captures were produced with
scripts/verify-capture.mjs.
Evidence images
Harness scripts and raw logs are in the workflow run artifacts (7-day retention).
— Qwen Code · sandboxed verification
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix review round — no action requiredThe only feedback newer than the last evaluation is @wenshao's hands-on local verification report, which concludes the bridge mechanism is sound, reproduces the failure and success paths against the real published artifacts and the real Triage of every point in the report:
No verification commands were run this round because no change was made. 中文说明Autofix 审查轮次 —— 无需任何改动上次评估之后唯一的新反馈是 @wenshao 的本地实机验证报告。该报告结论为桥接机制成立:针对真实已发布的发布资产和真实的 报告中每一点的分类处理如下:
本轮未做任何改动,因此未运行任何验证命令。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
|
Released in v0.21.5. |












What this PR does
This PR adds an opt-in, one-time macOS update bridge from the published Electron desktop app to the Tauri desktop shell. The Tauri bundle adopts the existing
Qwen Code Desktopname andcom.alibaba.qwen-codeidentifier, and the release workflow can publish legacy Electron ZIP/DMG assets pluslatest-mac.ymlalongside the normal signed Tauri updater manifest.The macOS release jobs can reuse the existing Electron-era signing and notarization secrets as complete credential sets. The packaged smoke test now reads the bundle identifier from the Tauri configuration so release validation follows the same identity.
Why it's needed
Electron
0.0.5readslatest-mac.ymlfrom the fixeddesktop-latestrelease. It cannot discover the Tauri JSON feed, and a Tauri bundle with a different name and identifier cannot safely replace the installed Electron app. The bridge lets existing macOS users cross to Tauri through the updater they already have; later releases continue on the Tauri updater without retaining Electron build tooling.Reviewer Test Plan
How to verify
Desktop Releaseworkflow as a dry run withelectron_bridge=trueand confirm both macOS jobs produce aQwen Code Desktop.appand the architecture-specific legacy ZIP while the normal Tauri updater archives remain present.0.0.5 -> Tauri bridge -> newer Taurion both arm64 and x64. The stabledesktop-latestrelease should retainlatest-mac.ymland the four legacy assets after later Tauri-only releases updatedesktop-latest.json.Evidence (Before & After)
N/A — release infrastructure and application identity only; no UI change.
Tested on
Environment (optional)
macOS arm64, Node.js 22.22.0. A local unsigned Tauri app bundle was produced as
Qwen Code Desktop.app; its bundle identifier iscom.alibaba.qwen-code.Risk & Scope
0.0.5, andTAURI_SIGNING_PRIVATE_KEYmust match the checked-in updater public key.Linked Issues
None — this migration was requested directly.
中文说明
这个 PR 做了什么
这个 PR 增加了一个可选、仅需执行一次的 macOS 自动更新桥接,让已发布的 Electron 桌面应用可以升级到 Tauri 桌面壳。Tauri 包采用现有的
Qwen Code Desktop名称和com.alibaba.qwen-code标识;发布流程可以在正常的 Tauri 签名更新清单之外,同时发布兼容旧 Electron 更新器的 ZIP、DMG 和latest-mac.yml。macOS 发布任务可以按完整凭据组复用 Electron 时代已有的签名和公证 secrets。打包 smoke 测试现在直接从 Tauri 配置读取 bundle identifier,确保发布验证与应用身份保持一致。
为什么需要
Electron
0.0.5会读取固定desktop-latestRelease 中的latest-mac.yml。它无法发现 Tauri 的 JSON 更新源,而名称和 identifier 不同的 Tauri 包也无法安全覆盖已安装的 Electron 应用。这个桥接让现有 macOS 用户通过当前已有的更新器迁移到 Tauri;后续版本继续使用 Tauri updater,不需要长期保留 Electron 构建工具链。Reviewer 测试计划
如何验证
electron_bridge=true对Desktop Releaseworkflow 执行 dry run,确认两个 macOS 任务都生成Qwen Code Desktop.app和对应架构的旧版 ZIP,同时保留正常的 Tauri updater 归档。Electron 0.0.5 -> Tauri 桥接版 -> 更新的 Tauri。后续仅发布 Tauri 的版本更新desktop-latest.json后,稳定的desktop-latestRelease 应继续保留latest-mac.yml和四个旧版资产。证据(Before & After)
N/A——仅涉及发布基础设施和应用身份,没有 UI 变化。
测试平台
环境(可选)
macOS arm64,Node.js 22.22.0。本地已成功生成未签名的 Tauri 应用
Qwen Code Desktop.app,bundle identifier 为com.alibaba.qwen-code。风险与范围
0.0.5,并且TAURI_SIGNING_PRIVATE_KEY必须与仓库中的 updater 公钥匹配。关联 Issue
无——这项迁移由维护者直接提出。