import { existsSync, readdirSync, rmSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path'; function fsPath(filePath: string): string { if (process.platform !== 'win32') return filePath; if (!filePath) return filePath; if (filePath.startsWith('\\\\?\\')) return filePath; return `\\\\?\\${filePath.replace(/\//g, '\\')}`; } function removeClipboardPackagesFromScope(scopeDir: string): number { if (!existsSync(fsPath(scopeDir))) return 0; let removed = 0; let entries: string[] = []; try { entries = readdirSync(fsPath(scopeDir)); } catch { return 0; } for (const entry of entries) { if (entry !== 'clipboard' && !entry.startsWith('clipboard-')) continue; try { rmSync(fsPath(join(scopeDir, entry)), { recursive: true, force: true }); removed += 1; } catch { // Best-effort cleanup only. } } return removed; } function cleanupNodeModules(nodeModulesDir: string): number { return removeClipboardPackagesFromScope(join(nodeModulesDir, '@mariozechner')); } function cleanupNodeModulesChildren(rootDir: string): number { if (!existsSync(fsPath(rootDir))) return 0; let removed = 0; let entries: Array<{ name: string; isDirectory: () => boolean }> = []; try { entries = readdirSync(fsPath(rootDir), { withFileTypes: true }) as typeof entries; } catch { return 0; } for (const entry of entries) { if (!entry.isDirectory()) continue; removed += cleanupNodeModules(join(rootDir, entry.name, 'node_modules')); } return removed; } export function cleanupOpenClawRuntimeNativeClipboard(openclawDir: string): number { return cleanupNodeModules(join(openclawDir, 'node_modules')); } export function cleanupOpenClawUserNativeClipboard(): number { const openclawHome = join(homedir(), '.openclaw'); let removed = 0; removed += cleanupNodeModules(join(openclawHome, 'runtime', 'openclaw', 'node_modules')); removed += cleanupNodeModules(join(openclawHome, 'npm', 'node_modules')); removed += cleanupNodeModules(join(openclawHome, 'node_modules')); removed += cleanupNodeModulesChildren(join(openclawHome, 'extensions')); removed += cleanupNodeModulesChildren(join(openclawHome, 'plugin-runtime-deps')); return removed; }