#!/usr/bin/env node import { spawnSync } from "child_process" import { cpSync, existsSync, mkdirSync, readdirSync, rmSync } from "fs" import path from "path" import { fileURLToPath } from "url" const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) const cliRoot = path.resolve(__dirname, "..") const sourceDir = path.resolve(cliRoot, "../opencode-config") const targetDir = path.resolve(cliRoot, "dist/opencode-config") const nodeModulesDir = path.resolve(sourceDir, "node_modules") const selfLinkDir = path.resolve(nodeModulesDir, "@codenomad", "opencode-config") const npmExecPath = process.env.npm_execpath const npmNodeExecPath = process.env.npm_node_execpath function stripNodeModuleBins(rootDir) { const root = path.join(rootDir, "node_modules") if (!existsSync(root)) { return 0 } const stack = [root] let removed = 0 while (stack.length > 0) { const current = stack.pop() if (!current) break let entries try { entries = readdirSync(current, { withFileTypes: true }) } catch { continue } for (const entry of entries) { const full = path.join(current, entry.name) if (entry.name === ".bin") { rmSync(full, { recursive: true, force: true }) removed += 1 continue } if (entry.isDirectory()) { stack.push(full) } } } return removed } if (!existsSync(sourceDir)) { console.error(`[copy-opencode-config] Missing source directory at ${sourceDir}`) process.exit(1) } if (!existsSync(nodeModulesDir)) { console.log(`[copy-opencode-config] Installing opencode-config dependencies in ${sourceDir}`) const npmArgs = [ "install", "--prefix", sourceDir, "--omit=dev", "--ignore-scripts", "--fund=false", "--audit=false", "--package-lock=false", "--workspaces=false", ] const env = { ...process.env, npm_config_workspaces: "false" } const npmCli = npmExecPath && npmNodeExecPath ? [npmNodeExecPath, [npmExecPath, ...npmArgs]] : null const result = npmCli ? spawnSync(npmCli[0], npmCli[1], { cwd: sourceDir, stdio: "inherit", env }) : spawnSync("npm", npmArgs, { cwd: sourceDir, stdio: "inherit", env, shell: process.platform === "win32" }) if (result.status !== 0) { if (result.error) { console.error("[copy-opencode-config] npm install failed to start", result.error) } console.error("[copy-opencode-config] Failed to install opencode-config dependencies") process.exit(result.status ?? 1) } } // npm can create a self-referential link for scoped packages on Windows. // That link causes recursive copies (ELOOP) during bundling. rmSync(selfLinkDir, { recursive: true, force: true }) rmSync(targetDir, { recursive: true, force: true }) mkdirSync(path.dirname(targetDir), { recursive: true }) cpSync(sourceDir, targetDir, { recursive: true }) const removedBins = stripNodeModuleBins(targetDir) if (removedBins > 0) { console.log(`[copy-opencode-config] Removed ${removedBins} node_modules/.bin directories`) } console.log(`[copy-opencode-config] Copied ${sourceDir} -> ${targetDir}`)