diff --git a/apps/macos/Sources/Clawdbot/CLIInstaller.swift b/apps/macos/Sources/Clawdbot/CLIInstaller.swift index b9113e27a..4428f32f7 100644 --- a/apps/macos/Sources/Clawdbot/CLIInstaller.swift +++ b/apps/macos/Sources/Clawdbot/CLIInstaller.swift @@ -38,6 +38,12 @@ enum CLIInstaller { let expected = GatewayEnvironment.expectedGatewayVersionString() ?? "latest" let prefix = Self.installPrefix() await statusHandler("Installing clawdbot CLI…") + + // 1. Architecture/Rosetta Guard + if self.isRosettaTranslated() { + await statusHandler("Warning: Rosetta detected. Attempting to force arm64…") + } + let cmd = self.installScriptCommand(version: expected, prefix: prefix) let response = await ShellExecutor.runDetailed(command: cmd, cwd: nil, env: nil, timeout: 900) @@ -94,6 +100,16 @@ enum CLIInstaller { private static func shellEscape(_ raw: String) -> String { "'" + raw.replacingOccurrences(of: "'", with: "'\"'\"'") + "'" } + + private static func isRosettaTranslated() -> Bool { + var ret = 0 + var size = MemoryLayout.size(ofValue: ret) + // sysctl.proc_translated: 1 if translated (Rosetta), 0 if native + if sysctlbyname("sysctl.proc_translated", &ret, &size, nil, 0) == 0 { + return ret == 1 + } + return false + } } private struct InstallEvent: Decodable { diff --git a/scripts/check-env.sh b/scripts/check-env.sh new file mode 100755 index 000000000..c5413066f --- /dev/null +++ b/scripts/check-env.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +echo "=== Clawdbot Environment Diagnostic ===" +echo "Date: $(date)" +echo "Host: $(hostname)" +echo "-------------------------------------" + +# 1. Architecture Check +ARCH=$(uname -m) +echo "Architecture: $ARCH" + +IS_ARM64=false +if [[ "$ARCH" == "arm64" ]]; then + IS_ARM64=true +fi + +# 2. Rosetta Check +IS_ROSETTA=false +if [[ "$(sysctl -in sysctl.proc_translated)" == "1" ]]; then + IS_ROSETTA=true + echo "⚠️ WARNING: Running under Rosetta translation!" + echo " Your terminal is emulating x86_64 on Apple Silicon." + echo " This may cause installation issues." + echo " Resolution: Use a native terminal or ensure 'Open using Rosetta' is unchecked." +else + echo "Rosetta Status: Not Active (Native)" +fi + +# 3. Homebrew Check +BREW_PATH=$(which brew) +echo "Homebrew Path: $BREW_PATH" + +if [[ "$IS_ARM64" == "true" || "$IS_ROSETTA" == "true" ]]; then + if [[ "$BREW_PATH" == "/usr/local/bin/brew" && "$IS_ROSETTA" == "true" ]]; then + echo "⚠️ WARNING: Homebrew found in Intel path (/usr/local) while on Apple Silicon (via Rosetta)." + echo " Recommmended: use /opt/homebrew (Native)." + elif [[ "$BREW_PATH" == "/opt/homebrew/bin/brew" ]]; then + echo "✅ Homebrew is in the correct Native Apple Silicon path." + fi +fi + +# 4. Node Check +NODE_PATH=$(which node) +NODE_VER=$(node -v) +NODE_ARCH=$(node -p "process.arch") +echo "Node Path: $NODE_PATH" +echo "Node Version: $NODE_VER" +echo "Node Arch: $NODE_ARCH" + +if [[ "$IS_ROSETTA" == "true" && "$NODE_ARCH" == "x64" ]]; then + echo "⚠️ WARNING: Node.js is running as x64 (Intel) under Rosetta." + echo " Native modules may fail to build." +fi + +echo "-------------------------------------" +echo "Diagnostic Complete." diff --git a/scripts/postinstall.js b/scripts/postinstall.js index 3211b194f..e964cddb8 100644 --- a/scripts/postinstall.js +++ b/scripts/postinstall.js @@ -248,10 +248,36 @@ function applyPatchFile({ patchPath, targetDir }) { applyPatchSet({ patchText, targetDir }); } -function main() { + +async function checkArchitecture() { + if (process.platform !== "darwin") return; + + // Check for Rosetta translation + try { + const { execSync } = await import("node:child_process"); + const isTranslated = execSync("sysctl -in sysctl.proc_translated").toString().trim() === "1"; + + if (isTranslated) { + console.warn("\n\x1b[33m" + "=".repeat(60)); + console.warn(" [WARNING] ROSETTA DETECTED"); + console.warn("=".repeat(60)); + console.warn(" You are running this installation under Rosetta (x86_64 emulation)."); + console.warn(" This may cause native dependencies to build incorrectly for Apple Silicon."); + console.warn(" Recommended: Use a native Terminal (uncheck 'Open using Rosetta')."); + console.warn("=".repeat(60) + "\x1b[0m\n"); + } + } catch (e) { + // Ignore errors on non-Apple systems or if sysctl fails + } +} + +async function main() { + await checkArchitecture(); + const repoRoot = getRepoRoot(); process.chdir(repoRoot); + ensureExecutable(path.join(repoRoot, "dist", "entry.js")); setupGitHooks({ repoRoot });