import { existsSync, readdirSync, rmSync, statSync } from "node:fs"; import { basename, join, resolve } from "node:path"; const root = resolve(process.argv[2] ?? "."); const nodeModulesDir = resolve(root, "node_modules"); const STRIP_DIR_NAMES = new Set([ ".github", "__mocks__", "__tests__", "coverage", "doc", "docs", "example", "examples", "test", "tests", ]); const STRIP_FILE_PATTERNS = [ /\.map$/i, /\.d\.cts$/i, /\.d\.ts$/i, /^README(\..+)?$/i, /^CHANGELOG(\..+)?$/i, ]; function safeStat(path) { try { return statSync(path); } catch { return null; } } function removePath(path) { rmSync(path, { recursive: true, force: true }); } function walkAndPrune(dir) { if (!existsSync(dir)) return; for (const entry of readdirSync(dir, { withFileTypes: true })) { const path = join(dir, entry.name); const stats = entry.isSymbolicLink() ? safeStat(path) : null; const isDirectory = entry.isDirectory() || stats?.isDirectory(); const isFile = entry.isFile() || stats?.isFile(); if (isDirectory) { if (STRIP_DIR_NAMES.has(entry.name)) { removePath(path); continue; } walkAndPrune(path); continue; } if (isFile && STRIP_FILE_PATTERNS.some((pattern) => pattern.test(entry.name))) { removePath(path); } } } function currentKoffiVariant() { if (process.platform === "darwin" && process.arch === "arm64") return "darwin_arm64"; if (process.platform === "darwin" && process.arch === "x64") return "darwin_x64"; if (process.platform === "linux" && process.arch === "arm64") return "linux_arm64"; if (process.platform === "linux" && process.arch === "x64") return "linux_x64"; if (process.platform === "win32" && process.arch === "arm64") return "win32_arm64"; if (process.platform === "win32" && process.arch === "x64") return "win32_x64"; return null; } function pruneKoffi(nodeModulesRoot) { const koffiRoot = join(nodeModulesRoot, "koffi"); if (!existsSync(koffiRoot)) return; for (const dirName of ["doc", "src", "vendor"]) { removePath(join(koffiRoot, dirName)); } const buildRoot = join(koffiRoot, "build", "koffi"); if (!existsSync(buildRoot)) return; const keep = currentKoffiVariant(); for (const entry of readdirSync(buildRoot, { withFileTypes: true })) { if (entry.name === keep) continue; removePath(join(buildRoot, entry.name)); } } function pruneBetterSqlite3(nodeModulesRoot) { const pkgRoot = join(nodeModulesRoot, "better-sqlite3"); if (!existsSync(pkgRoot)) return; removePath(join(pkgRoot, "deps")); removePath(join(pkgRoot, "src")); removePath(join(pkgRoot, "binding.gyp")); const buildRoot = join(pkgRoot, "build"); const releaseRoot = join(buildRoot, "Release"); if (existsSync(releaseRoot)) { for (const entry of readdirSync(releaseRoot, { withFileTypes: true })) { if (entry.name === "better_sqlite3.node") continue; removePath(join(releaseRoot, entry.name)); } } for (const entry of ["Makefile", "binding.Makefile", "config.gypi", "deps", "gyp-mac-tool", "test_extension.target.mk", "better_sqlite3.target.mk"]) { removePath(join(buildRoot, entry)); } } function pruneLiteparse(nodeModulesRoot) { const pkgRoot = join(nodeModulesRoot, "@llamaindex", "liteparse"); if (!existsSync(pkgRoot)) return; if (existsSync(join(pkgRoot, "dist"))) { removePath(join(pkgRoot, "src")); } } function prunePiCodingAgent(nodeModulesRoot) { const pkgRoot = join(nodeModulesRoot, "@mariozechner", "pi-coding-agent"); if (!existsSync(pkgRoot)) return; removePath(join(pkgRoot, "docs")); removePath(join(pkgRoot, "examples")); } if (!existsSync(nodeModulesDir)) { process.exit(0); } walkAndPrune(nodeModulesDir); pruneKoffi(nodeModulesDir); pruneBetterSqlite3(nodeModulesDir); pruneLiteparse(nodeModulesDir); prunePiCodingAgent(nodeModulesDir); console.log(`[feynman] pruned runtime deps in ${basename(root)}`);