import { homedir } from 'node:os' import { resolve as resolvePath } from 'node:path' export interface SynthesisConfig { bridgePort: number channelWsPort: number permissionMode: string idleKillMs: number maxProcesses: number mappingDbPath: string channelName: string } const DEFAULTS: SynthesisConfig = { bridgePort: 18900, channelWsPort: 18901, permissionMode: 'bypassPermissions', idleKillMs: 3_600_000, maxProcesses: 16, mappingDbPath: '~/.openclaw/synthesis/sessions.json', channelName: 'synthesis', } function expand(p: string): string { if (p.startsWith('~')) return resolvePath(homedir(), p.slice(2)) return resolvePath(p) } export function normalizeConfig(raw: unknown): SynthesisConfig { const r = (raw ?? {}) as Partial const merged: SynthesisConfig = { bridgePort: typeof r.bridgePort === 'number' ? r.bridgePort : DEFAULTS.bridgePort, channelWsPort: typeof r.channelWsPort === 'number' ? r.channelWsPort : DEFAULTS.channelWsPort, permissionMode: typeof r.permissionMode === 'string' && r.permissionMode ? r.permissionMode : DEFAULTS.permissionMode, idleKillMs: typeof r.idleKillMs === 'number' ? r.idleKillMs : DEFAULTS.idleKillMs, maxProcesses: typeof r.maxProcesses === 'number' ? r.maxProcesses : DEFAULTS.maxProcesses, mappingDbPath: typeof r.mappingDbPath === 'string' && r.mappingDbPath ? r.mappingDbPath : DEFAULTS.mappingDbPath, channelName: typeof r.channelName === 'string' && r.channelName ? r.channelName : DEFAULTS.channelName, } merged.mappingDbPath = expand(merged.mappingDbPath) return merged }