跳转至

macOS 开发者设置

从源代码构建并运行 OpenClaw macOS 应用。

打包后的应用需要 macOS 15.0 或更高版本。构建主机还必须满足以下 Xcode 要求。

先决条件

  • Xcode 26.4+(Swift 6.3 工具链),使用软件更新中可用的最新 macOS。
  • Node.js 24.16+ 或 26.1+ 以及 pnpm,用于 gateway、CLI 和打包脚本。

macOS shell 工具使用系统 /bin/bash(3.2);不需要 Homebrew Bash。 直接运行脚本或使用 /bin/bash 运行。Bash 5.3+ 可能在 heredoc 的读取器 启动之前停滞,导致在管道缓冲区压力下打包或签名日志为空。可移植脚本 入口点在 macOS 上切换到 /bin/bash,流式安装程序(curl ... | bash) 也会通过在执行前将其余输入捕获到私有临时文件中来实现相同行为,因此 文档中的安装命令无需更改。

1. 安装依赖

pnpm install

2. 构建并打包应用

./scripts/package-mac-app.sh

输出 dist/OpenClaw.app。打包默认需要真实的签名身份,如果没有可用身份 则失败。临时签名是显式选择加入;它不会保留 TCC 权限。请参阅 macOS 签名。

打包会构建 JavaScript 运行时和 Control UI,然后为每个请求的 BUILD_ARCHS 架构从规范包工件配置私有 Node 工作进程。根工作进程 tarball 使用仓库固定的 pnpm 打包器;支持仅 Corepack 环境。打包会在 签名前后的临时状态中验证原生能力和工作进程就绪状态,然后替换之前的 应用。scripts/restart-mac.sh 使用相同路径;SKIP_TSC=1 不会绕过 运行时构建。现有的内容检查构建缓存仍会避免不必要的声明处理。

工作进程裁剪会传递性地遵循模块导入、运行时启动描述符和命名工作进程 入口点。由另一个保留的工作进程启动的辅助进程会连同其导入和运行时依赖 一起保留在包中。

私有工作进程会保留应用已保存的桌面共享偏好和配置文件选择。打包会在 签名前后检查共享启用、禁用和未指定时的启动,包括命名配置文件启动。

打包时设置 OPENCLAW_NODE_VERSION=<version>,以选择每个私有工作进程 支持的 Node 版本。如果未设置或为空,则应用 CLI 安装程序的默认值。 打包会使用该运行时安装并验证完整工作进程。

每个工作进程保留支持其架构的原生二进制文件,并省略不兼容的 macOS、 Linux 和 Windows 预构建文件。这可防止未使用的仅 Intel 依赖项在 Apple silicon 构建中触发 macOS 兼容性警告。兼容的通用二进制文件、 JavaScript、WASM 和其他资源保持完整。

通用构建要求 arm64 和 x86_64 两种运行时在验证期间均可执行。在 Apple Silicon 上构建 x86_64 需要 Rosetta;缺少架构或不可移植的原生 依赖项会导致打包失败。Node 下载和包安装需要网络访问。较大的应用包含 其完整的私有运行时;它不会更新独立管理的 Gateway。

打包使用 Swift Build(--build-system swiftbuild)构建 MLX 语音辅助 程序,并将其 SwiftPM 资源包复制到 Contents/Resources。原生 SwiftPM 后端不会编译 MLX 的 Metal 着色器。如果辅助程序的 mlx-swift_Cmlx.bundle/Contents/Resources/default.metallib 缺失, 打包会失败,而不是发布一个在首次语音请求时失败的辅助程序。

私有工作进程使用只读核心配置引导,而不是 Gateway 范围的 Doctor 预检。 Node 插件验证、MCP 生命周期以及由 node 拥有的身份和执行审批启动迁移 保持启用。有关边界,请参阅 Gateway 所有权。

设置 OPENCLAW_SKIP_MLX_TTS=1 以打包不包含本地 MLX 语音辅助程序的 dev/proof 构建。这会跳过 openclaw-mlx-tts 二进制文件及其大型 mlx-swift Metal 着色器栈,某些 beta Xcode 工具链无法编译它。生成的 应用没有设备端 MLX 语音;它会被 release 构建拒绝,release 构建 必须包含该辅助程序。

