import { app } from 'electron'; import { existsSync, mkdirSync, realpathSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; export const OPENCLAW_CONFIG_DIR_NAME = '.openclaw'; export const OPENCLAW_RUNTIME_DIR_NAME = 'runtime'; export const OPENCLAW_PACKAGE_DIR_NAME = 'openclaw'; export const OPENCLAW_ENTRY_FILE_NAME = 'openclaw.mjs'; export const USER_DATA_DIR_ENV_NAME = 'ZN_AI_USER_DATA_DIR'; export interface OpenClawRuntimePaths { configDir: string; runtimeDir: string; dir: string; resolvedDir: string; entryPath: string; } export function getOpenClawConfigDir(): string { return join(homedir(), OPENCLAW_CONFIG_DIR_NAME); } export function getUserDataDir(): string { const override = process.env[USER_DATA_DIR_ENV_NAME]?.trim(); if (override) { return override; } return app.getPath('userData'); } export function getOpenClawRuntimeDir(): string { return join(getOpenClawConfigDir(), OPENCLAW_RUNTIME_DIR_NAME); } export function getOpenClawDir(): string { if (app.isPackaged) { return join(process.resourcesPath, OPENCLAW_PACKAGE_DIR_NAME); } return join(app.getAppPath(), 'node_modules', OPENCLAW_PACKAGE_DIR_NAME); } export function getOpenClawResolvedDir(): string { const dir = getOpenClawDir(); if (!existsSync(dir)) { return dir; } try { return realpathSync(dir); } catch { return dir; } } export function getOpenClawEntryPath(): string { return join(getOpenClawDir(), OPENCLAW_ENTRY_FILE_NAME); } export function ensureDir(dir: string): string { if (!existsSync(dir)) { mkdirSync(dir, { recursive: true }); } return dir; } export function ensureOpenClawRuntimeLayout( paths: OpenClawRuntimePaths = getOpenClawRuntimePaths(), ): OpenClawRuntimePaths { ensureDir(paths.configDir); ensureDir(paths.runtimeDir); return paths; } export function getOpenClawRuntimePaths(): OpenClawRuntimePaths { return { configDir: getOpenClawConfigDir(), runtimeDir: getOpenClawRuntimeDir(), dir: getOpenClawDir(), resolvedDir: getOpenClawResolvedDir(), entryPath: getOpenClawEntryPath(), }; }