mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(mac): use corepack pnpm for app packaging
This commit is contained in:
@@ -9,6 +9,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Fixes
|
||||
|
||||
- Crabbox: bootstrap raw AWS macOS JavaScript commands launched through `/usr/bin/env` so native mac runners without preinstalled Node, Corepack, or pnpm can still run wrapped Node and pnpm proof.
|
||||
- macOS: let app packaging fall back to `corepack pnpm` when a fresh native runner has Node/Corepack but no pnpm shim on `PATH`.
|
||||
|
||||
## 2026.5.26
|
||||
|
||||
|
||||
@@ -65,6 +65,30 @@ sparkle_framework_for_arch() {
|
||||
echo "$(build_path_for_arch "$1")/$BUILD_CONFIG/Sparkle.framework"
|
||||
}
|
||||
|
||||
PNPM_CMD=()
|
||||
|
||||
resolve_pnpm_cmd() {
|
||||
if command -v pnpm >/dev/null 2>&1; then
|
||||
PNPM_CMD=(pnpm)
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v corepack >/dev/null 2>&1 && (cd "$ROOT_DIR" && corepack pnpm --version >/dev/null 2>&1); then
|
||||
PNPM_CMD=(corepack pnpm)
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "ERROR: pnpm is not on PATH and corepack pnpm is unavailable. Install pnpm or run with Node/Corepack on PATH." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
run_pnpm() {
|
||||
if [[ "${#PNPM_CMD[@]}" -eq 0 ]]; then
|
||||
resolve_pnpm_cmd
|
||||
fi
|
||||
(cd "$ROOT_DIR" && "${PNPM_CMD[@]}" "$@")
|
||||
}
|
||||
|
||||
merge_framework_machos() {
|
||||
local primary="$1"
|
||||
local dest="$2"
|
||||
@@ -128,7 +152,7 @@ merge_framework_machos() {
|
||||
|
||||
if [[ "${SKIP_PNPM_INSTALL:-0}" != "1" ]]; then
|
||||
echo "📦 Ensuring deps (pnpm install --frozen-lockfile)"
|
||||
(cd "$ROOT_DIR" && pnpm install --frozen-lockfile --config.node-linker=hoisted)
|
||||
run_pnpm install --frozen-lockfile --config.node-linker=hoisted
|
||||
else
|
||||
echo "📦 Skipping pnpm install (SKIP_PNPM_INSTALL=1)"
|
||||
fi
|
||||
@@ -153,7 +177,7 @@ fi
|
||||
|
||||
if [[ "${SKIP_TSC:-0}" != "1" ]]; then
|
||||
echo "📦 Building JS (pnpm build)"
|
||||
(cd "$ROOT_DIR" && pnpm build)
|
||||
run_pnpm build
|
||||
else
|
||||
echo "📦 Skipping JS build (SKIP_TSC=1)"
|
||||
fi
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { chmodSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
@@ -36,6 +36,17 @@ function runHelper(script: string) {
|
||||
});
|
||||
}
|
||||
|
||||
function getPackageManagerHelperBlock(): string {
|
||||
const script = readFileSync(scriptPath, "utf8");
|
||||
const start = script.indexOf("PNPM_CMD=()");
|
||||
const end = script.indexOf("merge_framework_machos()");
|
||||
|
||||
expect(start).toBeGreaterThanOrEqual(0);
|
||||
expect(end).toBeGreaterThan(start);
|
||||
|
||||
return script.slice(start, end);
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
for (const dir of tempDirs.splice(0)) {
|
||||
rmSync(dir, { recursive: true, force: true });
|
||||
@@ -50,11 +61,71 @@ describe("package-mac-app plist stamping", () => {
|
||||
script.indexOf('if [[ -z "${APP_BUILD:-}" ]]'),
|
||||
);
|
||||
|
||||
expect(installBlock).toContain("pnpm install --frozen-lockfile");
|
||||
expect(installBlock).toContain("run_pnpm install --frozen-lockfile");
|
||||
expect(installBlock).toContain("--config.node-linker=hoisted");
|
||||
expect(installBlock).not.toContain("--no-frozen-lockfile");
|
||||
});
|
||||
|
||||
it("falls back to corepack pnpm when the pnpm shim is absent", () => {
|
||||
const helperBlock = getPackageManagerHelperBlock();
|
||||
const tempRoot = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-root-"));
|
||||
const toolsDir = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-tools-"));
|
||||
const logPath = path.join(tempRoot, "corepack.log");
|
||||
tempDirs.push(tempRoot, toolsDir);
|
||||
|
||||
const corepackPath = path.join(toolsDir, "corepack");
|
||||
writeFileSync(
|
||||
corepackPath,
|
||||
[
|
||||
"#!/usr/bin/env bash",
|
||||
"set -euo pipefail",
|
||||
"printf '%s|%s\\n' \"$PWD\" \"$*\" >> \"$OPENCLAW_TEST_LOG\"",
|
||||
"if [[ \"${1:-}\" == \"pnpm\" && \"${2:-}\" == \"--version\" ]]; then",
|
||||
" echo '11.2.2'",
|
||||
"fi",
|
||||
"",
|
||||
].join("\n"),
|
||||
"utf8",
|
||||
);
|
||||
chmodSync(corepackPath, 0o755);
|
||||
|
||||
const result = runHelper(`
|
||||
set -euo pipefail
|
||||
ROOT_DIR=${JSON.stringify(tempRoot)}
|
||||
OPENCLAW_TEST_LOG=${JSON.stringify(logPath)}
|
||||
export OPENCLAW_TEST_LOG
|
||||
PATH=${JSON.stringify(`${toolsDir}:/usr/bin:/bin`)}
|
||||
${helperBlock}
|
||||
run_pnpm install --frozen-lockfile --config.node-linker=hoisted
|
||||
run_pnpm build
|
||||
`);
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(readFileSync(logPath, "utf8").trim().split("\n")).toEqual([
|
||||
`${tempRoot}|pnpm --version`,
|
||||
`${tempRoot}|pnpm install --frozen-lockfile --config.node-linker=hoisted`,
|
||||
`${tempRoot}|pnpm build`,
|
||||
]);
|
||||
});
|
||||
|
||||
it("fails with an actionable error when neither pnpm nor corepack pnpm is available", () => {
|
||||
const helperBlock = getPackageManagerHelperBlock();
|
||||
const tempRoot = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-root-"));
|
||||
const toolsDir = mkdtempSync(path.join(tmpdir(), "openclaw-package-pnpm-tools-"));
|
||||
tempDirs.push(tempRoot, toolsDir);
|
||||
|
||||
const result = runHelper(`
|
||||
set -euo pipefail
|
||||
ROOT_DIR=${JSON.stringify(tempRoot)}
|
||||
PATH=${JSON.stringify(`${toolsDir}:/usr/bin:/bin`)}
|
||||
${helperBlock}
|
||||
run_pnpm build
|
||||
`);
|
||||
|
||||
expect(result.status).toBe(1);
|
||||
expect(result.stderr).toContain("pnpm is not on PATH and corepack pnpm is unavailable");
|
||||
});
|
||||
|
||||
it("does not kill unrelated OpenClaw processes during packaging", () => {
|
||||
const script = readFileSync(scriptPath, "utf8");
|
||||
const stopBlock = script.slice(
|
||||
|
||||
Reference in New Issue
Block a user