ai-board-build

star 0

AI Vibe Board 项目构建与编译技能。当用户需要构建、编译、打包项目时使用,包括开发构建、正式发布构建、Tauri 桌面应用构建、前端构建。触发关键词:编译、构建、build、打包、release、debug、tauri build、sidecar、发布。即使用户只说"编译一下"或"打包",也应该使用此技能。

ReAI-com By ReAI-com schedule Updated 6/11/2026

name: ai-board-build description: AI Vibe Board 项目构建与编译技能。当用户需要构建、编译、打包项目时使用,包括开发构建、正式发布构建、Tauri 桌面应用构建、前端构建。触发关键词:编译、构建、build、打包、release、debug、tauri build、sidecar、发布。即使用户只说"编译一下"或"打包",也应该使用此技能。

AI Vibe Board 构建技能

本项目是 Rust 后端 + Vue 3 前端 + Tauri 桌面应用的全栈项目。

权限配置(首次使用必须完成)

所有构建和开发命令都不需要 sudo。但 macOS 访问 HID 设备需要系统权限。

配置步骤

  1. 打开 系统设置 → 隐私与安全性 → 输入监控
  2. 点击左下角 🔒 解锁
  3. 添加你的终端应用:
    • Terminal.app → /System/Applications/Utilities/
    • iTerm → /Applications/
    • VS Code(如果在内建终端运行)
  4. 重启终端应用(完全退出再打开)
  5. 运行 make check-permissions 验证

Tauri 桌面应用 需要单独授权:首次启动后,系统会弹窗要求输入监控权限,点击「允许」即可。

不需要 sudo 的前提

场景 是否需要 sudo 原因
make dev / make d Tauri app 走独立 TCC 条目
make ss / make s 终端已授权输入监控
make sm / make m 同上
所有 build-* 命令 编译不需要设备访问
make check/test/lint 纯代码检查

如果之前用过 sudo

sudo 创建的文件属于 root,会导致普通用户写入失败。执行清理:

sudo chown -R $(whoami) ~/.reai-vibe-board/
sudo chown -R $(whoami) target/    # 如果 target/ 下有 root 文件

Tauri 桌面应用权限(.app 三项授权)

Tauri 生产 .app 需要三项 macOS 权限才能完整运行。应用会在启动时自动检测并弹窗引导。

权限 作用 自动重启 Tauri 命令
辅助功能 (Accessibility) 语音转录文本自动插入输入框 ✅ 授权后自动重启 open_accessibility_settings
输入监听 (Input Monitoring) 监听键盘按键(PTT 一键录音) ✅ macOS 自动杀进程重启 open_input_monitoring_settings
麦克风 (Microphone) 录音和语音识别 ❌ 即时生效 navigator.mediaDevices.getUserMedia

权限检测 API

  • check_accessibility_grantedAXIsProcessTrusted()
  • check_input_monitoring_grantedCGPreflightListenEventAccess()
  • restart_appopen .app && app.exit(0),辅助功能授权后自动触发

文本插入机制

sidecar 无法获得独立 TCC 授权(ad-hoc signing),文本插入路由:

  1. sidecar 调用 .app/Contents/MacOS/tauri-app insert-text --stdin
  2. tauri-app 在 .app TCC 下执行 AXIsProcessTrusted() → CGEvent 注入
  3. 返回 JSON {"kind":"inserted"} 等(serde tag 必须与 sidecar InsertOutcome 一致)

构建环境净化(macOS)

强制约束:所有构建入口必须在净化后的环境里跑 cargo / cc / pkg-config,否则用户 shell 里的 MacPorts (/opt/local) / Homebrew (/opt/homebrew, /usr/local) 会把 host 绝对路径写进 Mach-O 的 LC_LOAD_DYLIB,导致 .app 在没装这些工具链的 Mac 上启动期 dyld abort(典型报错:Library not loaded: /opt/local/lib/liblzma.5.dylib)。

scripts/build-env.sh 负责净化,被所有 make target 与 scripts/tauri-release.sh 自动 source。手动跑 cargo build / cargo tauri build也必须先:

source scripts/build-env.sh

