#!/usr/bin/env node const fs = require("fs"); const path = require("path"); const { execSync } = require("child_process"); const OPENCODE_DIR = path.join(process.env.HOME || "/root", ".config", "opencode"); function getPackageDir() { try { return path.resolve(__dirname, ".."); } catch { return null; } } function isGlobalInstall() { if (process.env.npm_config_global === "true") return true; if (process.env.npm_config_global === "1") return true; return false; } function copyFile(src, dest, force) { if (!fs.existsSync(src)) return { copied: 0, skipped: 0 }; const dir = path.dirname(dest); fs.mkdirSync(dir, { recursive: true }); if (fs.existsSync(dest) && !force) { try { const srcContent = fs.readFileSync(src, "utf8"); const destContent = fs.readFileSync(dest, "utf8"); if (srcContent === destContent) return { copied: 0, skipped: 1 }; } catch {} return { copied: 0, skipped: 1 }; } fs.copyFileSync(src, dest); return { copied: 1, skipped: 0 }; } function install() { const pkgDir = getPackageDir(); if (!pkgDir) { console.log("CI postinstall: Could not determine package directory. Skipping."); return; } const opencodeDir = path.join(pkgDir, "opencode"); if (!fs.existsSync(opencodeDir)) { console.log("CI postinstall: opencode/ directory not found. Skipping."); return; } if (!isGlobalInstall()) { console.log("CI postinstall: Not a global install. Skipping opencode integration."); console.log(" Run `npx ci-install` or `./scripts/install.sh` to install manually."); return; } let copied = 0; let skipped = 0; function copyGlob(srcDir, destDir, pattern) { if (!fs.existsSync(srcDir)) return; const entries = fs.readdirSync(srcDir).filter((f) => { if (pattern instanceof RegExp) return pattern.test(f); return f.startsWith(pattern); }); for (const entry of entries) { const result = copyFile(path.join(srcDir, entry), path.join(destDir, entry), false); copied += result.copied; skipped += result.skipped; } } fs.mkdirSync(path.join(OPENCODE_DIR, "agents"), { recursive: true }); fs.mkdirSync(path.join(OPENCODE_DIR, "command"), { recursive: true }); fs.mkdirSync(path.join(OPENCODE_DIR, "ci", "contexts"), { recursive: true }); fs.mkdirSync(path.join(OPENCODE_DIR, "ci", "references"), { recursive: true }); fs.mkdirSync(path.join(OPENCODE_DIR, "ci", "workflows"), { recursive: true }); copyGlob(path.join(opencodeDir, "agents"), path.join(OPENCODE_DIR, "agents"), /^ci-/); copyGlob(path.join(opencodeDir, "command"), path.join(OPENCODE_DIR, "command"), /^ci-/); copyGlob(path.join(opencodeDir, "ci", "contexts"), path.join(OPENCODE_DIR, "ci", "contexts"), /\.md$/); copyGlob(path.join(opencodeDir, "ci", "references"), path.join(OPENCODE_DIR, "ci", "references"), /\.md$/); copyGlob(path.join(opencodeDir, "ci", "workflows"), path.join(OPENCODE_DIR, "ci", "workflows"), /\.md$/); const versionFile = path.join(opencodeDir, "ci", "VERSION"); if (fs.existsSync(versionFile)) { const result = copyFile(versionFile, path.join(OPENCODE_DIR, "ci", "VERSION"), false); copied += result.copied; skipped += result.skipped; } const ciJsonPath = path.join(opencodeDir, "opencode.json"); const targetJsonPath = path.join(OPENCODE_DIR, "opencode.json"); if (fs.existsSync(ciJsonPath)) { if (!fs.existsSync(targetJsonPath)) { fs.copyFileSync(ciJsonPath, targetJsonPath); } else { try { const existing = JSON.parse(fs.readFileSync(targetJsonPath, "utf8")); const ciJson = JSON.parse(fs.readFileSync(ciJsonPath, "utf8")); existing.permission = existing.permission || {}; existing.permission.read = existing.permission.read || {}; existing.permission.external_directory = existing.permission.external_directory || {}; for (const [k, v] of Object.entries(ciJson.permission?.read || {})) { if (!existing.permission.read[k]) existing.permission.read[k] = v; } for (const [k, v] of Object.entries(ciJson.permission?.external_directory || {})) { if (!existing.permission.external_directory[k]) existing.permission.external_directory[k] = v; } fs.writeFileSync(targetJsonPath, JSON.stringify(existing, null, 2)); } catch {} } } console.log(`CI postinstall: ${copied} files installed, ${skipped} skipped.`); } try { install(); } catch (err) { console.log("CI postinstall: Non-fatal error:", err.message); }