有关 dev 运行模式、签名标志和 Team ID 故障排除,请参阅 apps/macos/README.md。 从仓库根目录进行快速开发循环:scripts/restart-mac.sh(添加 --no-sign 以进行临时签名;使用 --no-sign 时 TCC 权限不会保留)。

Note

临时签名的应用可能会触发安全提示。如果应用立即崩溃并显示 "Abort trap 6",请参阅 故障排除。

3. 安装 CLI 和 Gateway

打包的应用嵌入了规范的 scripts/install-cli.sh 安装程序。在新配置文件 中,引导期间选择 此 Mac;应用会在启动 Gateway 向导之前安装匹配的 用户空间 CLI 和运行时。

对于手动开发恢复,请自行安装匹配的 CLI。从应用中读取版本:在菜单栏中 选择 关于 OpenClaw,或运行 openclaw-mac status --json,它会报告 应用版本和构建。

下面的 npm 命令适用于 npm 12 或 npm 11.16+。在 npm 11.15 及更早版本 中,省略 --allow-scripts=openclaw。

npm install -g openclaw@<version> --allow-scripts=openclaw

pnpm add -g --allow-build=openclaw openclaw@<version> 和 bun add -g --trust openclaw@<version> 也可用。Bun 的 --trust 允许 该安装使用 OpenClaw 生命周期脚本。Node 仍然是 Gateway 本身推荐的运行时。

安全运行原生测试

在一次性 macOS VM 或 CI 工作进程中运行完整的 macOS 应用测试套件,其中 没有操作员凭据、配置或正在运行的 Gateway。AppKit 测试可能会显示窗口, WebKit 会启动辅助进程。仅使用临时 HOME、TMPDIR 或命名应用配置文件 并不构成沙箱:固定的偏好设置域和 Keychain 访问仍可能访问这些目录之外 的 macOS 服务。

The native test bundle links OpenClawWebKitTestSupport, which suppresses WebKit Screen Time observation for every WKWebView in the test process. WebKit removes its KVO observer on the main thread during deallocation while ScreenTime delivers configuration on a private queue. Tearing down a windowed HTTP(S) web view right after its first commit can hit this race and abort the process with NSInternalInconsistencyException. Product builds keep Screen Time.

The macos-swift GitHub CI job builds the tests with the runner's normal SwiftPM caches, then runs the built suite through scripts/test-macos-native.mts. Each invocation selects private HOME and CFFIXED_USER_HOME, OPENCLAW_CONFIG_PATH, OPENCLAW_STATE_DIR, and short TMPDIR before any test bundle loads. Tools honoring TMPDIR use that launcher-owned directory; Foundation uses Darwin's per-user temp directory, owned and discarded by the disposable OS worker. The full suite explicitly selects the default profile, preserving its local Gateway lifecycle contracts. AppState lifecycle tests and the interactive chat fixture run separately with a unique named profile; no test is run twice. The child environment excludes inherited app settings and credentials while retaining toolchain and runtime loader paths. Before Swift starts, the launcher creates an empty-password test Keychain under its private HOME/Library/Keychains, unlocks it, disables automatic locking for that resource, and sets the user-domain default and search list to that file. This lets real catalog migration save without an interactive login-Keychain creation prompt. Its Security preferences live in the private HOME/Library/Preferences; common and dynamic Keychain domains remain unchanged. Resources remain available for process-lifetime singletons and retained windows; the launcher deletes its Keychain and files after the managed process group and output pipes close. The disposable runner owns default preferences and system-service state; named-profile preferences use a fresh domain and are also discarded with the runner. If process cleanup cannot be verified or Keychain deletion fails, the launcher fails and retains its files for inspection. CI environment markers only catch accidental invocation; they do not enforce isolation or make an operator desktop safe.

For a focused rerun inside that disposable macOS CI runner, after the normal test build:

node scripts/test-macos-native.mts named \
  --package-path apps/macos --build-system native --enable-code-coverage \
  --skip-build --filter "AppStateIsolationTests|ProfileChatPreferencesTests"

