e31afe3b59
- README.md: title, project name, CLI commands, .ci/ → .ciagent/, ci-files → ciagent-files, CI Modification → CIAgent Modification - AGENTS.md: title, project name, architecture tree, agent count (18→19), test count (25→31 suites, 218→370 tests), version (0.4.0→0.6.0), ci-files → ciagent-files, CIConfig → CIAgentConfig, CiMetadata → CIAgentMetadata, .ci/ → .ciagent/ - templates/DECISIONS.md: .ci/audit/ → .ciagent/audit/, ci audit → ciagent audit - scripts/postinstall.js: CI postinstall → CIAgent postinstall - scripts/install.sh: CI → CIAgent, ci-init → ciagent-init, INSTALL COMPLETE banner - opencode/ci/workflows/*.md (11 files): .ci/ → .ciagent/, CI → CIAgent project name, ci-command → ciagent-command usage lines - opencode/ci/references/*.md (5 files): .ci/ → .ciagent/, CI → CIAgent project name, ci-files → ciagent-files references - opencode/ci/contexts/*.md (3 files): .ci/ → .ciagent/, CI → CIAgent project name - opencode/agents/ci-*.md (18 files): .ci/ → .ciagent/, CI → CIAgent project name - opencode/command/ci-*.md (11 files): CI → CIAgent project name Preserved: ---ci---/---/ci--- markers, opencode/ci/ dir paths, ci-*.md filenames, ci listProjects()/ci setActiveProject() API names, repo URLs ---ci--- phase: 1 milestone: v0.6 plan: 01-01 task: 01-01-01 status: execute ---/ci---
142 lines
5.0 KiB
JavaScript
142 lines
5.0 KiB
JavaScript
#!/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, templateVars) {
|
|
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 = applyTemplate(fs.readFileSync(src, "utf8"), templateVars);
|
|
const destContent = fs.readFileSync(dest, "utf8");
|
|
if (srcContent === destContent) return { copied: 0, skipped: 1 };
|
|
} catch {}
|
|
return { copied: 0, skipped: 1 };
|
|
}
|
|
|
|
const content = applyTemplate(fs.readFileSync(src, "utf8"), templateVars);
|
|
fs.writeFileSync(dest, content, "utf8");
|
|
return { copied: 1, skipped: 0 };
|
|
}
|
|
|
|
function applyTemplate(content, vars) {
|
|
if (!vars) return content;
|
|
let result = content;
|
|
for (const [key, value] of Object.entries(vars)) {
|
|
result = result.replaceAll(key, value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function install() {
|
|
const pkgDir = getPackageDir();
|
|
if (!pkgDir) {
|
|
console.log("CIAgent postinstall: Could not determine package directory. Skipping.");
|
|
return;
|
|
}
|
|
|
|
const opencodeDir = path.join(pkgDir, "opencode");
|
|
if (!fs.existsSync(opencodeDir)) {
|
|
console.log("CIAgent postinstall: opencode/ directory not found. Skipping.");
|
|
return;
|
|
}
|
|
|
|
if (!isGlobalInstall()) {
|
|
console.log("CIAgent postinstall: Not a global install. Skipping opencode integration.");
|
|
console.log(" Run `npx ciagent-install` or `./scripts/install.sh` to install manually.");
|
|
return;
|
|
}
|
|
|
|
const templateVars = {
|
|
__OPENCODE_DIR__: OPENCODE_DIR,
|
|
};
|
|
|
|
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, templateVars);
|
|
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, templateVars);
|
|
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)) {
|
|
const content = applyTemplate(fs.readFileSync(ciJsonPath, "utf8"), templateVars);
|
|
fs.writeFileSync(targetJsonPath, content, "utf8");
|
|
} else {
|
|
try {
|
|
const existing = JSON.parse(fs.readFileSync(targetJsonPath, "utf8"));
|
|
const ciJson = JSON.parse(applyTemplate(fs.readFileSync(ciJsonPath, "utf8"), templateVars));
|
|
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(`CIAgent postinstall: ${copied} files installed, ${skipped} skipped.`);
|
|
}
|
|
|
|
try {
|
|
install();
|
|
} catch (err) {
|
|
console.log("CIAgent postinstall: Non-fatal error:", err.message);
|
|
} |