mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-12 22:09:48 +08:00
23fac03691
Move the codex-imagegen wrapper out of scripts/ into its own workspace package alongside baoyu-md, baoyu-chrome-cdp, and baoyu-fetch. Drop the bash shim — src/main.ts now carries a `#\!/usr/bin/env bun` shebang and serves as the sole entrypoint. Add scripts/sync-codex-imagegen.sh so skills/baoyu-image-gen/scripts/codex-imagegen/ can be regenerated from packages/baoyu-codex-imagegen/src/ for skill self-containment. Update CLAUDE.md, docs/codex-imagegen-backend.md, and the CI workflow paths accordingly.
99 lines
3.2 KiB
TypeScript
99 lines
3.2 KiB
TypeScript
import { test, expect } from "bun:test";
|
|
import { mkdtemp, writeFile, rm, mkdir } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { verifyOutput, verifyImageGenWasInvoked, findCpToTarget } from "./validator.ts";
|
|
import { GenError } from "./types.ts";
|
|
|
|
const PNG_HEADER = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
|
|
|
|
test("verifyOutput passes for valid PNG", async () => {
|
|
const dir = await mkdtemp(path.join(tmpdir(), "cig-val-"));
|
|
try {
|
|
const p = path.join(dir, "good.png");
|
|
await writeFile(p, Buffer.concat([PNG_HEADER, Buffer.alloc(5000)]));
|
|
const r = await verifyOutput(p);
|
|
expect(r.bytes).toBeGreaterThan(1000);
|
|
} finally {
|
|
await rm(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("verifyOutput rejects missing file", async () => {
|
|
await expect(verifyOutput("/no/such/file.png")).rejects.toBeInstanceOf(GenError);
|
|
});
|
|
|
|
test("verifyOutput rejects tiny file", async () => {
|
|
const dir = await mkdtemp(path.join(tmpdir(), "cig-val-"));
|
|
try {
|
|
const p = path.join(dir, "tiny.png");
|
|
await writeFile(p, "tiny");
|
|
await expect(verifyOutput(p)).rejects.toThrow(/too small/);
|
|
} finally {
|
|
await rm(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("verifyOutput rejects non-PNG magic", async () => {
|
|
const dir = await mkdtemp(path.join(tmpdir(), "cig-val-"));
|
|
try {
|
|
const p = path.join(dir, "fake.png");
|
|
await writeFile(p, Buffer.concat([Buffer.from("GIF89a"), Buffer.alloc(5000)]));
|
|
await expect(verifyOutput(p)).rejects.toThrow(/not a valid PNG/);
|
|
} finally {
|
|
await rm(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("verifyImageGenWasInvoked false when no thread directory", async () => {
|
|
const orig = process.env.CODEX_HOME;
|
|
const tempHome = await mkdtemp(path.join(tmpdir(), "cig-home-"));
|
|
process.env.CODEX_HOME = tempHome;
|
|
try {
|
|
const r = await verifyImageGenWasInvoked("no-such-thread");
|
|
expect(r.ok).toBe(false);
|
|
} finally {
|
|
process.env.CODEX_HOME = orig;
|
|
await rm(tempHome, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("verifyImageGenWasInvoked true when PNG exists in thread dir", async () => {
|
|
const orig = process.env.CODEX_HOME;
|
|
const tempHome = await mkdtemp(path.join(tmpdir(), "cig-home-"));
|
|
process.env.CODEX_HOME = tempHome;
|
|
try {
|
|
const threadDir = path.join(tempHome, "generated_images", "thread-xyz");
|
|
await mkdir(threadDir, { recursive: true });
|
|
await writeFile(path.join(threadDir, "ig_abc.png"), Buffer.alloc(100));
|
|
const r = await verifyImageGenWasInvoked("thread-xyz");
|
|
expect(r.ok).toBe(true);
|
|
} finally {
|
|
process.env.CODEX_HOME = orig;
|
|
await rm(tempHome, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("findCpToTarget detects cp from generated_images", () => {
|
|
expect(
|
|
findCpToTarget(
|
|
[
|
|
{
|
|
id: "1",
|
|
tool: "shell",
|
|
status: "completed",
|
|
command: "cp ~/.codex/generated_images/thread/ig_x.png /tmp/out.png",
|
|
},
|
|
],
|
|
"/tmp/out.png",
|
|
),
|
|
).toBe(true);
|
|
|
|
expect(
|
|
findCpToTarget(
|
|
[{ id: "1", tool: "shell", status: "completed", command: "ls /tmp" }],
|
|
"/tmp/out.png",
|
|
),
|
|
).toBe(false);
|
|
});
|