import { mkdtemp, mkdir, readdir, rm, access, writeFile } from "node:fs/promises"; import { constants as fsConstants } from "node:fs"; import { join, resolve } from "node:path"; import { spawnSync } from "node:child_process"; import { tmpdir } from "node:os"; import test from "node:test"; import assert from "node:assert/strict"; const cliPath = resolve( process.cwd(), "bin/antigravity-superpowers.js", ); async function pathExists(path) { try { await access(path, fsConstants.F_OK); return true; } catch { return false; } } function runCli(args, cwd) { return spawnSync(process.execPath, [cliPath, ...args], { cwd, encoding: "utf8", }); } async function createTempProject(prefix) { const baseTmp = tmpdir(); await mkdir(baseTmp, { recursive: true }); return mkdtemp(join(baseTmp, prefix)); } test("init creates .agent in a fresh project", async () => { const projectDir = await createTempProject("agsp-fresh-"); try { const result = runCli(["init"], projectDir); assert.equal(result.status, 0); const hasAgent = await pathExists(join(projectDir, ".agent", "AGENTS.md")); assert.equal(hasAgent, true); } finally { await rm(projectDir, { recursive: true, force: true }); } }); test("init fails when .agent exists without --force", async () => { const projectDir = await createTempProject("agsp-existing-"); try { await mkdir(join(projectDir, ".agent"), { recursive: true }); const result = runCli(["init"], projectDir); assert.equal(result.status, 1); assert.match(result.stderr, /already exists/i); assert.match(result.stderr, /--force/i); } finally { await rm(projectDir, { recursive: true, force: true }); } }); test("init replaces .agent with --force", async () => { const projectDir = await createTempProject("agsp-force-"); try { await mkdir(join(projectDir, ".agent"), { recursive: true }); const result = runCli(["init", "--force"], projectDir); assert.equal(result.status, 0); const hasTemplate = await pathExists(join(projectDir, ".agent", "AGENTS.md")); assert.equal(hasTemplate, true); } finally { await rm(projectDir, { recursive: true, force: true }); } }); test("init with -f short flag works", async () => { const projectDir = await createTempProject("agsp-short-f-"); try { await mkdir(join(projectDir, ".agent"), { recursive: true }); const result = runCli(["init", "-f"], projectDir); assert.equal(result.status, 0); assert.match(result.stdout, /Initialized/); } finally { await rm(projectDir, { recursive: true, force: true }); } }); test("init with target directory argument", async () => { const parentDir = await createTempProject("agsp-parent-"); const targetDir = join(parentDir, "myproject"); await mkdir(targetDir); try { const result = runCli(["init", targetDir], parentDir); assert.equal(result.status, 0); const hasAgent = await pathExists(join(targetDir, ".agent", "AGENTS.md")); assert.equal(hasAgent, true); } finally { await rm(parentDir, { recursive: true, force: true }); } }); test("init fails when target directory does not exist", async () => { const result = runCli(["init", "/tmp/nonexistent-dir-agsp-12345"]); assert.equal(result.status, 1); assert.match(result.stderr, /does not exist/i); }); test("init with unknown option fails", async () => { const projectDir = await createTempProject("agsp-unknown-"); try { const result = runCli(["init", "--bogus"], projectDir); assert.equal(result.status, 1); assert.match(result.stderr, /Unknown option/); } finally { await rm(projectDir, { recursive: true, force: true }); } }); test("init --dry-run previews files without copying", async () => { const projectDir = await createTempProject("agsp-dryrun-"); try { const result = runCli(["init", "--dry-run"], projectDir); assert.equal(result.status, 0); assert.match(result.stdout, /Dry run/); assert.match(result.stdout, /AGENTS\.md/); const hasAgent = await pathExists(join(projectDir, ".agent")); assert.equal(hasAgent, false, ".agent should not be created during dry run"); } finally { await rm(projectDir, { recursive: true, force: true }); } }); test("init --force --backup creates backup before replacing", async () => { const projectDir = await createTempProject("agsp-backup-"); try { // Create initial .agent with a custom file await mkdir(join(projectDir, ".agent"), { recursive: true }); await writeFile(join(projectDir, ".agent", "custom.txt"), "my custom config"); const result = runCli(["init", "--force", "--backup"], projectDir); assert.equal(result.status, 0); assert.match(result.stdout, /Backed up/); // New .agent should exist const hasAgent = await pathExists(join(projectDir, ".agent", "AGENTS.md")); assert.equal(hasAgent, true); // Backup dir should exist const entries = await readdir(projectDir); const backupDirs = entries.filter((e) => e.startsWith(".agent-backup-")); assert.equal(backupDirs.length, 1, "Should have exactly one backup directory"); // Backup should contain the custom file const hasCustom = await pathExists(join(projectDir, backupDirs[0], "custom.txt")); assert.equal(hasCustom, true, "Backup should preserve custom files"); } finally { await rm(projectDir, { recursive: true, force: true }); } });