diff --git a/apps/client/src/desktop.ts b/apps/client/src/desktop.ts index e762aa65b..88f3e0731 100644 --- a/apps/client/src/desktop.ts +++ b/apps/client/src/desktop.ts @@ -8,7 +8,7 @@ import electronContextMenu from "./menus/electron_context_menu.js"; import glob from "./services/glob.js"; import { t } from "./services/i18n.js"; import options from "./services/options.js"; -import server from "./services/server.js"; +import { isRunningUnderRosetta2 } from "./services/rosetta_detection.js"; import type ElectronRemote from "@electron/remote"; import type Electron from "electron"; import "./stylesheets/bootstrap.scss"; @@ -119,13 +119,12 @@ function initDarkOrLightMode(style: CSSStyleDeclaration) { nativeTheme.themeSource = themeSource; } -async function checkRosetta2Warning() { +function checkRosetta2Warning() { if (!utils.isElectron()) return; try { - // Check if running under Rosetta 2 by calling the server - const response = await server.get("api/system-info/rosetta-check") as { isRunningUnderRosetta2: boolean }; - if (response.isRunningUnderRosetta2) { + // Check if running under Rosetta 2 directly on client + if (isRunningUnderRosetta2()) { // Trigger the Rosetta 2 warning dialog appContext.triggerCommand("showRosettaWarning", {}); } diff --git a/apps/client/src/services/rosetta_detection.ts b/apps/client/src/services/rosetta_detection.ts new file mode 100644 index 000000000..b3d0fccd2 --- /dev/null +++ b/apps/client/src/services/rosetta_detection.ts @@ -0,0 +1,34 @@ +import utils from "./utils.js"; + +/** + * Detects if the application is running under Rosetta 2 translation on Apple Silicon. + * This happens when an x64 version of the app is run on an M1/M2/M3 Mac. + * Uses the macOS sysctl.proc_translated to properly detect translation. + * @returns true if running under Rosetta 2, false otherwise + */ +export function isRunningUnderRosetta2(): boolean { + if (!utils.isElectron()) return false; + + const process = utils.dynamicRequire("process"); + const { execSync } = utils.dynamicRequire("child_process"); + + // Only check on macOS + if (process.platform !== "darwin") return false; + + try { + // Use sysctl.proc_translated to check if process is being translated by Rosetta 2 + // This is the proper way to detect Rosetta 2 translation + const result = execSync("sysctl -n sysctl.proc_translated 2>/dev/null", { + encoding: "utf8", + timeout: 1000 + }).trim(); + + // Returns "1" if running under Rosetta 2, "0" if native ARM64 + // Returns empty string or error on Intel Macs (where the key doesn't exist) + return result === "1"; + } catch (error) { + // If the command fails (e.g., on Intel Macs), assume not running under Rosetta 2 + console.debug("Could not check Rosetta 2 status:", error); + return false; + } +} diff --git a/apps/server/src/routes/api/system_info.ts b/apps/server/src/routes/api/system_info.ts deleted file mode 100644 index 4d49f4ca2..000000000 --- a/apps/server/src/routes/api/system_info.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { isRunningUnderRosetta2 } from "../../services/utils.js"; -import type { Request, Response } from "express"; - -function rosettaCheck(req: Request, res: Response) { - res.json({ - isRunningUnderRosetta2: isRunningUnderRosetta2() - }); -} - -export default { - rosettaCheck -}; diff --git a/apps/server/src/routes/routes.ts b/apps/server/src/routes/routes.ts index eee979859..b988ecb11 100644 --- a/apps/server/src/routes/routes.ts +++ b/apps/server/src/routes/routes.ts @@ -58,7 +58,6 @@ import ollamaRoute from "./api/ollama.js"; import openaiRoute from "./api/openai.js"; import anthropicRoute from "./api/anthropic.js"; import llmRoute from "./api/llm.js"; -import systemInfoRoute from "./api/system_info.js"; import etapiAuthRoutes from "../etapi/auth.js"; import etapiAppInfoRoutes from "../etapi/app_info.js"; @@ -239,7 +238,6 @@ function register(app: express.Application) { apiRoute(PST, "/api/recent-notes", recentNotesRoute.addRecentNote); apiRoute(GET, "/api/app-info", appInfoRoute.getAppInfo); apiRoute(GET, "/api/metrics", metricsRoute.getMetrics); - apiRoute(GET, "/api/system-info/rosetta-check", systemInfoRoute.rosettaCheck); // docker health check route(GET, "/api/health-check", [], () => ({ status: "ok" }), apiResultHandler); diff --git a/apps/server/src/services/utils.ts b/apps/server/src/services/utils.ts index c02a325d8..7555e1a7c 100644 --- a/apps/server/src/services/utils.ts +++ b/apps/server/src/services/utils.ts @@ -23,33 +23,7 @@ export const isElectron = !!process.versions["electron"]; export const isDev = !!(process.env.TRILIUM_ENV && process.env.TRILIUM_ENV === "dev"); -/** - * Detects if the application is running under Rosetta 2 translation on Apple Silicon. - * This happens when an x64 version of the app is run on an M1/M2/M3 Mac. - * Uses the macOS sysctl.proc_translated to properly detect translation. - * @returns true if running under Rosetta 2, false otherwise - */ -export const isRunningUnderRosetta2 = () => { - if (!isMac) return false; - try { - // Use child_process to check sysctl.proc_translated - // This is the proper way to detect Rosetta 2 translation - const { execSync } = require("child_process"); - const result = execSync("sysctl -n sysctl.proc_translated 2>/dev/null", { - encoding: "utf8", - timeout: 1000 - }).trim(); - - // 1 means the process is being translated by Rosetta 2 - // 0 means native execution - // If the sysctl doesn't exist (on Intel Macs), this will return empty/error - return result === "1"; - } catch (error) { - // If sysctl fails or doesn't exist (Intel Macs), not running under Rosetta 2 - return false; - } -}; export function newEntityId() { return randomString(12); @@ -423,7 +397,6 @@ export default { isElectron, isEmptyOrWhitespace, isMac, - isRunningUnderRosetta2, isStringNote, isWindows, md5,