Skip to content

Commit 44667f8

Browse files
authored
build(macos): add Intel x64 packaging support
Add macOS Intel x64 packaging, artifact verification, and README updates while keeping OpenClaw on the local runtime path.
1 parent 4e00da0 commit 44667f8

7 files changed

Lines changed: 208 additions & 21 deletions

File tree

.github/workflows/build-platforms.yml

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ name: Build Platforms
22

33
on:
44
workflow_dispatch:
5+
push:
6+
tags:
7+
- 'v*'
58

69
env:
710
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
@@ -31,29 +34,58 @@ jobs:
3134
test "$(uname -m)" = "arm64"
3235
node -e "if (process.arch !== 'arm64') process.exit(1)"
3336
34-
# 设置 OpenClaw runtime (如果需要)
35-
- name: Setup OpenClaw Runtime
36-
run: |
37-
if [ -d "vendor/openclaw-runtime/current" ]; then
38-
echo "✓ OpenClaw runtime found"
39-
else
40-
echo "⚠ OpenClaw runtime not found, build may fail"
41-
fi
42-
4337
- name: Build macOS arm64
4438
run: npm run dist:mac:arm64 -- --publish never
4539
env:
4640
CSC_IDENTITY_AUTO_DISCOVERY: false
4741

42+
- name: Verify macOS arm64 artifact
43+
run: npm run verify:mac:arm64-artifact
44+
4845
- uses: actions/upload-artifact@v4
4946
with:
5047
name: macos-arm64-build
5148
path: release/*.dmg
5249
retention-days: 7
5350

51+
# ========== macOS Intel 构建 ==========
52+
build-macos-x64:
53+
runs-on: macos-15-intel
54+
steps:
55+
- uses: actions/checkout@v4
56+
- uses: actions/setup-node@v4
57+
with:
58+
node-version: '24.x'
59+
- uses: actions/cache@v4
60+
with:
61+
path: ~/.npm
62+
key: npm-${{ runner.os }}-x64-${{ hashFiles('package.json') }}
63+
restore-keys: npm-${{ runner.os }}-x64-
64+
65+
- run: npm install
66+
67+
- name: Verify Intel runner
68+
run: |
69+
test "$(uname -m)" = "x86_64"
70+
node -e "if (process.arch !== 'x64') process.exit(1)"
71+
72+
- name: Build macOS x64
73+
run: npm run dist:mac:x64 -- --publish never
74+
env:
75+
CSC_IDENTITY_AUTO_DISCOVERY: false
76+
77+
- name: Verify macOS x64 artifact
78+
run: npm run verify:mac:x64-artifact
79+
80+
- uses: actions/upload-artifact@v4
81+
with:
82+
name: macos-x64-build
83+
path: release/*.dmg
84+
retention-days: 7
85+
5486
# ========== 创建 Release ==========
5587
create-release:
56-
needs: [build-macos-arm64]
88+
needs: [build-macos-arm64, build-macos-x64]
5789
runs-on: ubuntu-latest
5890
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
5991
steps:
@@ -74,6 +106,7 @@ jobs:
74106
args=(
75107
"$TAG_NAME"
76108
artifacts/macos-arm64-build/*.dmg
109+
artifacts/macos-x64-build/*.dmg
77110
--draft
78111
--generate-notes
79112
--title "$TAG_NAME"

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<a href="https://github.com/freestylefly/wesight/network/members"><img src="https://img.shields.io/github/forks/freestylefly/wesight?style=flat-square&color=14b8a6" alt="GitHub forks"></a>
1414
<a href="https://github.com/freestylefly/wesight/releases/latest"><img src="https://img.shields.io/github/v/release/freestylefly/wesight?style=flat-square&color=f59e0b" alt="Latest release"></a>
1515
<a href="LICENSE"><img src="https://img.shields.io/github/license/freestylefly/wesight?style=flat-square&color=64748b" alt="MIT License"></a>
16-
<img src="https://img.shields.io/badge/platform-macOS%20Apple%20Silicon-111827?style=flat-square&logo=apple&logoColor=white" alt="macOS Apple Silicon">
16+
<img src="https://img.shields.io/badge/platform-macOS%20Apple%20Silicon%20%2B%20Intel-111827?style=flat-square&logo=apple&logoColor=white" alt="macOS Apple Silicon and Intel">
1717
</p>
1818

1919
<p align="center">
@@ -22,7 +22,7 @@
2222

2323
WeSight is an open-source desktop control console for local AI agents. It helps you install or reuse Claude Code, Codex, OpenClaw, Hermes Agent, OpenCode, Qwen Code, DeepSeek-TUI, and the built-in agent runtime, then gives them a visual workspace for chat, tools, files, IM channels, skills, model providers, runtime metrics, and desktop companion workflows.
2424

25-
> Early public releases ship macOS Apple Silicon first. If WeSight helps your agent workflow, a Star makes the project easier for more builders to discover.
25+
> Early public releases ship macOS Apple Silicon and Intel builds. If WeSight helps your agent workflow, a Star makes the project easier for more builders to discover.
2626
2727
## Quick Links
2828

@@ -138,13 +138,13 @@ Public desktop builds are published through GitHub Releases:
138138
- Website: [wesight.ai](https://wesight.ai/)
139139
- Latest release: [github.com/freestylefly/wesight/releases/latest](https://github.com/freestylefly/wesight/releases/latest)
140140

141-
Early public releases currently ship macOS Apple Silicon builds first. Release assets are intended for end users. CI artifacts are short-lived build outputs for maintainers to test before a release is published.
141+
Early public releases currently ship macOS Apple Silicon and Intel builds. Release assets are intended for end users. CI artifacts are short-lived build outputs for maintainers to test before a release is published.
142142

143143
## Download And Install
144144

145145
### 1. Download the DMG
146146

147-
Download `WeSight-*-arm64.dmg` from the [latest release](https://github.com/freestylefly/wesight/releases/latest), open it, and drag `WeSight.app` into the `Applications` folder.
147+
Download the matching macOS DMG from the [latest release](https://github.com/freestylefly/wesight/releases/latest): `WeSight-*-mac-arm64.dmg` for Apple Silicon or `WeSight-*-mac-x64.dmg` for Intel. Open it and drag `WeSight.app` into the `Applications` folder.
148148

149149
<p align="center">
150150
<img src="public/readme/tutorial/install-dmg.svg" alt="WeSight DMG install guide" width="760">
@@ -236,9 +236,13 @@ npm run lint
236236
```bash
237237
# macOS
238238
npm run dist:mac
239+
240+
# macOS single-architecture packages
239241
npm run dist:mac:x64
240242
npm run dist:mac:arm64
241-
npm run dist:mac:universal
243+
244+
# Do not use npm run dist:mac:universal until native modules have an
245+
# explicit merge strategy for both macOS architectures.
242246

243247
# Windows
244248
npm run dist:win

README_zh.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<a href="https://github.com/freestylefly/wesight/network/members"><img src="https://img.shields.io/github/forks/freestylefly/wesight?style=flat-square&color=14b8a6" alt="GitHub forks"></a>
1414
<a href="https://github.com/freestylefly/wesight/releases/latest"><img src="https://img.shields.io/github/v/release/freestylefly/wesight?style=flat-square&color=f59e0b" alt="Latest release"></a>
1515
<a href="LICENSE"><img src="https://img.shields.io/github/license/freestylefly/wesight?style=flat-square&color=64748b" alt="MIT License"></a>
16-
<img src="https://img.shields.io/badge/platform-macOS%20Apple%20Silicon-111827?style=flat-square&logo=apple&logoColor=white" alt="macOS Apple Silicon">
16+
<img src="https://img.shields.io/badge/platform-macOS%20Apple%20Silicon%20%2B%20Intel-111827?style=flat-square&logo=apple&logoColor=white" alt="macOS Apple Silicon 和 Intel">
1717
</p>
1818

1919
<p align="center">
@@ -22,7 +22,7 @@
2222

2323
WeSight 是一个开源桌面 AI Agent 控制台。它可以安装或复用 Claude Code、Codex、OpenClaw、Hermes Agent、OpenCode、Qwen Code、DeepSeek-TUI 和内置 Agent runtime,把它们统一到一个可视化工作台里,覆盖对话、工具、文件、IM 通道、技能、模型供应商、运行监控和桌面宠物工作流。
2424

25-
> 早期公开版本优先提供 macOS Apple Silicon 安装包。如果 WeSight 对你的 Agent 工作流有帮助,欢迎点亮 Star,让更多开发者看到这个项目。
25+
> 早期公开版本提供 macOS Apple Silicon 和 Intel 安装包。如果 WeSight 对你的 Agent 工作流有帮助,欢迎点亮 Star,让更多开发者看到这个项目。
2626
2727
## 快速入口
2828

@@ -138,13 +138,13 @@ WeSight 把模型配置集中在一个设置页。某个引擎选择“跟随 We
138138
- 官网:[wesight.ai](https://wesight.ai/)
139139
- 最新版本:[github.com/freestylefly/wesight/releases/latest](https://github.com/freestylefly/wesight/releases/latest)
140140

141-
早期公开版本优先提供 macOS Apple Silicon 安装包。Release assets 面向最终用户下载。CI artifacts 作为维护者测试构建产物的临时入口。
141+
早期公开版本提供 macOS Apple Silicon 和 Intel 安装包。Release assets 面向最终用户下载。CI artifacts 作为维护者测试构建产物的临时入口。
142142

143143
## 下载与安装教程
144144

145145
### 1. 下载 DMG 并安装
146146

147-
[最新版本](https://github.com/freestylefly/wesight/releases/latest) 下载 `WeSight-*-arm64.dmg`,打开后将 `WeSight.app` 拖入 `Applications` 文件夹。
147+
[最新版本](https://github.com/freestylefly/wesight/releases/latest) 下载匹配的 macOS DMG:Apple Silicon 使用 `WeSight-*-mac-arm64.dmg`Intel 使用 `WeSight-*-mac-x64.dmg`打开后将 `WeSight.app` 拖入 `Applications` 文件夹。
148148

149149
<p align="center">
150150
<img src="public/readme/tutorial/install-dmg.svg" alt="WeSight DMG 安装示意图" width="760">
@@ -236,9 +236,12 @@ npm run lint
236236
```bash
237237
# macOS
238238
npm run dist:mac
239+
240+
# macOS 单架构安装包
239241
npm run dist:mac:x64
240242
npm run dist:mac:arm64
241-
npm run dist:mac:universal
243+
244+
# 在 native modules 具备双架构合并策略前,不要使用 npm run dist:mac:universal
242245

243246
# Windows
244247
npm run dist:win

electron-builder.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"target": [
6363
"dmg"
6464
],
65+
"artifactName": "${productName}-${version}-mac-${arch}.${ext}",
6566
"icon": "build/icons/mac/icon.icns",
6667
"category": "public.app-category.productivity",
6768
"hardenedRuntime": true,

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@
8989
"dist:mac:x64": "npm run build && npm run compile:electron && npm run build:skills && electron-builder --mac --x64",
9090
"dist:mac:arm64": "npm run build && npm run compile:electron && npm run build:skills && electron-builder --mac --arm64",
9191
"dist:mac:universal": "npm run build && npm run compile:electron && npm run build:skills && electron-builder --mac --universal",
92+
"verify:mac:x64-artifact": "node scripts/verify-mac-artifact.cjs mac-x64",
93+
"verify:mac:arm64-artifact": "node scripts/verify-mac-artifact.cjs mac-arm64",
9294
"predist:win": "npm run build && npm run compile:electron && npm run build:skills",
9395
"dist:win": "npm run setup:python-runtime && npm run build && npm run compile:electron && npm run build:skills && electron-builder --win --x64",
9496
"predist:linux": "npm run build && npm run compile:electron && npm run build:skills",

scripts/electron-builder-hooks.cjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,9 @@ function installSkillDependencies() {
483483
}
484484

485485
async function beforePack(context) {
486-
ensureBundledOpenClawRuntime(context);
486+
if (!isMacTarget(context)) {
487+
ensureBundledOpenClawRuntime(context);
488+
}
487489
// Install skill dependencies first (for all platforms)
488490
installSkillDependencies();
489491

scripts/verify-mac-artifact.cjs

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
'use strict';
2+
3+
const fs = require('fs');
4+
const path = require('path');
5+
const { spawnSync } = require('child_process');
6+
7+
const MacArtifactTarget = {
8+
X64: 'mac-x64',
9+
Arm64: 'mac-arm64',
10+
};
11+
12+
const NativeArchToken = {
13+
[MacArtifactTarget.X64]: 'x86_64',
14+
[MacArtifactTarget.Arm64]: 'arm64',
15+
};
16+
17+
const NativeTargetPathToken = {
18+
[MacArtifactTarget.X64]: ['x64-darwin', 'darwin-x64'],
19+
[MacArtifactTarget.Arm64]: ['arm64-darwin', 'darwin-arm64'],
20+
};
21+
22+
const rootDir = path.resolve(__dirname, '..');
23+
const target = (process.argv[2] || '').trim();
24+
25+
function fail(message) {
26+
console.error(`[verify-mac-artifact] ${message}`);
27+
process.exit(1);
28+
}
29+
30+
function log(message) {
31+
console.log(`[verify-mac-artifact] ${message}`);
32+
}
33+
34+
if (!Object.values(MacArtifactTarget).includes(target)) {
35+
fail(`Usage: node scripts/verify-mac-artifact.cjs ${MacArtifactTarget.X64}|${MacArtifactTarget.Arm64}`);
36+
}
37+
38+
function walk(dir, visitor) {
39+
if (!fs.existsSync(dir)) return;
40+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
41+
const fullPath = path.join(dir, entry.name);
42+
if (entry.isDirectory()) {
43+
visitor(fullPath, entry);
44+
walk(fullPath, visitor);
45+
} else {
46+
visitor(fullPath, entry);
47+
}
48+
}
49+
}
50+
51+
function findPackagedApps() {
52+
const releaseDir = path.join(rootDir, 'release');
53+
const apps = [];
54+
walk(releaseDir, (candidate, entry) => {
55+
if (entry.isDirectory() && candidate.endsWith('.app')) {
56+
apps.push(candidate);
57+
}
58+
});
59+
return apps.sort();
60+
}
61+
62+
function runFile(filePath) {
63+
const result = spawnSync('file', [filePath], {
64+
encoding: 'utf8',
65+
stdio: ['ignore', 'pipe', 'pipe'],
66+
});
67+
if (result.status !== 0) {
68+
fail(`Could not inspect file architecture for ${filePath}: ${result.stderr || result.error?.message || 'unknown error'}`);
69+
}
70+
return (result.stdout || '').trim();
71+
}
72+
73+
function selectApp(apps, expectedToken) {
74+
const matching = apps.find((appPath) => {
75+
const executablePath = path.join(appPath, 'Contents', 'MacOS', 'WeSight');
76+
return fs.existsSync(executablePath) && runFile(executablePath).includes(expectedToken);
77+
});
78+
if (matching) return matching;
79+
return apps[0] || null;
80+
}
81+
82+
function assertFileHasArch(filePath, expectedToken) {
83+
const output = runFile(filePath);
84+
if (!output.includes(expectedToken)) {
85+
fail(`Expected ${filePath} to include ${expectedToken}, got: ${output}`);
86+
}
87+
log(output);
88+
}
89+
90+
function shouldInspectNativeModule(filePath) {
91+
const normalizedPath = filePath.replace(/\\/g, '/');
92+
const targetPathTokens = NativeTargetPathToken[target];
93+
if (targetPathTokens.some((token) => normalizedPath.includes(`/${token}/`) || normalizedPath.includes(`/${token}.node`))) {
94+
return true;
95+
}
96+
97+
const packagedTargetPattern = /\/(?:x64|arm64)-(?:darwin|linux|win32)\/|\/(?:darwin|linux|win32)-(?:x64|arm64)\//;
98+
return !packagedTargetPattern.test(normalizedPath);
99+
}
100+
101+
const apps = findPackagedApps();
102+
const expectedArchToken = NativeArchToken[target];
103+
const appPath = selectApp(apps, expectedArchToken);
104+
if (!appPath) {
105+
fail(`No packaged .app found under ${path.join(rootDir, 'release')}`);
106+
}
107+
108+
const executablePath = path.join(appPath, 'Contents', 'MacOS', 'WeSight');
109+
110+
log(`Checking ${appPath}`);
111+
112+
if (!fs.existsSync(executablePath)) {
113+
fail(`Packaged app executable is missing: ${executablePath}`);
114+
}
115+
assertFileHasArch(executablePath, expectedArchToken);
116+
117+
const nativeModules = [];
118+
const skippedNativeModules = [];
119+
walk(appPath, (candidate, entry) => {
120+
if (!entry.isFile() || !candidate.endsWith('.node')) {
121+
return;
122+
}
123+
124+
if (shouldInspectNativeModule(candidate)) {
125+
nativeModules.push(candidate);
126+
} else {
127+
skippedNativeModules.push(candidate);
128+
}
129+
});
130+
131+
if (nativeModules.length === 0) {
132+
fail('No native .node modules were found in the packaged app.');
133+
}
134+
135+
for (const nativeModule of nativeModules.sort()) {
136+
assertFileHasArch(nativeModule, expectedArchToken);
137+
}
138+
139+
log(`Verified ${nativeModules.length} native module(s).`);
140+
if (skippedNativeModules.length > 0) {
141+
log(`Skipped ${skippedNativeModules.length} non-target vendor native module(s).`);
142+
}

0 commit comments

Comments
 (0)