ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Qwen Code Desktop Web Shell 桌面壳发布架构设计:Tauri 薄壳 + 本地 daemon 的三平台实践

Qwen Code Desktop Web Shell 桌面壳发布架构设计:Tauri 薄壳 + 本地 daemon 的三平台实践 Qwen Code Desktop Web Shell 桌面壳发布架构设计Tauri 薄壳 本地 daemon 的三平台实践【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-codeQwen Code 桌面端packages/desktop-shell并不维护第二套 UI而是将 Tauri 壳与 daemon 托管的 Web Shell 组合成一个完整的桌面应用。本文基于 2026-07-31-desktop-web-shell-release.md 展开结合仓库源码详解其整体架构、启动状态机、工作区持久化、Runtime 生命周期、安全边界、构建元数据、签名更新模型与三平台发布矩阵。读完你可以掌握一个薄桌面壳 本地 daemon 现有 Web Shell的发布级落地范式并能在本仓库中定位每项设计的实现与验证代码。背景为什么需要薄壳而不是第二套 UI桌面 PoC 已经证明 Tauri 可以复用 daemon 提供的 Web Shell无需为桌面单独开发聊天界面。但 PoC 缺少公开发布所需的用户流程、故障恢复、签名更新、安全边界和三平台安装产物。本设计把packages/desktop-shell完善为薄桌面壳桌面壳只负责生命周期与平台集成产品功能继续由qwen serve和qwen-code/web-shell提供。设计目标与非目标摘自原设计文档目标macOS、Windows、Linux 使用同一套 Web Shell UI首次启动允许选择工作区后续启动恢复最近工作区daemon 启动失败或运行中退出时提供可操作的恢复界面而非静默退出桌面壳只加载本地 bootstrap 页面与本机随机端口 daemon外部 URL 一律交给系统浏览器发布产物带版本、来源、许可证、校验和与签名更新元数据公共 release 在 macOS 完成签名与公证、Windows 完成 Authenticode 签名Linux 生成 AppImage 和 deb。非目标不新增桌面专属聊天 UI、会话模型或 daemon API不把 Web Shell 复制进桌面包维护不实现多窗口、多工作区同时运行或后台常驻不承诺 Store 分发首个公开版本使用 GitHub Releases不内置 Git、shell 或其他系统工具缺失工具继续由现有 Web Shell 能力反馈。整体架构与组件职责四个组件的职责划分继承自原文档组件职责bootstrap 页面启动状态、工作区选择、失败恢复、版本与日志入口Rust 桌面状态设置持久化、窗口状态、runtime 生命周期、单实例、更新状态bundled runtime当前平台 Node.js、Qwen Code bundle、Web Shell 静态资源发布 CI三平台构建、签名、公证、smoke、校验和、latest.json、GitHub Release从源码看Rust 侧由三个模块承担这些职责main.rs窗口、生命周期、导航边界、更新、runtime.rsdaemon 进程组管理与健康探测、desktop_state.rs设置与窗口状态持久化前端 bootstrap 由 index.html 与 bootstrap.js 实现。启动状态机让慢启动与失败路径都有可见 UI应用先创建 bootstrap 窗口再异步启动 daemon。daemon 深度健康检查/health?deeptrue通过后同一个窗口导航到http://127.0.0.1:port/#tokentoken。token 只存在于 URL fragment 中永远不会随请求发往服务端因此不需要 cookie 握手也不会进入 access log 或 Referer。五种启动状态继承自原文档状态用户看到的内容可用操作startingQwen Code 品牌启动页和当前工作区等待needs_workspace首次启动工作区选择选择目录readydaemon-served Web Shell正常使用failed精简错误摘要重试、选择其他目录、打开日志stoppeddaemon 意外退出提示重启 daemon、选择目录、打开日志bootstrap 页面通过invoke(bootstrap_state)拉取状态快照并监听runtime-starting、runtime-failed、update-available三个事件驱动 UI 切换见 bootstrap.js按钮层提供Choose another workspacechoose_workspace、Retryrestart_runtime、Open logsopen_logs、Install updateinstall_update四个 command且全部经过require_bootstrap_origin校验只有 bootstrap 页面才能调用main.rs。为什么必须用深度健康检查serve fast path 在真正的 runtime含 Web Shell挂载之前会用 bootstrap app 应答浅层/health。此时/health?deeptrue仍返回503 {reason: bootstrap}只有它变为 200 才代表 Web Shell 可用若用浅层健康检查判定就绪导航会撞进 deferred runtime 窗口。runtime.rs 的wait_for_health是这一策略的实现先通过解析 daemon stdout 中的qwen serve listening on http://127.0.0.1:port拿到监听地址再以Authorization: Bearer token轮询health?deeptrue直到响应体包含status:ok。整体启动等待有 45 秒超时STARTUP_TIMEOUT健康探测间隔 100ms、单次请求超时 2 秒启动失败时会把捕获到的 stdout/stderr 摘要上限 16KB按 UTF-8 边界截断拼进错误信息供恢复页展示。工作区选择与持久化设置文件存储于 Tauriapp_config_dir下的desktop-state.jsondesktop_state.rs内容格式如下继承自原文档{ workspace: /absolute/path, window: { width: 1280, height: 820, x: 120, y: 80, maximized: false } }启动优先级继承自原文档QWEN_DESKTOP_WORKSPACE用于开发和自动化测试设置文件中的最近工作区首次启动显示目录选择器。源码中initial_workspace依次检查环境变量与持久化设置都没有时回落到默认工作区main.rs。默认工作区与 Electron 壳保持一致~/Documents/Qwen可通过QWEN_DEFAULT_WORKSPACE_DIR重定向空值视为未设置仍走默认路径首次启动需要创建该目录时创建动作放到主线程之外执行因为首次触碰~/Documents可能触发 macOS 的 TCC 授权弹窗main.rs。细节与边界只有已存在且为目录的绝对规范路径会传给 daemonresolve_workspace使用dunce::canonicalize去掉 Windows\\?\前缀并拒绝残留的 verbatim 路径UNC、超长路径、以点或空格结尾的名称相关拒绝逻辑与测试见 runtime.rs。选择新工作区时先停止当前 process group再用新目录重新启动start_runtime_async开头即stop_runtime。设置写入采用原子写先写desktop-state.json.id.tmp再 renameWindows 上 rename 失败时走备份-替换-回滚路径避免文件损坏desktop_state.rs。smoke 测试可通过QWEN_DESKTOP_DISABLE_SETTINGS_PERSISTENCE1关闭持久化。窗口位置每 300ms 由后台线程做脏检查后落盘恢复时若保存的坐标落在不可见屏幕外则回退到居中restore_window用monitor_from_point判定desktop_state.rs。Runtime 生命周期与恢复桌面壳与 daemon 之间采用每次启动全新实例的模型核心机制如下均继承自原文档并在源码中可验证每次启动生成 256-bit bearer tokenrandom_token用rand::rng().fill_bytes生成 32 字节随机数并编码为 hexruntime.rs。token 通过子进程环境QWEN_SERVER_TOKEN下发给 daemon同时以 URL fragment/#tokentoken交给 Web Shell 前端前端读取后从 URL 中清除并以Authorization: Bearer头调用 API。authenticated_web_url()只把 token 写进 fragmentbase URL 本身不含 token对应测试carries_the_daemon_token_only_in_the_url_fragment。daemon 绑定127.0.0.1随机端口并启用--require-auth实际启动参数为serve --port 0 --hostname 127.0.0.1 --require-auth --workspace ws --no-open由runtime_arguments构造runtime.rs。stdout 与 stderr 同时写入滚动日志desktop-runtime.log位于 app log 目录两个捕获线程分别把行写入带[stdout]/[stderr]前缀的日志文件并保留最多 16KB 的启动摘要供 UI 展示append_failure_output/append_log。Rust 监视 daemon 进程退出monitor_runtime每 250mstry_wait一次非应用退出导致的停止会 emitruntime-process-stopped事件主进程校验runtime_id后清理状态、把窗口导航回 bootstrap 并 emitruntime-failed用户即可在原窗口重试main.rs。重试始终创建新的 token 和 daemon不复用已退出进程每次start_runtime_async都递增start_generation用代数编号丢弃过期的启动结果防止竞态下旧 runtime 覆盖新状态。应用退出时终止整个子进程组避免 orphan daemonUnix 用command_group的group_spawnWindows 则必须通过 group builder 设置CREATE_NO_WINDOW0x08000000——因为 bundled Node 是控制台程序若不设置会弹出可见终端窗口且关闭该窗口会杀掉 runtime对应测试runtime_child_gets_no_windows_console见 runtime.rs。PendingRuntime与共享child句柄的设计保证了启动进行中发生停止应用退出/重启/新启动也能杀掉在途 daemon 而不是让它成为孤儿stop_runtime_handle用Option::take让并发停止幂等对应测试pending_stop_reaps_a_child_taken_from_the_shared_handle。窗口与单实例主窗口最小尺寸 900 × 600默认 1280 × 820常量定义见 desktop_state.rs窗口构建见 main.rs。关闭、移动、缩放和最大化状态持久化恢复时把不可见屏幕外位置回退到居中。最大化状态下保存的是此前普通窗口的边界saved_window_state逻辑。单实例插件必须最先注册tauri_plugin_single_instance是 builder 上第一个插件第二次启动只聚焦并恢复主窗口不再启动 daemonmain.rs。macOS 上还有全屏隐藏的竞态处理关闭时若处于全屏先退出全屏再隐藏通过FULLSCREEN_HIDE_PENDING与代数计数器避免窗口卡在全屏或误隐藏并用RunEvent::Reopen恢复主窗口。安全边界桌面壳把安全边界显式收紧每一条都在源码中有对应实现bootstrap CSP与 tauri.conf.json 及 index.html 的 meta 标签一致继承自原文档default-src self; script-src self; style-src self unsafe-inline; img-src self data:; connect-src ipc: http://ipc.localhost; object-src none; base-uri none; form-action none; frame-ancestors noneWeb Shell 仍由 daemon 生成自身 CSP桌面壳不放宽 daemon 页面策略。主窗口导航白名单on_navigation只放行 bootstrap 自定义协议Windows 为http://tauri.localhost其余平台为tauri://localhost和选定 daemon 的同源导航origin_of强制 runtime URL 必须是http://127.0.0.1上的 loopback 地址is_same_origin严格比较 scheme、host 与端口对应测试allows_only_the_daemon_origin_in_the_main_window、rejects_non_loopback_runtime_origins。外链交给系统浏览器on_new_window只对http、https、mailto放行到系统浏览器并拒绝新窗口file、javascript、自定义协议一律拒绝is_safe_external_url对应测试new_windows_allow_only_browser_safe_schemes。blob 下载仅允许由主 Web Shell 发起且由原生下载回调选择安全目标路径on_download校验当前页面 origin 必须等于 runtime origin 且 URL scheme 为blob。Tauri 不暴露文件系统、shell 或 process JavaScript APIbootstrap 只使用显式invokecommandcapabilities 只授予最小权限——bootstrap.json 仅含事件订阅权限web-shell-external-url.json 仅对http://127.0.0.1:*远程页面开放 opener 的 http/https/mailto 放行。Windows manifest使用asInvoker、Common Controls v6 和 long-path awareness见 windows-app-manifest.xml。macOS hardened runtime 开启entitlements 只包含运行 JIT WebView 与网络 client/server 所需能力见 Entitlements.plist 与 tauri.conf.json 的hardenedRuntime: true。构建元数据与合规prepare-runtime.jsscripts/prepare-runtime.js负责把 Qwen Code bundle 与 Node.js 运行时组装成packages/desktop-shell/runtime/qwen-code/并生成manifest.json桌面版本、Qwen Code 版本、Qwen Code commit、Node 版本、target、构建时间字段见 prepare-runtime.jschecksums.json所有 bundled runtime 文件的 SHA-256递归计算并排序writeChecksums根LICENSE和桌面NOTICENode.jsLICENSE。构建过程的工程细节Node 运行时从 nodejs.org 下载并逐字节校验官方SHASUMS256.txt通过后才落本地缓存QWEN_DESKTOP_NODE_CACHE_DIR可指定缓存目录版本必须匹配仓库.nvmrc的大版本。目标平台通过QWEN_DESKTOP_TARGET或platform-arch推导支持darwin-arm64、darwin-x64、linux-arm64、linux-x64、win32-x64非法 target 直接报错。runtime 目录采用暂存 原子替换先在.prepare-*目录组装成功后 rename 替换现有目录失败回滚并能在下次构建时清理中断残留recoverInterruptedRuntime/replaceRuntime。每个平台还生成bin/qwen或qwen.cmd启动器供在桌面包外以命令行方式使用同一套 bundled runtime。打包前 smoke 会校验 manifest、关键文件和 checksum。GitHub Release 同时发布每个安装产物的SHA256SUMS.txt。更新模型Tauri updater 使用签名更新产物和固定公开 key。稳定发布的安装包和 updater 产物同时保存在 GitHub Releases 与 Aliyun OSS应用优先检查 OSS 的小型更新清单并在请求失败或超时时回退 GitHub。两个清单分别指向同一版本在各自源中的签名产物——这一点在 tauri.conf.json 的 updaterendpoints中直接可见OSS 在前、GitHub 在后并配有 minisign 公钥。应用启动后后台检查一次更新check_updates_silentlymain.rs无更新不打扰用户检查失败写日志不阻塞启动检查带 3 秒超时有更新emitupdate-availablebootstrap/Web Shell 上方显示原生确认对话框用户确认后下载并安装然后request_restart()重启安装失败会弹出明确错误提示并告知用户数据安全。发布 CI 使用TAURI_SIGNING_PRIVATE_KEY与TAURI_SIGNING_PRIVATE_KEY_PASSWORD生成 updater signatures。只有非 draft、非 prerelease 发布会更新 GitHub 的desktop-latestfeed并在校验版本化 OSS 产物后更新 OSS feed。GitHub 始终保留为权威发布源和回退源。平台发布矩阵平台架构安装包签名要求macOSarm64、x64.dmg、.app.tar.gzupdaterDeveloper ID Application notarizationWindowsx64NSIS.exeupdater/installerAuthenticode SHA-256 timestampLinuxx64.AppImageupdater/installer、.debupdater minisign无 OS code-signingTauri bundle 配置tauri.conf.json与矩阵对应targets为[app, dmg, nsis, appimage, deb]且createUpdaterArtifacts: truemacOS 开启 hardened runtime、最低系统版本 11.0Windows NSIS 采用currentUser安装模式、digestAlgorithm: sha256、DigiCert 时间戳服务并挂载electron-migration.nsh处理 Electron 版迁移WebView2 使用 download bootstrapper——系统离线且缺失 WebView2 时安装失败会明确提示依赖Linux CI 安装 Tauri WebKit/GTK、AppImage 和 deb 构建依赖AppImage 关闭 media framework 捆绑以减小体积。发布流程原文档给出 8 步发布流程全部继承如下输入 desktop 版本和需要 vendor 的 Qwen Code ref校验 ref 可追溯到允许发布的提交同步 desktop-shell package、Cargo 和 Tauri 版本。版本仅在每次构建时由 CI 瞬时设置不会提交回仓库main分支有意保持开发占位版本0.0.1已发布版本以 git tag 为准每个平台准备 runtime运行 checksum/runtime smoke 和 Rust 测试cargo test --manifest-path src-tauri/Cargo.toml见 package.json构建安装包和 updater artifacts平台 runner 安装并启动 packaged app等待 daemon/Web Shell ready 证据上传产物发布 job 生成latest.json和SHA256SUMS.txt非 draft stable release 更新 GitHubdesktop-latestfeed将同一批产物同步并校验到 OSS再更新 OSS feed。缺失签名密钥时只允许dry_runtrue公开发布必须 fail closed。验证标准与 smoke 测试原文档的验证标准首次启动能选择目录并进入 Web Shell重启恢复工作区和窗口位置无效工作区、缺失 runtime、daemon 提前退出均显示恢复页daemon 运行中被终止后用户能在原窗口重启外链进入系统浏览器主窗口不离开 daemon origin三平台 packaged app smoke 观测到/health、未认证的 Web Shell root 导航返回 200且不下发任何 cookie、未携带 token 的/capabilities返回 401updater manifest 签名可被客户端验证版本回退被拒绝。这些标准在仓库中有对应的自动化落点smoke-packaged.js 会安装并启动 packaged app等待日志中出现qwen serve listening on http://127.0.0.1:port然后验证未认证导航边界root 导航返回 200 且set-cookie为空token 只走 fragment、服务端不下发 cookie、/capabilities无 token 返回 401macOS 上还会校验 bundle 内 manifest 的qwenCodeCommit与期望 ref 一致。smoke-runtime.js 在同一个 bundle 上覆盖带认证的正常路径。test-release.js 与version.js支撑发布流程中的版本同步与发布预检。Rust 侧单测覆盖了启动参数、token fragment、导航白名单、外链安全、窗口状态序列化、原子写入、默认工作区解析等关键不变量见 main.rs 与 runtime.rs 内嵌的#[cfg(test)]模块。深入阅读指引设计文档docs/design/2026-07-31-desktop-web-shell-release.md桌面包入口与构建脚本packages/desktop-shell/package.json、packages/desktop-shell/scripts/prepare-runtime.jsRust 主进程 / runtime / 状态main.rs、runtime.rs、desktop_state.rsTauri 配置CSP、bundle、updater 端点tauri.conf.json权限最小化bootstrap.json、web-shell-external-url.json三平台 smokesmoke-packaged.js、smoke-runtime.js相关上下游能力qwen serve的 daemon 协议可参考 docs/developers/qwen-serve-protocol.mdWeb Shell 前端位于 packages/web-shell。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表