fix(agents): preserve user-owned definitions during Pi conversion

This commit is contained in:
haelyra
2026-10-10 17:50:39 -04:00
parent 3b24eca2e6
commit 9966fef84a
2 changed files with 42 additions and 4 deletions
+24 -4
View File
@@ -135,13 +135,33 @@ function main() {
if (args.out) {
const dir = path.resolve(args.out);
if (!args.dryRun) fs.mkdirSync(dir, { recursive: true });
if (!args.dryRun) {
if (fs.existsSync(dir) && fs.lstatSync(dir).isSymbolicLink()) {
throw new Error('output directory must not be a symlink');
}
// Check the whole batch before writing. Existing operator-owned agents
// cannot be replaced simply because they share an ECC dispatch name.
for (const r of results) {
const target = path.join(dir, `${r.id}.md`);
let stat;
try { stat = fs.lstatSync(target); } catch (error) {
if (error.code !== 'ENOENT') throw error;
}
if (stat && (!stat.isFile() || stat.isSymbolicLink()
|| fs.readFileSync(target, 'utf8') !== r.markdown)) {
throw new Error(`refusing to overwrite existing agent: ${target}`);
}
}
fs.mkdirSync(dir, { recursive: true });
}
for (const r of results) {
const target = path.join(dir, `${r.id}.md`);
if (args.dryRun) {
progress(`[dry-run] would write ${target}`);
} else {
fs.writeFileSync(target, r.markdown);
} else if (!fs.existsSync(target)) {
// Exclusive creation prevents a file/symlink appearing after preflight
// from being overwritten. Identical existing output stays untouched.
fs.writeFileSync(target, r.markdown, { flag: 'wx' });
progress(`wrote ${target}`);
}
}
@@ -172,4 +192,4 @@ function main() {
}
}
main();
try { main(); } catch (error) { console.error(`error: ${error.message}`); process.exitCode = 1; }
+18
View File
@@ -65,6 +65,24 @@ function main() {
assert.match(planner, /prompt_mode: replace/);
}],
["--out preserves user-owned agents before writing any output", () => {
const dir = tmpdir();
const target = path.join(dir, "planner.md");
fs.writeFileSync(target, "USER_OWNED_AGENT\n");
assert.throws(() => runCli(["--out", dir]), /refusing to overwrite existing agent/);
assert.strictEqual(fs.readFileSync(target, "utf8"), "USER_OWNED_AGENT\n");
assert.deepStrictEqual(fs.readdirSync(dir), ["planner.md"]);
}],
["--out repeats identical output without changing bytes", () => {
const dir = tmpdir();
runCli(["--out", dir]);
const target = path.join(dir, "planner.md");
const before = fs.readFileSync(target, "utf8");
runCli(["--out", dir]);
assert.strictEqual(fs.readFileSync(target, "utf8"), before);
}],
["--out --dry-run writes nothing", () => {
const dir = tmpdir()
const out = runCli(["--from", "claude", "--to", "pi", "--out", dir, "--dry-run"])