Repository navigation
chore(desktop): rename packages/desktop-shell to packages/desktop - #12653
Conversation
The Electron-era packages/desktop was removed in #9085 and the OpenWork downstream has forked, so the short name is free and the shell suffix is the only thing left of the transition. Rename the package directory and every load-bearing reference: workspace negations (npm + pnpm), the ci.yml crate filter, desktop-release.yml, the isolation guard, lint/ignore configs, scripts tests, CLI workspace-fixture tests, and living docs. User-facing identity is untouched: the crate stays qwen-code-desktop, productName stays "Qwen Code Desktop", the bundle identifier, updater feed, release tag scheme, and the legacy electron-bridge asset names are all unchanged. check-desktop-isolation now guards both path names so the old one cannot re-enter a workspace set. Dated design docs under docs/design/ keep their historical paths deliberately. Refs #8596
The web-shell-browser-notification-details pair is a living doc without a date prefix, so it falls under the PR's update rule rather than the historical-record exception.
Three prose sites and one CI comment still described the pre-rename world, or contradicted themselves once `packages/desktop` named both the removed Electron app and the living Tauri shell. - ci.yml `desktop_shell`: the comment this branch added credited the Cargo.toml guard with keeping "branches from either side of the rename" green. It does not. A pre-rename head's files sit under `packages/desktop-shell`, which the changed-files filter no longer matches, so the job skips before the guard ever runs. Say that, and say what the guard does cover (a head the filter matched because ci.yml itself changed, with no crate at the new path). - docs/design/web-shell-user-message-links.md: "desktop-shell routing" / "desktop-shell clicks" -> "desktop-host", the wording this branch already chose in LinkifiedText.tsx for the same rule. - docs/design/telemetry-runtime-client-attribution-design.md: repoint the `runtime.rs` citation. It backs the live `QWEN_CODE_DESKTOP=1` claim, and the other document of record for that invariant -- the comment in acp-channel-fallback.ts -- was already repointed by this branch, so the two disagreed. Only the path token changes; the doc's dated findings are untouched. - brand-create.mjs / SKILL.md / src-tauri/src/main.rs: name the historical referent as historical (the Electron `packages/desktop` removed in PR 9085) instead of letting it read as a self-reference. In main.rs the citation `packages/desktop/packages/shared/src/config/storage.ts` now looked like a subpath of the file's own package. Rewritten, not deleted: the `QWEN_DEFAULT_WORKSPACE_DIR` clause next to it is the only in-code documentation of that override and still resolves. Deliberately not swept: `scripts/check-desktop-isolation.js`'s `packages/desktop-shell` tripwire, ci.yml's #8132 history comment, `docs/design/9152-architecture-invariant-classification.md` (names both spellings and is accurate), and the date-prefixed `docs/design/2026-07-31-desktop-web-shell-release.md`. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmug1iw422v
…overage
Both invariants fail green today, and this rename is the second time the
crate directory has moved.
`scripts/check-desktop-isolation.js` gained `'packages/desktop'` in
`nativePrefixes` -- the only production-logic line in this branch -- and
nothing read it. Deleting that line leaves the guard's output and exit code
byte-identical, because `isNativeLocation('packages/desktop')` then matches
no remaining prefix; a later PR that drops `!packages/desktop` from the root
workspace list would re-admit the package with CI green.
The `desktop_shell` job names the crate directory in five places (the
changed-files filter, the Cargo.toml guard and its `::notice::` text, the
rust-cache `workspaces:`, and two `working-directory:` values). Nothing
asserted they agree with each other or with a directory that exists, so the
next drift reports a skipped job as a passed one.
The new suite parses both instead of re-running them, and is superset-shaped
on purpose: `nativePrefixes` carries a fourth entry (the
`packages/desktop-shell` tripwire) that nothing negates, and an exact-match
assertion would invite deleting it. The npm/pnpm mirror of the negation list
is already pinned by package-scripts.test.js, so this reads package.json only.
Verified by mutation, each applied alone and then restored: reverting the
filter alternative or either `working-directory` to `packages/desktop-shell`,
dropping `'packages/desktop'` from `nativePrefixes`, and dropping
`!packages/desktop` from package.json all turn this suite red. Today no other
test does.
Co-authored-by: Qwen-Coder <[email protected]>
Patrol-Run: qwen-pr-closeout/jmug1iw422v
Local real-environment verification — PR #12653 @
|
| Check | Result |
|---|---|
git grep desktop-shell on the test-merge tree (PR + current main) |
10 hits, all deliberate: 2 ci.yml comments, the dated design doc (2 hits), 9152-…classification.md, the guard's tripwire, and the new test (4 hits). The 12 main commits since the branch point added no new old-path references. |
pnpm install --frozen-lockfile at the root |
OK. packages/desktop stays outside the workspace set. |
cargo test in packages/desktop on macOS |
34/34 |
npm run build:runtime + npx tauri build --bundles app |
Qwen Code Desktop.app, 337 MB, bundle id com.alibaba.qwen-code unchanged. The only error was the expected updater-signing message (no TAURI_SIGNING_PRIVATE_KEY locally). |
npm run smoke:packaged -- <.app>/Contents/MacOS/qwen-code-desktop |
Runtime ready in 5.7 s |
node scripts/test-release.js |
passed |
npm run check:desktop-isolation |
passed |
scripts suites: the new desktop-isolation.test.js, plus workspaces, package-scripts, brand-create-safety, desktop-oss-workflow, security-checks-audit-retry, qwen-autofix-workflow |
7 files, 440 passed / 1 skipped |
CLI suites: review/lib/{workspaces,workspace-scope,diff-plan}, review/{build-test,test-efficacy}, config/acp-channel-fallback (run from packages/cli) |
6 files, 383/383 |
Every packages/desktop… path in desktop-release.yml |
All exist in the renamed tree. The diff is path substitutions only. |
Finding 1 — #12649's CI will skip the crate once this lands (confirms the PR's Risk section, measured)
I extracted the Detect desktop changes step from ci.yml verbatim, using a YAML parse. I then ran it against the live GitHub PR-files API, with each PR's head as the working directory:
| Head | Filter from | Output |
|---|---|---|
| #12653 | this PR | changed=true |
#12649 (6f89c26, edits packages/desktop-shell/scripts/{prepare-runtime,test-release}.js) |
main today |
changed=true |
| #12649 | this PR (i.e. after merge) | changed=false: the job skips and reports green |
The merged result itself is correct. git merge-tree of (main + #12653) with #12649 is clean and leaves 0 files under packages/desktop-shell/. Rename detection carries #12649's edits into packages/desktop/scripts/: prepare-runtime.js is byte-identical to #12649's version, and test-release.js differs only by this PR's one-line path change. Only #12649's own PR CI would be blind.
Suggested action: after this merges, #12649 should git merge origin/main (no rebase needed) before it is approved. Its PR-files list then shows packages/desktop/… and the Desktop job runs again. Alternatively, land #12649 first. Either order produces a correct tree.
Finding 2 (non-blocking, pre-existing) — the guard's npm query half is blind on the pnpm tree, and the new test is what covers the gap
I ran a mutation matrix. Each mutant was applied, confirmed with git diff --shortstat, and then restored:
| Mutant | new desktop-isolation.test.js |
check:desktop-isolation |
|---|---|---|
M1 drop 'packages/desktop' from nativePrefixes |
❌ 2 failed | ✅ pass (blind) |
M2 drop "!packages/desktop" from package.json |
❌ 1 failed | ✅ pass (blind) |
M3 filter alternative → packages/desktop-shell/ |
❌ 1 failed | n/a (out of scope) |
M4 cargo working-directory → old path |
❌ 1 failed | n/a |
M5 rust-cache workspaces → old path |
❌ 1 failed | n/a |
M6 Cargo.toml guard → old path |
❌ 1 failed | n/a |
M7 test-release working-directory → old path |
❌ 1 failed | n/a |
All 7 mutants are killed by the new test, which matches the PR's mutation claims. M2 is the interesting one. CI runs check:desktop-isolation after corepack pnpm install, and on a pnpm-laid-out node_modules, npm query .workspace returns only 7 packages (acp-bridge, channels/base, cli, core, sdk-typescript, web-shell, web-templates). So a packages/desktop that re-enters the npm workspaces list never shows up there.
The guard still has teeth through its lockfile-importer half. As a positive control, I dropped the negation from both package.json and pnpm-workspace.yaml and ran pnpm install --lockfile-only. The guard then fails with Root pnpm-lock.yaml should not contain native package importers: packages/desktop. So "guards the new path" holds, via the lockfile.
The npm-query half going inert predates this PR and comes from the pnpm migration. This PR doesn't need to fix it, but it is worth a follow-up issue.
Not verified
- A signed or notarized release, and the updater feed, from the renamed path. That needs release secrets, and the next
desktop-v*tag will exercise it. - Windows and Linux crate builds locally. The PR's green
Desktop Shell (windows-2022 / ubuntu-22.04)jobs cover those.
中文说明
本地真实环境验证 — PR #12653 @ b053c21
结论:可以合入,无阻断项。 改名完整,从 packages/desktop 能在 macOS 上构建出真实桌面应用并正常启动。合并顺序上有一件事要处理,涉及 #12649(见发现 1);另有一条关于守卫的说明,不阻断(发现 2)。
环境:macOS 26.6 arm64,Node 22.23.2(按 .nvmrc),cargo 1.97.1,pnpm 11.24.0。另把 PR head 与当前 origin/main d124dd5 做了试合并;main 比分叉点新 12 个提交,合并干净。
截图 1:用改名后的路径执行 npm run build:runtime + tauri build --bundles app,产出 Qwen Code Desktop.app,用隔离的 HOME 启动:内置 qwen serve 起来了,Web Shell 在原生窗口中加载成功。CI 的 Desktop Shell 矩阵只覆盖 ubuntu 和 windows,这是 macOS 这一侧的数据。截图 2 是验证矩阵汇总。
执行项
| 检查 | 结果 |
|---|---|
在试合并树(PR + 当前 main)上 git grep desktop-shell |
10 处命中,全部是有意保留:ci.yml 注释 2 处、带日期的设计文档(2 处)、9152-…classification.md、守卫里的 tripwire、新测试(4 处)。分叉点之后 main 新增的 12 个提交没有带进新的旧路径引用 |
根目录 pnpm install --frozen-lockfile |
通过,packages/desktop 不在 workspace 集合内 |
macOS 上在 packages/desktop 跑 cargo test |
34/34 |
npm run build:runtime + npx tauri build --bundles app |
Qwen Code Desktop.app,337 MB,bundle id com.alibaba.qwen-code 未变;唯一的报错是预期内的 updater 签名提示(本地没有 TAURI_SIGNING_PRIVATE_KEY) |
npm run smoke:packaged |
5.7 s runtime ready |
node scripts/test-release.js |
通过 |
npm run check:desktop-isolation |
通过 |
scripts 套件:新增的 desktop-isolation.test.js,外加 workspaces、package-scripts、brand-create-safety、desktop-oss-workflow、security-checks-audit-retry、qwen-autofix-workflow |
7 个文件,440 通过 / 1 跳过 |
CLI 套件(在 packages/cli 目录下跑) |
6 个文件,383/383 |
desktop-release.yml 里引用的每个 packages/desktop… 路径 |
在改名后的树里全部存在,diff 只是路径替换 |
发现 1 — 本 PR 合入后,#12649 的 CI 会跳过 crate 编译(PR 的 Risk 一节所述,已实测确认)
用 YAML 解析把 ci.yml 的 Detect desktop changes 步骤逐字取出,以各 PR 的 head 为工作目录,对线上 GitHub PR-files API 实跑:本 PR 为 changed=true;#12649 用 main 当前的过滤器为 changed=true;#12649 换成本 PR 的过滤器(即合入后)为 changed=false,job 跳过并报绿。
合并结果本身是对的:git merge-tree(main + #12653)⊕ #12649 合并干净,packages/desktop-shell/ 下 0 个文件。改名检测把 #12649 的改动带进了 packages/desktop/scripts/:prepare-runtime.js 与 #12649 的版本逐字节相同,test-release.js 只差本 PR 那一行路径改动。只是 #12649 自己的 PR CI 看不见这些改动。
建议: 本 PR 合入后,#12649 先 git merge origin/main(不需要 rebase)再批准。这样它的 PR-files 列表会变成 packages/desktop/…,Desktop job 重新生效。也可以让 #12649 先合入。两种顺序得到的树都正确。
发现 2(不阻断,既有问题)— 守卫的 npm query 那一半在 pnpm 树上失效,靠新测试补位
变异矩阵(每个变异都先用 git diff --shortstat 确认已生效,再还原):M1–M7 七个变异全部被新测试打红,与 PR 的变异声明一致;守卫对 M1/M2 都放行,看不出问题。M2 的原因是:CI 在 corepack pnpm install 之后才跑 check:desktop-isolation,而在 pnpm 布局的 node_modules 上,npm query .workspace 只返回 7 个包,所以 packages/desktop 重新进入 npm workspaces 时不会在这里出现。
守卫的lockfile importer 那一半依然有效。阳性对照:同时去掉 package.json 和 pnpm-workspace.yaml 里的排除项,再跑 pnpm install --lockfile-only,守卫报 Root pnpm-lock.yaml should not contain native package importers: packages/desktop 并失败。所以「新路径受守卫保护」这一说法成立,靠的是 lockfile 那一半。
npm-query 那一半失效早于本 PR,来自 pnpm 迁移。本 PR 不需要修,但值得开一个后续 issue。
未验证
- 从改名后路径发布签名/公证版本,以及 updater feed:需要发布密钥,下一个
desktop-v*tag 会覆盖到。 - 本地没有编译 Windows/Linux 的 crate:由 PR 上已通过的
Desktop Shell (windows-2022 / ubuntu-22.04)覆盖。
Four review findings on scripts/tests/desktop-isolation.test.js, each verified by mutating the thing it claims to pin, before and after. - The comment above the local `isNativeLocation` copy claimed a change to the script's rule "has to be made here too". Nothing reads the rule back from the producer -- `nativePrefixesFromSource` parses the array literal only -- and narrowing the script's rule to prefix equality leaves the suite green. Describe the copy instead of claiming coupling that does not exist. - `still carries the Cargo.toml existence guard` matched only the guard's condition text. Flip the body's `changed=false` to `changed=true`, or move it after `fi`, and the suite stayed green at 5/5 while the job runs every gated step against a crate that is not there. Assert the assignment sits inside the guard's own `if ... fi` body. - Both on-disk checks keyed on the bare directory, so git-ignored residue under `packages/desktop-shell` (`node_modules`, which survives a branch switch with an empty `git status`) reddened two tests on a tree with no defect and blamed the root workspace set. Key on `package.json`, which is what `packages/*` requires to make a directory a workspace member; a real re-entry still reddens both. - The `startsWith(filterAlternative)` assertion compared a path built from `crateDir` -- `filterAlternative` with one trailing slash stripped -- back against `filterAlternative`, so it could not fail for any input. Dropping the trailing slash from the changed-files filter in ci.yml left it green. Replace it with the property that makes the alternative a path prefix rather than a bare string prefix. Co-authored-by: Qwen-Coder <[email protected]> Patrol-Run: qwen-pr-closeout/jmugedurp3j
Brings the branch up to date with main (78faaec), including #12649, which edited packages/desktop-shell/scripts/prepare-runtime.js and test-release.js at the pre-rename path. Rename detection carried both edits into the new packages/desktop path: prepare-runtime.js takes main's blob verbatim, and test-release.js keeps main's degrade-arm comment rewrite at line 771 together with this PR's path change at line 530. package.json keeps both sides: main's @lydell/node-pty-linux-arm64 pin and 0.24.5 version bump, plus this PR's !packages/desktop workspace negation. packages/desktop-shell is absent from the merged tree. Co-authored-by: Qwen-Coder <[email protected]>
yiliang114
left a comment
There was a problem hiding this comment.
Review at 65afaeb (author is myself — this COMMENT is the record; a non-author maintainer vote is needed to clear REVIEW_REQUIRED).
No blocking findings on a rename this size (121 files):
- Completeness verified at the tree level: zero
desktop-shellpaths remain in the head's git tree (10,293 entries walked), and everydesktop-shellhit in the diff is either a removed line or a deliberate historical note in comments. New references consistently usepackages/desktop, including the rootpackage.jsonworkspace exclusion. - CI wiring updated coherently: the path filter, the Cargo.toml presence guard, rust-cache workspaces, and both
working-directoryentries all moved together; the Desktop Shell lanes (ubuntu-22.04 + windows-2022) are green on this head, which is the only lane that actually compiles the crate. - The one real trade-off is disclosed in the workflow comment itself: a pre-rename branch (files still under
packages/desktop-shell) no longer matches the filter and would report green having compiled nothing — the comment states such branches need a rebase to be gated again. That's the honest answer for a rename and acceptable: those branches must rebase before merge anyway. - The review-lib path updates (workspaces.ts, workspace-scope, build-test, test-efficacy) are mechanical renames with their tests updated to match; the
desktop-brand-builderskill's relative paths follow the move.
CI green except review-pr (queued, bot infrastructure) and web-shell E2E Smoke (queued). All 8 threads resolved.
chiga0
left a comment
There was a problem hiding this comment.
No blocking findings.
Approval blockers: none.
Scope: 121 files, 402 additions / 204 deletions. ~96 pure renames (packages/desktop-shell/* → packages/desktop/*) plus targeted path-string substitutions in CI workflows, root workspace manifests, tool configs, docs, test fixtures, and two CLI workspaces source files (comment-only updates). One production-logic change: check-desktop-isolation.js gains 'packages/desktop' in nativePrefixes. New test: scripts/tests/desktop-isolation.test.js.
Checked:
-
Workspace isolation coherence (class 1 — writer/reader contract):
package.jsonworkspace negation (!packages/desktop),pnpm-workspace.yamlexclusion,check-desktop-isolation.jsnativePrefixes, andpnpm-worktree-smoke.ymlpath filters all updated consistently.packages/desktop-shellkept innativePrefixesas a re-entry tripwire — deliberate and documented. -
CI wiring (class 1): The
desktop_shelljob's five crate-path references (changed-files filter alternative, Cargo.toml existence guard, guard::notice::text, rust-cacheworkspaces:, bothworking-directory:values) all move together topackages/desktop.desktop-isolation.test.jspins all five sites to agree, existence-checksCargo.toml, and verifies the filter alternative carries a trailing/(preventing prefix collision with any future sibling namedpackages/desktop-extraor similar). -
Pre-rename branch skip risk: Explicitly documented in both the PR description and the ci.yml job comment. A branch still at
packages/desktop-shell/no longer matches the filter and reports green having compiled nothing. Not a defect introduced here — it is the acknowledged trade-off of a directory rename. The Cargo.toml existence guard continues to cover the complementary case (filter matched because ci.yml itself changed, crate absent at the new path). -
npm package name (
@qwen-code/desktop-shell→@qwen-code/desktop):private: truethroughout — no published consumer can break. -
Callers of renamed path strings (class 2):
acp-channel-fallback.ts,LinkifiedText.tsx,web-shell/client/index.html,.qwen/skillsreferences, docs all updated.LinkifiedText.tsx:9deliberately usesdesktop-host routing(notdesktop routing); per the author's thread reply, this is the terminology adopted in the living docs. -
Deliberate
desktop-shellsurvivors (class 10 — stated intent): the isolation-guard tripwire incheck-desktop-isolation.js, two ci.yml comment lines naming both sides of the rename,docs/design/9152-architecture-invariant-classification.md(names both spellings accurately), and the date-prefixeddocs/design/2026-07-31-desktop-web-shell-release.md(historical record). All are correct per the PR description. -
desktop-isolation.test.jstest validity (class 5): The guard-body assertion now pinschanged=falseinside theif..then..fiblock (not just the condition text), fixing R2-2. The pre-rename tripwire checkspackages/desktop-shell/package.jsonexistence rather than the bare directory, fixing R2-3 (build residue under the old path would no longer produce a false positive). The prior tautologicalstartsWithassertion (R2-4) is absent from the current head. -
Binary renames (icons, images): All shown as similarity-100 renames in the diff — no content changes, only path moves.
Not covered: local execution of the vitest suite (no node_modules available); Windows path behaviour; CI matrix runs (delegated to the Desktop Shell CI job on this PR).
Reviewed with AI assistance.
qqqys
left a comment
There was a problem hiding this comment.
Critical-only review at 65afaeb9, base 78faaec8.
Verdict: APPROVE — no Critical, and no blocking issue was ever filed here. For a 121-file rename the thing to verify is not the moved bytes but every reference that has to keep resolving, so that is what I checked: the load-bearing ones all point at the new path, and the two places that still name the old one are deliberate.
The rename is coherent across everything that resolves a path
Both workspace negations moved together — "!packages/desktop" in the root package.json workspaces array and '!packages/desktop' in pnpm-workspace.yaml. That pair matters more than the rest: the release set is derived from the workspace globs, so a negation left behind at the old path would have pulled packages/desktop into RELEASE_WORKSPACES and into a publish step that has no business publishing it. It is also private: true, so the exclusion is doubled rather than resting on one mechanism.
In ci.yml the changed-files filter, the rust-cache workspaces: key and both working-directory: values all read packages/desktop. desktop-release.yml, eslint.config.js and .prettierignore contain zero occurrences of the old name at this head. Of the 121 files, the overwhelming majority are pure renames with no content change; the substantive edits are the reference updates above plus comments.
Both remaining references to the old path are intentional, and I read them rather than counting them
scripts/check-desktop-isolation.js keeps packages/desktop-shell in nativePrefixes alongside the new packages/desktop, with the reason stated: nothing should be created under the pre-rename location again, and it must never enter a workspace set. Dropping it would have removed the tripwire exactly when a stale branch is most likely to recreate the directory.
The two occurrences in ci.yml are inside the comment that documents the rename's own hazard, and the job carries two guards plus one disclosed gap:
- The changed-files filter includes
.previous_filenameas well as.filename, with the comment naming why — renaming a file out of the crate changes it, and only the old path says so. Without that, moving a source file out ofpackages/desktop/would not trigger the crate compile. - The Cargo.toml existence guard sets
changed=falsewith a::notice::when the filter matched butpackages/desktop/src-tauri/Cargo.tomlis absent, so a pre-rename head that matched only becauseci.ymlitself changed does not fail with a missing working directory blamed on the PR. - The gap is disclosed rather than papered over: a pre-rename head's files sit under the old path, the filter no longer matches, the job skips and reports green having compiled nothing, and because a 100%-similarity directory rename merges cleanly with an edit to the old path, such a branch reports no conflict either. Those branches need a rebase. The description also records that widening the filter to
packages/desktop(-shell)?/was considered and rejected, with the reasoning — on its own it is a no-op, since the guard would setchanged=falseanyway, and making it real means resolving a crate directory and plumbing it into four sites, which is a transition-window redesign rather than a rename.
scripts/tests/desktop-isolation.test.js is what keeps that coherent: it pins all five ci.yml crate-path sites to one directory, asserts that directory's src-tauri/Cargo.toml exists, and pins nativePrefixes superset-shaped against the root workspace negations so the old-path tripwire stays legal. The description reports it was verified by mutation — reverting the filter alternative or either working-directory, dropping packages/desktop from nativePrefixes, or dropping !packages/desktop from package.json each turns it red. That is the right shape of test for a rename, where the failure mode is a reference nobody greps for.
The non-mechanical edits are corrections the rename forced
packages/cli/src/commands/review/lib/workspaces.ts changes nine lines and every one is inside a comment: the negation-ownership examples that used packages/desktop-shell as their illustration now use packages/desktop, with the surrounding reasoning about fallback ownership preserved verbatim. No logic moves.
packages/desktop/src-tauri/src/main.rs changes two comment lines, and it is the most interesting edit in the diff. The old comment cited packages/desktop/packages/shared/src/config/storage.ts — a path belonging to the Electron package #9085 removed, which was already dead. Left alone, this rename would have made that dead citation look live again, since packages/desktop now exists and means something different. It is rewritten to name the removed Electron package and the PR that removed it. That is the class of error a rename produces and a grep for the old name cannot find.
One item in Risk & Scope is now stale, in the harmless direction
The description says #12649 is open and edits packages/desktop-shell/scripts/prepare-runtime.js and test-release.js, and should be rebased onto this rename before merging. #12649 merged to main since this branch last took main, so that ordering advice no longer applies. The outcome is still the one the description relies on elsewhere: a 100%-similarity rename merges cleanly with edits made at the old path, so #12649's comment changes follow the files to their new location rather than being lost, and GitHub reports this PR MERGEABLE against a main that contains them. Worth a line in the description so the next reader does not act on advice that has already been overtaken, and worth knowing that the two files #12649 touched are exactly the ones the skipped node scripts/test-release.js step exercises — which is the concrete form of the rebase gap documented above.
CI
28 checks pass and 26 are skipped at this head, with web-shell E2E Smoke and review-pr pending and nothing failing. The lanes that would catch a missed reference are green: both Desktop Shell lanes, which compile the crate at its new path, all three Install lanes, which would fail on an incoherent workspace set, Test (ubuntu-latest, Node 22.x), Lint & Static and Integration Tests (no-AK, No Sandbox). I did not wait on the two pending lanes. No review thread is unresolved.
The one thing no lane can verify here is the actual desktop release from the renamed path — the workflow edits are path substitutions and the next desktop-v* tag is what exercises them, which the description states plainly rather than claiming coverage it does not have.


What this PR does
Renames
packages/desktop-shelltopackages/desktopand updates every load-bearing reference: npm/pnpm workspace negations, theci.ymlcrate filter,desktop-release.yml, the desktop isolation guard, eslint/prettier ignores, scripts and CLI test fixtures, the brand-builder skill, and living docs (docs/developers/architecture.md,.qwen/skills/).The crate name (
qwen-code-desktop),productName("Qwen Code Desktop"), bundle identifier, updater feed,desktop-v*tag scheme, and the legacy electron-bridge asset names are all unchanged — nothing user-facing moves. One name does change: the npm package is now@qwen-code/desktop(it isprivate: true, and the old name appears nowhere outside the package's own manifest and lockfile).Why it's needed
#8596 retired the Electron app; #9085 removed the old
packages/desktop, and the OpenWork downstream has since forked. Thedesktop-shellname is the last artifact of the transition period — the short name is free, and keeping the suffix permanently costs every reader a "which desktop is this?" moment. No open PR touchedpackages/desktop-shellwhen this branch was cut, so this was the quiet window to do it. #12649 has since opened and edits two old-path files — see Risk & Scope.Reviewer Test Plan
How to verify
git diff --statshould show the move as renames with high similarity, plus targeted reference edits — no logic changes.npm run check:desktop-isolation— now guards both the new and the old path.cd packages/desktop && npm ci && npm test— compiles the crate at the new path and runs the Rust suite.node packages/desktop/scripts/test-release.js.npx vitest run src/commands/review/(workspace fixtures) and the scripts tests below.Evidence (Before & After)
packages/desktop-shell; references across 41 files.packages/desktop;git grep desktop-shellreturns only deliberate hits — the isolation-guard tripwire, the twoci.ymlcomments that name both sides of the rename,docs/design/9152-architecture-invariant-classification.md(names both spellings and is accurate), the date-prefixeddocs/design/2026-07-31-desktop-web-shell-release.md(historical record, deliberately not rewritten), and the new test that pins the tripwire.check:desktop-isolation✅; desktop cratecargo test34/34 ✅;test-release.js✅; CLI workspace suites 377/377 ✅;qwen-autofix-workflow.test.js325 passed / 13 skipped ✅; prettier/eslint clean on touched files. (desktop-smoke-teardown.test.jshas 2 SIGTERM timing tests that fail identically on unmodifiedmainon this machine — pre-existing flake, not from this change.)Tested on
Risk & Scope
packages/desktop-shell/, and theci.ymlchanged-files filter no longer matches that path — sodesktop_shellskips those heads and reports green without compiling them. This is not the Cargo.toml existence guard; that one covers the other side (a head the filter matched becauseci.ymlitself changed, with no crate at the new path), and the job comment now says so explicitly.packages/desktop-shell/scripts/prepare-runtime.jsandpackages/desktop-shell/scripts/test-release.js— the exact two files the skippednode scripts/test-release.jsstep exercises. It should be rebased onto this rename before it merges.packages/desktop(-shell)?/was considered and rejected for this PR. On its own it is a no-op: a pre-rename head then matches the filter, and the guard setschanged=falseanyway becausepackages/desktop/src-tauri/Cargo.tomlis absent. Making it real means resolving acrate_dirin the filter step and plumbing it into the guard, the rust-cacheworkspaces:and bothworking-directory:values — a transition-window redesign of the job, out of scope for a rename.scripts/tests/desktop-isolation.test.jspins all fiveci.ymlcrate-path sites to one directory and asserts that directory'ssrc-tauri/Cargo.tomlexists, and pinsnativePrefixes(superset-shaped, so thepackages/desktop-shelltripwire stays legal) against the root workspace negations. Verified by mutation: reverting the filter alternative or eitherworking-directory, dropping'packages/desktop'fromnativePrefixes, or dropping!packages/desktopfrompackage.jsoneach turns it red.desktop-release.yml's probe block (different lines than the path edits here); a rebase should be mechanical.desktop-v*tag exercises it; the workflow edits are path substitutions only.Linked Issues
Refs #8596
中文说明
本 PR 做了什么
把
packages/desktop-shell改名为packages/desktop,并更新所有承重引用:npm/pnpm 的 workspace 排除项、ci.yml的 crate 过滤器、desktop-release.yml、桌面隔离守卫、eslint/prettier 忽略配置、scripts 与 CLI 的测试夹具、brand-builder 技能,以及活跃文档(docs/developers/architecture.md、.qwen/skills/)。crate 名(
qwen-code-desktop)、productName("Qwen Code Desktop")、bundle identifier、updater feed、desktop-v*tag 体系、legacy electron-bridge 产物名全部不变——没有任何用户可见的东西移动。为什么现在做
#8596 退役了 Electron 应用;#9085 删除了旧的
packages/desktop,OpenWork 下游也已 fork。desktop-shell这个名字是过渡期最后的残留——短名字已经空出来,而一直留着后缀会让每个读者都多想一次"这是哪个 desktop"。切出本分支时没有任何 open PR 触碰packages/desktop-shell,正是安静的窗口期。#12649 之后开出来了,改了两个旧路径文件——见「风险与范围」。验证
check:desktop-isolation✅(现在同时守卫新旧两个路径名);桌面条目cargo test34/34 ✅;test-release.js✅;CLI workspace 套件 377/377 ✅;qwen-autofix-workflow.test.js325 通过 / 13 跳过 ✅;改动文件 prettier/eslint 干净。desktop-smoke-teardown.test.js有 2 个 SIGTERM 时序用例在未改动的main上同样失败——预存 flake,与本改动无关。风险与范围
packages/desktop-shell/,而ci.yml的变更文件过滤器已不再匹配该路径——所以desktop_shell会跳过这些 head,并在什么都没编译的情况下报绿。这不是 Cargo.toml 存在性守卫管的:守卫覆盖的是另一侧(过滤器因ci.yml自身变更而命中、但新路径下没有 crate 的 head),任务注释现已明确写出这一点。packages/desktop-shell/scripts/prepare-runtime.js和packages/desktop-shell/scripts/test-release.js——正是被跳过的node scripts/test-release.js所检验的那两个文件。它应在合并前 rebase 到本次改名之上。packages/desktop(-shell)?/,本 PR 不采纳:单独放宽是空操作(改名前的 head 命中过滤器后,守卫仍会因packages/desktop/src-tauri/Cargo.toml不存在而置changed=false)。要真正生效必须在 filter 步骤解析出crate_dir,并把它接到守卫、rust-cache 的workspaces:和两个working-directory:上——那是对该任务的过渡期重构,超出了一个改名 PR 的范围。scripts/tests/desktop-isolation.test.js,把 ci.yml 的五处 crate 路径钉到同一个目录并断言其src-tauri/Cargo.toml存在;同时以超集形态(保留packages/desktop-shell绊线的合法性)把nativePrefixes与根 workspace 的否定项对齐。已做变异验证:把过滤器分支或任一working-directory改回旧名、从nativePrefixes删掉'packages/desktop'、或从package.json删掉!packages/desktop,都会让它变红。desktop-release.yml的探测段(与本 PR 的路径编辑不同行),rebase 应是机械操作。desktop-v*tag 会覆盖;workflow 改动仅为路径替换。