清掉的变量:

  • pkg-config:PKG_CONFIG_PATH PKG_CONFIG_LIBDIR PKG_CONFIG HOST_PKG_CONFIG TARGET_PKG_CONFIG
  • 链接器/编译器搜索:LIBRARY_PATH DYLD_LIBRARY_PATH DYLD_FALLBACK_LIBRARY_PATH DYLD_FRAMEWORK_PATH DYLD_FALLBACK_FRAMEWORK_PATH CPATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH
  • 编译/链接 flag:LDFLAGS CFLAGS CPPFLAGS CXXFLAGS BINDGEN_EXTRA_CLANG_ARGS
  • 工具链覆盖:CC CXX LD AR RANLIB 及其 HOST_* / TARGET_* 变体
  • 扫描 cc-rs / pkg-config-rs 的 target-scoped 变量(CC_aarch64_apple_darwinPKG_CONFIG_PATH_* 等):值若含 host 路径 → 脚本 fail
  • 检查 RUSTFLAGS / CARGO_ENCODED_RUSTFLAGS / CARGO_TARGET_*_LINKER / CARGO_TARGET_*_RUSTFLAGS 是否被污染(含 host 路径 → fail)

PATH 清洗:移除 /opt/local/bin /opt/local/sbin /opt/homebrew/bin /opt/homebrew/sbin /usr/local/bin /usr/local/sbin;prepend ~/.cargo/bin ~/.bun/bin ~/.local/bin(按存在性);兜底 /usr/bin:/bin:/usr/sbin:/sbin

固定 MACOSX_DEPLOYMENT_TARGET=10.15(对齐 tauri.conf.json minimumSystemVersion),SDKROOTxcrun --sdk macosx --show-sdk-path

构建后 gatescripts/verify-no-host-paths.sh "$APP" 扫描 .app 内所有 Mach-O 的 LC_LOAD_DYLIB/LC_LOAD_WEAK_DYLIB/LC_REEXPORT_DYLIB/LC_LOAD_UPWARD_DYLIB/LC_ID_DYLIB/LC_RPATH,任一指向 host 路径直接 fail。make tauri-build / make tauri-build-sherpa / make local-build / make release 末尾自动跑。

dry-run(不触发真实 Apple 公证上传,省掉等待与失败重来)

make tauri-build          # 自动 source build-env + env -u 屏蔽 APPLE_* + 末尾 verify
make verify-self-test     # 验证 verify 脚本本身的逻辑
make verify-app           # 校验当前已构建的 .app

真正发布(全托管,推荐)

./scripts/release.sh            # 默认 patch +1(= make publish)
./scripts/release.sh minor      # 或 minor / major / 显式 0.20.0
./scripts/release.sh --dry-run  # 只算版本 + 预览路径修正 + tag 碰撞检查,不构建不公证不写文件

release.sh发布编排器:版本 bump + 三处对齐(Cargo.toml / tauri.conf.json / web/package.json,取最大值为基准)→ 路径自愈(cd ../webcd web)→ tag 碰撞守卫 → 调底层引擎 → 失败回滚版本文件 → 成功后打印好 git commit + git tag v$NEW 命令,停在 commit 前等你确认(不自动 commit、不自动 push)。

底层引擎 ./scripts/tauri-release.sh(= make release)只管「构建→签名→公证→验证」、不做版本 bump;想跳过版本管理直接重建当前版本时才单独用它。引擎顺序:.env.local 加载 + APPLE_* 校验 + exportsource build-env.sh → 路径自愈预检 → cargo tauri build内部完成签名 + .app 公证 + staple)→ verify-no-host-paths(gate)→ codesign --verifystapler validate .appDMG 硬 gate(缺失即 fail)notarytool submit .dmg + staple + stapler validate .dmgspctl -a Gatekeeper 硬 gate。任一 gate 失败即非零退出——所以 exit 0 可信。

gate 边界:因 cargo tauri build 把 .app 公证封装在构建里,后续 gate 失败只能阻止 DMG 公证,已经发生的那次 .app 公证上传无法撤回(公证免费、不按次扣费,但那次上传 + Apple 排队几分钟的时间收不回来)。所以日常先用 make tauri-build / ./scripts/release.sh --dry-run 预检,再走真发布。

快速决策

根据需求选择构建路径:

