fix(mac): harden restart and dSYM packaging

This commit is contained in:
Vincent Koc
2026-05-26 22:01:21 +02:00
parent 4d6593642e
commit 639e7ff997
5 changed files with 73 additions and 17 deletions

View File

@@ -8,6 +8,8 @@ Docs: https://docs.openclaw.ai
### Fixes
- Mac: prefer the freshly packaged app in restart flows and collect dSYMs only for requested build architectures so stale installed apps and unrequested arch symbol directories cannot break validation.
## 2026.5.26
### Changes

View File

@@ -19,6 +19,11 @@ APP_VERSION_INPUT="${APP_VERSION:-$(cd "$ROOT_DIR" && node -p "require('./packag
# Default to universal binary for distribution builds (supports both Apple Silicon and Intel Macs)
export BUILD_ARCHS="${BUILD_ARCHS:-all}"
export BUILD_CONFIG
DSYM_ARCHS_VALUE="$BUILD_ARCHS"
if [[ "$DSYM_ARCHS_VALUE" == "all" ]]; then
DSYM_ARCHS_VALUE="arm64 x86_64"
fi
IFS=' ' read -r -a DSYM_ARCHS <<< "$DSYM_ARCHS_VALUE"
# Use release bundle ID (not .debug) so Sparkle auto-update works.
# The .debug suffix in package-mac-app.sh blanks SUFeedURL intentionally for dev builds.
@@ -136,24 +141,49 @@ else
fi
if [[ "$SKIP_DSYM" != "1" ]]; then
DSYM_ARM64="$(find "$BUILD_ROOT/arm64" -type d -path "*/$BUILD_CONFIG/$PRODUCT.dSYM" -print -quit)"
DSYM_X86="$(find "$BUILD_ROOT/x86_64" -type d -path "*/$BUILD_CONFIG/$PRODUCT.dSYM" -print -quit)"
if [[ -n "$DSYM_ARM64" || -n "$DSYM_X86" ]]; then
DSYM_PATHS=()
MISSING_DSYM_ARCHS=()
for arch in "${DSYM_ARCHS[@]}"; do
if [[ ! -d "$BUILD_ROOT/$arch" ]]; then
MISSING_DSYM_ARCHS+=("$arch")
continue
fi
DSYM_FOR_ARCH="$(find "$BUILD_ROOT/$arch" -type d -path "*/$BUILD_CONFIG/$PRODUCT.dSYM" -print -quit)"
if [[ -n "$DSYM_FOR_ARCH" ]]; then
DSYM_PATHS+=("$DSYM_FOR_ARCH")
else
MISSING_DSYM_ARCHS+=("$arch")
fi
done
if [[ "${#MISSING_DSYM_ARCHS[@]}" -gt 0 ]]; then
echo "Error: dSYM not found for architecture(s): ${MISSING_DSYM_ARCHS[*]} (set SKIP_DSYM=1 to skip symbols)" >&2
exit 1
fi
if [[ "${#DSYM_PATHS[@]}" -gt 0 ]]; then
TMP_DSYM="$ROOT_DIR/dist/$PRODUCT.dSYM"
rm -rf "$TMP_DSYM"
if [[ -n "$DSYM_ARM64" && -n "$DSYM_X86" ]]; then
cp -R "$DSYM_ARM64" "$TMP_DSYM"
if [[ "${#DSYM_PATHS[@]}" -gt 1 ]]; then
cp -R "${DSYM_PATHS[0]}" "$TMP_DSYM"
DWARF_OUT="$TMP_DSYM/Contents/Resources/DWARF/$PRODUCT"
DWARF_ARM="$DSYM_ARM64/Contents/Resources/DWARF/$PRODUCT"
DWARF_X86="$DSYM_X86/Contents/Resources/DWARF/$PRODUCT"
if [[ -f "$DWARF_ARM" && -f "$DWARF_X86" ]]; then
/usr/bin/lipo -create "$DWARF_ARM" "$DWARF_X86" -output "$DWARF_OUT"
DWARF_INPUTS=()
for dsym in "${DSYM_PATHS[@]}"; do
DWARF_INPUT="$dsym/Contents/Resources/DWARF/$PRODUCT"
if [[ ! -f "$DWARF_INPUT" ]]; then
echo "Error: missing DWARF binaries for dSYM merge (set SKIP_DSYM=1 to skip symbols)" >&2
exit 1
fi
DWARF_INPUTS+=("$DWARF_INPUT")
done
if [[ "${#DWARF_INPUTS[@]}" -gt 1 ]]; then
/usr/bin/lipo -create "${DWARF_INPUTS[@]}" -output "$DWARF_OUT"
else
echo "Error: missing DWARF binaries for dSYM merge (set SKIP_DSYM=1 to skip symbols)" >&2
exit 1
fi
else
cp -R "${DSYM_ARM64:-$DSYM_X86}" "$TMP_DSYM"
cp -R "${DSYM_PATHS[0]}" "$TMP_DSYM"
fi
echo "🧩 dSYM: $DSYM_ZIP"
rm -f "$DSYM_ZIP"

View File

@@ -188,13 +188,11 @@ fi
run_step "package app" bash -lc "cd '${ROOT_DIR}' && SKIP_TSC=${SKIP_TSC:-1} '${ROOT_DIR}/scripts/package-mac-app.sh'"
choose_app_bundle() {
if [[ -n "${APP_BUNDLE}" && -d "${APP_BUNDLE}" ]]; then
return 0
fi
if [[ -d "/Applications/OpenClaw.app" ]]; then
APP_BUNDLE="/Applications/OpenClaw.app"
return 0
if [[ -n "${APP_BUNDLE}" ]]; then
if [[ -d "${APP_BUNDLE}" ]]; then
return 0
fi
fail "OPENCLAW_APP_BUNDLE does not exist: ${APP_BUNDLE}"
fi
if [[ -d "${ROOT_DIR}/dist/OpenClaw.app" ]]; then
@@ -205,6 +203,11 @@ choose_app_bundle() {
return 0
fi
if [[ -d "/Applications/OpenClaw.app" ]]; then
APP_BUNDLE="/Applications/OpenClaw.app"
return 0
fi
fail "App bundle not found. Set OPENCLAW_APP_BUNDLE to your installed OpenClaw.app"
}

View File

@@ -83,6 +83,12 @@ describe("package-mac-dist plist validation", () => {
const script = readFileSync(scriptPath, "utf8");
const dsymBlock = script.slice(script.indexOf('if [[ "$SKIP_DSYM" != "1" ]]'));
expect(dsymBlock).toContain('for arch in "${DSYM_ARCHS[@]}"');
expect(dsymBlock).toContain('if [[ ! -d "$BUILD_ROOT/$arch" ]]; then');
expect(dsymBlock).toContain('MISSING_DSYM_ARCHS+=("$arch")');
expect(dsymBlock).toContain("Error: dSYM not found for architecture(s):");
expect(dsymBlock).not.toContain('find "$BUILD_ROOT/arm64"');
expect(dsymBlock).not.toContain('find "$BUILD_ROOT/x86_64"');
expect(dsymBlock).toContain("Error: missing DWARF binaries for dSYM merge");
expect(dsymBlock).toContain("Error: dSYM not found");
expect(dsymBlock).toContain("exit 1");

View File

@@ -73,4 +73,19 @@ describe("scripts/restart-mac.sh", () => {
);
expect(script).not.toContain("lsof -iTCP:${GATEWAY_PORT} -sTCP:LISTEN | head -n 5 || true");
});
it("prefers the freshly packaged app unless an explicit app bundle is set", () => {
const script = readFileSync(restartScriptPath, "utf8");
const chooseBlock = script.slice(
script.indexOf("choose_app_bundle()"),
script.indexOf("choose_app_bundle", script.indexOf("choose_app_bundle()") + 1),
);
expect(chooseBlock).toContain('fail "OPENCLAW_APP_BUNDLE does not exist: ${APP_BUNDLE}"');
expect(chooseBlock.indexOf('${ROOT_DIR}/dist/OpenClaw.app')).toBeGreaterThan(-1);
expect(chooseBlock.indexOf('/Applications/OpenClaw.app')).toBeGreaterThan(-1);
expect(chooseBlock.indexOf('${ROOT_DIR}/dist/OpenClaw.app')).toBeLessThan(
chooseBlock.indexOf('/Applications/OpenClaw.app'),
);
});
});