触发:push 到 main(只认 desktop/ 与 protocol/ 的改动)、v* tag、PR、手动。 产物:Linux deb + AppImage、Windows NSIS 安装包、macOS 通用 dmg,各自传 artifact。 几个不是随手写的点: - 三个平台都显式 --target / CARGO_BUILD_TARGET。desktop/.cargo/config.toml 里钉着 aarch64-apple-darwin,不覆盖的话 Linux/Windows 的 runner 会去编 macOS 的目标, 然后在依赖深处以 libc 找不到 MAP_FAILED 这类形式失败。 - protocol 的测试写 cargo +stable:protocol/ 没有自己的 rust-toolchain.toml,会被 根目录那个 `esp` 接住,而 CI 上没有那个工具链(espup 要下几百 MB)。 - Windows 与 macOS 两个 job 默认不跑(本仓库目前只有 Linux runner),要用仓库变量 ENABLE_WINDOWS / ENABLE_MACOS 打开;没有 runner 时它们只会一直排队。 - cargo 只缓存 registry、不缓存 target/:容器化的 runner 每次都是干净的,拉几 GB 的 target 缓存常常比重新编译还慢。 - 守门 job 先跑 tsc + vite build + protocol/core 的单元测试,三个构建都 needs 它。 本地(Windows)实测:同一条 pnpm tauri build --target x86_64-pc-windows-msvc --bundles nsis 真的编出了 src-tauri/target/x86_64-pc-windows-msvc/release/bundle/ nsis/cam-desktop_0.1.0_x64-setup.exe(2.97 MiB),也验证了 --target 确实盖住了 .cargo/config.toml;protocol 15 个测试、cam-core 80 个测试、tsc、vite build 都过; 三个 Cargo.lock 与 --locked 一致;workflow 本身过 actionlint(带 shellcheck)。 Linux 与 macOS 的打包只能在你们的 runner 上验,第一次跑完把日志贴回来。