The ordinary CI invocation bounds Swift Testing parallelism to the runner's logical CPU count, capped at 12. It runs three disjoint partitions sequentially with coverage instrumentation: the default-profile suite, rendered Quick Chat in a fresh default-profile process, and named-profile fixtures. The rendered partition preserves catalog, disclosure, and shortcut order without sharing process-wide executor changes from other tests. Both interactive fixtures use Swift Testing and start an AppKit-owned run loop before exercising native menus, so XCTest does not have to regain its outer wait loop afterward. Historical targets with the launcher keep their original default- and named-profile partitions. Local scripts/prepush-ci.sh runs Swift lint/format checks and a release build, but does not run native tests. For native changes it exits nonzero with a requirement to obtain the exact commit's macos-swift CI result; local build success is not native test success.

On an operator desktop, run only an audited subset inside an OS sandbox that blocks operator files, preferences and Keychain services, unwanted network access, and desktop/helper processes. A Swift test filter is not itself an isolation boundary. If that boundary cannot be established, use the disposable macOS environment instead.

Tests should own their resources: unique defaults suites with cleanup, nonpersistent WebKit data stores, ephemeral loopback fixture endpoints, and temporary files rooted in FileManager.temporaryDirectory. Unix-domain socket fixtures require a short test-owned path there; an overlong path fails rather than silently writing outside that directory. The cooperative TestIsolation helper serializes and restores participating tests' environment and selected defaults mutations. Config-only scopes also own a temporary state directory for config health/audit writes and remove it when the async body finishes, including errors. Callers still own their config fixture files and must join any async work before leaving the scope. These unique fixture directories are cleaned by their owners; remaining Foundation temporary files are discarded with the worker, not the launcher's root. Never change OPENCLAW_PROFILE inside a test: AppProfile and AppDefaults freeze their identity for the process. Tests needing another singleton identity require a fresh process. The cooperative helper does not isolate unrelated tests or the process from the host.

故障排除

冻结 Peekaboo 源代码时构建失败

If packaging stops at Freezing authenticated Peekaboo sources in a read-only snapshot, check the hdiutil error on stderr. Routine image creation and attachment output stays quiet, but failures such as hdiutil: attach failed - Permission denied are preserved. Snapshot images and build outputs stay in the checkout. Their read-only mount directories use macOS's per-user temporary location (getconf DARWIN_USER_TEMP_DIR), independently of TMPDIR, so an external checkout does not need to support nested mounts. If attachment still fails, check that location's mount permissions. Unverified cleanup retains the mount directories and build locks at the paths printed in the error. This step runs before signing; source verification and the read-only snapshot remain required.

构建失败:工具链或 SDK 不匹配

The macOS app build expects the latest macOS SDK and the Swift 6.3 toolchain (Xcode 26.4+).

xcodebuild -version
xcrun swift --version

如果版本不匹配,请更新 macOS/Xcode 并重新运行构建。

构建失败:MLX 语音辅助工具 Metal 着色器

在仅 beta 的 Xcode 工具链上(例如使用 macOS 27 SDK 的 Xcode 27), 可能只有 openclaw-mlx-tts 辅助工具会失败,而主应用构建正常。 mlx-swift 的 Metal 编译会非确定性地报错(每次运行都是不同的 .metal 文件,先出现 Could not read serialized diagnostics file,随后 metal 以非零状态退出),因为 beta 版 metal 编译器及其单独下载的 Metal Toolchain 仍不稳定。这是上游工具链问题,不是 OpenClaw 的问题。

如果不需要设备端 MLX 语音,请跳过该辅助工具:

OPENCLAW_SKIP_MLX_TTS=1 ./scripts/package-mac-app.sh

否则,请安装 Metal Toolchain (xcodebuild -downloadComponent MetalToolchain),并使用稳定的 Xcode 版本构建。

应用授予权限时崩溃

如果尝试允许 语音识别 或 麦克风 访问时应用崩溃,可能是 TCC 缓存损坏或签名不匹配。

  1. 重置调试 bundle id 的 TCC 权限:
tccutil reset All ai.openclaw.mac.debug
  1. 如果失败,请临时修改 scripts/package-mac-app.sh 中的 BUNDLE_ID,以强制 macOS 从干净状态开始。

网关一直显示“Starting...”

检查是否有僵尸进程占用端口:

openclaw gateway status
openclaw gateway stop

# If you're not using a LaunchAgent (dev mode / manual runs), find the listener:
lsof -nP -iTCP:18789 -sTCP:LISTEN

如果手动运行的进程占用端口,请停止它(Ctrl+C),或作为最后手段终止上面找到的 PID。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/openclaw