场景 命令 产出
开发调试(推荐) make dev / make d Tauri 桌面窗口 + 热更新
后端 + 前端(Web 模式) make ss HTTP 服务 :8067 + STT
只编译后端 make build-sherpa target/release/ai-vibe-board
对外发布(全托管,推荐) ./scripts/release.sh / make publish 版本 bump + 签名 + 公证 + gate,停在 commit 前
重建当前版本(裸引擎,不 bump) make release 签名 + 公证当前版本,不改版本号
仅本机构建(不公证) make tauri-build dry-run:屏蔽 Apple 凭据、不 notarize
只编译前端 cd web && bun run build web/dist/

构建命令

开发模式(日常推荐)

make dev          # 或 make d(Tauri 桌面应用,自动编译后端 + 前端热更新)

完整流程:

  1. build-all-stt → 编译 Rust 后端(含全部 STT)
  2. 复制 sidecar 到 src-tauri/binaries/
  3. 启动 Tauri 开发模式(前端热更新 + 后端自动管理)

Web 模式(不用 Tauri 桌面窗口):

make ss           # 编译 + 启动 HTTP 服务(含 sherpa STT)
# 另开终端:cd web && bun run dev   # 前端热更新 :1420

正式发布

对外发布首选 ./scripts/release.sh(或 make publish——它自带版本 bump(默认 patch)+ 三处对齐,无需手动改版本号(见下方「版本管理」章节)。根据分发目标选择命令

场景 命令 说明
对外分发(全托管,推荐) ./scripts/release.sh / make publish 版本 bump+对齐 → 路径自愈 → 签名 + Notarization + Stapling + gate → 停在 commit 前
重建当前版本(裸引擎,不 bump) ./scripts/tauri-release.sh / make release 不改版本号,直接签名 + 公证 + 装订当前版本,见下方「Apple 签名与公证」章节
仅编译 .app/.dmg,不公证 make tauri-build 直接走 cargo tauri build。有 Developer ID 证书会真签名,但不做 notarization,发到别人电脑会被 Gatekeeper 拦

如果只发布后端二进制(不用 Tauri 桌面壳):

make build-all-stt    # 产出 target/release/ai-vibe-board

✅ 发布前自检(现已自动化,了解即可)

历史上这两个坑反复踩,每次白等一轮 Apple 公证(上传 + 排队几分钟,失败还得重来)。现在 release.sh 与引擎已自动处理这两条,不再需要手动 grep;保留说明便于理解:

  1. beforeBuildCommand 路径方向(已自动纠正)

    grep '"beforeBuildCommand"' src-tauri/tauri.conf.json
    

    正确:"beforeBuildCommand": "cd web && bun run build" 错误:"beforeBuildCommand": "cd ../web && bun run build"

    release.sh(版本快照前)与引擎构建前预检都会探测到 cd ../web 并就地改回 cd web,即便复发也会被自动修掉(属持久根因修复,不被失败回滚抹掉)。

    真正的机制(tauri-cli app_paths.rs,2026-06 源码确认):hook 的 CWD 是 tauri-cli 解析出的「前端目录」——若src-tauri/ 启动构建(本仓库 Makefile / release.sh / CI 均如此),其下找不到 package.json,确定性回退到 src-tauri/ 的父目录即仓库根,故 cd web 正确。若从仓库根启动,tauri-cli 会全仓库搜第一个 package.json 来猜前端目录(backup/firmware/landing 都有),命中哪个看运气——历史上 CI 从仓库根启动时碰巧猜中 landing 级目录,cd ../web 侥幸可用,于是出现「CI 要 ../web、本地要 web」的假性平台冲突,这行被来回改了 6+ 次。结论:永远从 src-tauri/ 启动构建,永远写 cd web(本地与 CI 的 tauri-cli 均锁定 2.11.1;升级 tauri-cli 时需先复核该解析机制是否变化)。详见下方「常见问题」同名条目。

  2. 退出码现已可信(旧 bug 已修)

    引擎曾有「beforeBuildCommand 失败 / DMG 缺失 / spctl 失败仍 exit 0」的假成功 bug。现已补齐硬 gate(DMG 必须存在 + stapler validate + spctl 任一失败即非零退出),exit 0 ⇒ 产物已验真,不再需要手动跑外部 gate 二次确认。release.sh 走到成功收尾即代表这些 gate 全过。

双平台发布同步(macOS + Windows)

macOS 与 Windows 安装包由不同流程发布(Mac 本地公证、Windows GitHub Actions),通过 GitHub Releases 作为唯一真相源统一版本号、把两平台产物归集到同一个 vX.Y.Z Release。

  • macOS:发布并 git push origin vX.Y.Z 后,跑 make release-upload(= scripts/upload-release.sh)把已公证的 .dmg 同步到对应 Release(幂等:没有就建、有就追加)。
  • Windows:push tag 自动触发 .github/workflows/build.yml,NSIS 安装包发到同一 Release(对已存在的 tag 可用 workflow_dispatch 补发)。
  • 谁先发布谁定版本号、建 Release,另一端复用同一 tag;release.sh 的 tag 碰撞守卫防两边撞号。

完整约定(角色分工、谁先到谁建、补发流程、典型时序)见 docs/release-coordination.md

Apple Developer ID 签名与公证

对外分发必须完整走完签名 + 公证 + 装订三步,否则 Gatekeeper 会阻止运行。

关于「公证成本」的正确认知:公证(Notarization)本身免费、不按次收费——它包含在 Apple Developer Program 年费里,没有「用完即锁」的次数额度池,也不是按 App 分配。真实开销只有两类:①每次都要把包上传给 Apple、排队等自动扫描(DMG 通常 3-5 分钟),失败得从头重来;②账号级有速率限流(社区经验值约 75 次/天/团队,非 Apple 正式承诺的硬配额),但单人手动发版基本撞不到。所以本文反复强调先 dry-run 预检——省的是时间和重试成本,不是会被扣空的配额。

凭据角色分工

凭据 存放位置 作用 每次发布需要
Developer ID Application 证书 + 私钥 macOS 钥匙串「登录」 代码签名(.app / sidecar / dylib) ✅ 但钥匙串自动提供,无需输密码
APPLE_ID + APPLE_PASSWORD (app-specific) + APPLE_TEAM_ID .env.local(gitignore) Notarization 上传凭证 ✅ 每次都要,因为要登录 Apple 服务器

首次配置(一次性)

  1. 申请 Developer ID Application 证书

    • developer.apple.com → Certificates → Developer ID Application → 上传本机钥匙串生成的 CSR → 下载 .cer → security import 或双击
    • 验证:security find-identity -v -p codesigning | grep "Developer ID Application"
  2. 生成 App-Specific Password(用于 notarytool)

    • account.apple.com → Sign-In and Security → App-Specific Passwords → Generate → 标签如 tauri-notarize
    • 密码只显示一次,立即存入密码管理器
  3. 备份私钥为 .p12(防丢)

    • 钥匙串访问 → 我的证书 → 展开箭头同时选中证书+私钥 → 右键「导出 2 项」→ .p12 + 强密码
    • 异地保存(U 盘 / 加密云盘),密码单独存密码管理器
  4. 配置 tauri.conf.json

    "macOS": {
      "signingIdentity": "Developer ID Application: YOUR NAME (TEAMID)",
      "providerShortName": "TEAMID"
    }
    
  5. 配置 Entitlements.plist Hardened Runtime 必需键

    <key>com.apple.security.cs.disable-library-validation</key><true/>
    <key>com.apple.security.cs.allow-jit</key><true/>
    <key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
    

    (whisper-rs/sherpa-onnx 等未签名 dylib 必需,否则运行时 dyld 拒绝)

  6. 创建 .env.local(已在 .gitignore)

    export APPLE_SIGNING_IDENTITY="Developer ID Application: YOUR NAME (TEAMID)"
    export APPLE_ID="your-apple-id@example.com"
    export APPLE_PASSWORD="xxxx-xxxx-xxxx-xxxx"
    export APPLE_TEAM_ID="TEAMID"
    
    chmod 600 .env.local
    

日常发布(配置完成后)

./scripts/release.sh          # 全托管:版本 bump + 引擎 + gate(推荐)
./scripts/tauri-release.sh    # 仅底层引擎:不 bump,重建当前版本

底层引擎 tauri-release.sh 自动完成:

  1. 加载 .env.local + 校验环境变量
  2. 确保 PATH 含 ~/.cargo/bin(避免旧 Rust 读不懂 Cargo.lock v4)
  3. cargo tauri build → 编译 + 签名 .app / sidecar / dylib → tauri-cli 自带:提交 .app 公证 + staple
  4. 轻量校验 .app 已被 stapled(信任 tauri-cli 的产物,不重复提交)
  5. 单独提交 .dmg 公证 + staple(Tauri v2 默认不做 DMG 公证,脚本补上)
  6. spctl -a 最终 Gatekeeper 验证

关键事实:当 tauri.conf.jsonmacOS.signingIdentity 已配置、且环境里有 APPLE_ID + APPLE_PASSWORD + APPLE_TEAM_ID 时,Tauri v2 的 cargo tauri build 会自动完成 .app 公证 + staple(log 里会看到 Notarizing ... Accepted + Stapling app...);本仓库的 tauri-release.sh 在 build 前会校验这三个变量,所以这条路径成立。脚本若再用 notarytool submit "$APP_PATH" 提交一次 .app,会被拒绝(notarytool 只收 zip/pkg/dmg,不收裸 .app),所以脚本职责只剩"补 DMG 公证"。

反过来,如果只配 signingIdentity 但没配 Apple 凭据(比如直接跑 make tauri-build),tauri-cli 会打印 skipping app notarization 后继续构建,产出的 .app 只签名不公证——发到别人电脑会被 Gatekeeper 拦。需要对外分发就用 ./scripts/release.sh(全托管,推荐)或 ./scripts/tauri-release.sh(裸引擎,不 bump)。

产物:src-tauri/target/release/bundle/dmg/ReAI Vibe Board_X.Y.Z_aarch64.dmg

公证验证命令

# 检查产物是否含 host 路径(MacPorts / Homebrew / 开发机用户目录)
scripts/verify-no-host-paths.sh "path/to/AI Vibe Board.app"

# 检查签名
codesign --verify --deep --strict --verbose=2 "path/to/AI Vibe Board.app"

# 检查公证票据是否装订
xcrun stapler validate "path/to/AI Vibe Board.app"
xcrun stapler validate "path/to/*.dmg"

# Gatekeeper 最终放行检查(应显示 Notarized Developer ID / accepted)
spctl -a -vvv -t install "path/to/*.dmg"

版本管理(由 release.sh 自动处理)

./scripts/release.sh / make publish 自动完成版本 bump + 三处对齐,无需手动改版本号

升级规则

类型 命令 示例
patch(默认) ./scripts/release.shrelease.sh patch 0.9.0 → 0.9.1
minor ./scripts/release.sh minor 0.9.1 → 0.10.0
major ./scripts/release.sh major 0.10.0 → 1.0.0
显式 ./scripts/release.sh 0.20.0 → 0.20.0(必须 > 当前基准)

release.sh 自动维护的版本文件(三处对齐)

文件 格式
src-tauri/Cargo.toml version = "X.Y.Z"
src-tauri/tauri.conf.json "version": "X.Y.Z"
web/package.json "version": "X.Y.Z"

三处事先不一致时(本仓库出现过 web/package.json 落后),release.sh 自动取最大值为基准再递增并打印告警。Cargo.lockcargo tauri build 自动刷新本 crate 版本。

全托管发布流程(release.sh 内部,了解即可)

  1. 解析 bump 档(默认 patch);多个版本参数会报错(防歧义)。
  2. 读三处版本、校验 X.Y.Z 格式、用自写 semver 比较取最大值为基准;按档算新版本。
  3. tag 碰撞守卫:本地 + 远端(尽力,网络不可达只告警)v$NEW 已存在则报错退出。
  4. --dry-run 在此之后、任何写动作之前分支退出(只预览版本/路径/碰撞)。
  5. 前置脏检查 4 个版本文件(Cargo.toml / tauri.conf.json / web/package.json / Cargo.lock)无未提交改动,否则报错退出(避免回滚误伤)。
  6. 规范化 beforeBuildCommand 路径(持久根因修复,在版本快照前做,不被回滚)。
  7. 备份 4 文件 → 写入新版本到三处 → 写后校验确实写成 $NEW
  8. 调引擎 scripts/tauri-release.sh(构建+签名+公证+硬 gate)。引擎失败 → 自动从备份回滚 4 文件。
  9. 成功 → 打印 git add … && git commit && git tag v$NEW 命令,停在 commit 前等用户确认(不自动 commit、不自动 push)。

退出码可信:引擎硬 gate 保证 exit 0 ⇒ 产物已验真。commit + tag 需用户确认后手动执行;push 始终手动。dry-run 预检:./scripts/release.sh --dry-run

快速验证(不生成二进制)

make check    # cargo check --all-targets
make clippy   # 静态分析
make lint     # fmt-check + clippy
make test     # 运行测试

Cargo Features(STT 后端)

Feature 引擎 编译时间 适用场景
(default) ~2min 基础版
sherpa Sherpa-ONNX ~5min 日常开发推荐
whisper whisper-rs ~5min macOS Metal GPU
sherpa,whisper 全部 ~8min 正式发布

快捷命令速查

快捷命令 等同于 说明
make d make dev Tauri 开发模式
make ss make serve 启动 HTTP 服务(sherpa STT)
make sm make monitor 启动 HID 监控
make b make build 构建后端
make s make serve 同 ss
make m make monitor 同 sm
make sss make sudo-serve 强制 sudo(一般不需要)
make ssm make sudo-monitor 强制 sudo(一般不需要)
make publish ./scripts/release.sh 全托管发布:版本 bump + 签名 + 公证 + gate(推荐)
make release ./scripts/tauri-release.sh 裸引擎发布:不 bump,签名 + 公证当前版本

常见问题

端口 8067 被占用

lsof -nP -iTCP:8067 -sTCP:LISTEN  # 找到占用进程
kill -9 <PID>

编译太慢

  • 开发时用 make build-sherpa 而非 build-all-stt
  • make check 只做类型检查

Sidecar 未更新

后端代码修改后需要重新构建 sidecar:

make b && make sidecar   # 或直接 make dev(会自动重建)

~/.reai-vibe-board/ 下文件权限错误

如果之前用过 sudo 启动,文件会属于 root:

sudo chown -R $(whoami) ~/.reai-vibe-board/

Cargo.lock version 4 无法读取

本机 Rust 太旧(如 MacPorts 的 1.71),而 lock 文件由新 Rust 生成。修复:

# 确认已装 rustup + stable
rustup show

# 把 ~/.cargo/bin 放到 PATH 最前(~/.zshrc)
export PATH="$HOME/.cargo/bin:$PATH"

scripts/tauri-release.sh 已自动处理,但 make 直跑不会。

cargo tauri 找不到(no such command: tauri

发布脚本需要 cargo-tauri binary。装:

# 必须用 rustup 的 cargo,不能用 MacPorts 的旧 cargo
PATH="$HOME/.cargo/bin:$PATH" cargo install tauri-cli --version "^2.0" --locked

装好后会生成 ~/.cargo/bin/cargo-tauri(约 30 MB)。一次性安装,后续不用重装。

如果直接 cargo install tauri-cli 失败、报 serde_spanned ... requires rustc 1.76+,说明 PATH 里 MacPorts cargo 在前。两个修法选一:临时 PATH="$HOME/.cargo/bin:$PATH" cargo install ...,或在 ~/.zshrc~/.cargo/bin 永久放到 PATH 最前。

beforeBuildCommand 失败:cd: ../web: No such file or directory(反复踩坑)

这个坑本仓库踩过至少两次(commit c89a92a 改对过一次,ee8359f 又改反了一次)。历史问题说明——release.sh 与引擎现已在构建前自动纠正这个路径(见上方「正式发布 → 发布前自检」第 1 条);若需手动排查可参考该节。

V2 重构后 src-tauri/tauri.conf.json 里如果写成 "beforeBuildCommand": "cd ../web && bun run build",发布构建一开局就会失败。

机制:Tauri v2 执行 beforeBuildCommand / beforeDevCommand hook 时把 CWD 设为 dirs.frontend。本仓库没有显式配 TAURI_FRONTEND_PATH,所以 dirs.frontend fallback 到仓库根src-tauri/ 的父目录),而不是 src-tauri/ 本身。从仓库根看 ../web 指向仓库外,不存在。

正确写法

"beforeDevCommand": "cd web && bun run dev",
"beforeBuildCommand": "cd web && bun run build",

判断方向的方法(不要凭直觉,凭事实):

  1. 出现 sh: line 0: cd: ../web: No such file or directory → hook CWD 不是 src-tauri/,是项目根 → 用 cd web
  2. 出现 sh: line 0: cd: web: No such file or directory → hook CWD 是 src-tauri/(罕见,需配了 frontendDir)→ 用 cd ../web
  3. 见到 commit message 写"路径修复"不要假定方向正确,本仓库历史上两个方向都"修复"过,以本机 grep 当前值 + 实际报错为准

将来如果给 Tauri 显式配了 frontendDirTAURI_FRONTEND_PATH,hook CWD 会变成那个目录,路径写法需要再调整——届时同样按"出错信息 + 实测"判定,不靠记忆。

脚本第三次重跑卡在 .app 公证那步

症状:log 里能看到 tauri-cli 自己已经 Notarizing ... Accepted + Stapling app...,但脚本后续又调用 xcrun notarytool submit "$APP_PATH" 时报:

Error: ReAI Vibe Board.app must be a zip archive (.zip), flat installer package (.pkg), or UDIF disk image (.dmg)

原因:Tauri v2 的 cargo tauri build 已经在内部完成了 .app 公证 + staple(zip 打包 → notarytool → staple 一条龙),所以脚本不能再次 notarytool submit 裸 .app。现在的 scripts/tauri-release.sh 已经改成只验证 xcrun stapler validate "$APP_PATH",不重复提交;如果在更早的脚本版本上跑遇到,直接更新脚本即可。

切分支后前端 TypeScript 找不到模块

Cannot find module '@tauri-apps/plugin-dialog'。说明 web/node_modules 和当前分支 web/bun.lock 不同步:

cd web && bun install

.app 在别人电脑启动崩溃,提示 liblzma.5.dylib not found(或类似 /opt/local/lib/...

症状:开发机能跑,分发到没装 MacPorts/Homebrew 的 Mac 上启动期直接 abort,Crash Report 里:

Library not loaded: /opt/local/lib/liblzma.5.dylib
Reason: tried: '/opt/local/lib/liblzma.5.dylib' (no such file), ...

原因:构建时链接器命中开发机的 MacPorts / Homebrew 路径,把 host 绝对路径写进了 Mach-O 的 LC_LOAD_DYLIB

修复:

  1. 用本仓库的 scripts/build-env.sh 净化环境再构建(make / tauri-release.sh 已自动 source)
  2. 构建后跑 scripts/verify-no-host-paths.sh "$APP" 确认无污染
  3. 任一 gate fail 时检查 shell 配置(~/.zshrc / direnv / launchd plist),把所有 /opt/local/opt/homebrew/usr/local 相关的 PKG_CONFIG_PATH LIBRARY_PATH LDFLAGS CFLAGS CC CXX 等清掉

历史脏包:/Applications/ReAI Vibe Board.appscripts/verify-no-host-paths.sh 跑一遍,如果输出违规列表,就是这个问题;删掉重装新版本。

Notarization 卡住几分钟

正常现象。xcrun notarytool ... --wait 会轮询 Apple 服务器,DMG 通常 3-5 分钟,.app 更快。看到 status: Accepted 就成功。切勿 Ctrl+C,否则要重新提交。

失败(status: Invalid)时看日志:

xcrun notarytool log <submission-id> \
  --apple-id "$APPLE_ID" --password "$APPLE_PASSWORD" --team-id "$APPLE_TEAM_ID"

常见原因:Entitlements 缺 Hardened Runtime 键、dylib 未签名、包含未 staple 的旧产物。

权限弹窗不显示

macOS 的辅助功能和输入监听授权弹窗在 Tauri 中可能不显示。应用已内置:

  • 启动时自动检测权限状态,未授权则弹出引导弹窗
  • 点击「去授权」打开系统设置并显示分步操作指引
  • 辅助功能授权后 2 秒轮询检测,通过后自动重启

构建前检查清单

正式发布前运行:

make lint     # 格式 + Clippy
make test     # 测试

Release Profile

[profile.release]
opt-level = 3    # 最大优化
lto = true       # 链接时优化
strip = true     # 去除调试符号
Install via CLI
npx skills add https://github.com/ReAI-com/ai-vibe-board --skill ai-board-build
Repository Details
star Stars 0
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator