mirror of
https://github.com/merlinhu1/codex-game-studio.git
synced 2026-08-25 07:54:34 +02:00
83 lines
4.5 KiB
TypeScript
83 lines
4.5 KiB
TypeScript
import { existsSync, mkdtempSync, readFileSync, readdirSync, writeFileSync, mkdirSync } from "node:fs";
|
|
import { execFileSync } from "node:child_process";
|
|
import { tmpdir } from "node:os";
|
|
import path from "node:path";
|
|
import { describe, test } from "node:test";
|
|
import { expect } from "expect";
|
|
import { initProject } from "../src/projects.js";
|
|
import { validateTemplateSurfaces } from "../src/validation.js";
|
|
|
|
const repoRoot = process.cwd();
|
|
|
|
function trackedFiles(pattern: string): string[] {
|
|
return execFileSync("git", ["ls-files", pattern], { cwd: repoRoot, encoding: "utf8" })
|
|
.split("\n")
|
|
.filter(Boolean)
|
|
.sort();
|
|
}
|
|
|
|
function filesUnder(relativeDir: string): string[] {
|
|
const full = path.join(repoRoot, relativeDir);
|
|
if (!existsSync(full)) return [];
|
|
return readdirSync(full, { recursive: true, withFileTypes: true })
|
|
.filter((entry) => entry.isFile())
|
|
.map((entry) => path.join(entry.parentPath, entry.name).slice(repoRoot.length + 1).split(path.sep).join("/"))
|
|
.sort();
|
|
}
|
|
|
|
describe("template repository Codex surfaces", () => {
|
|
test("clone-visible game agents, workflows, and skills are tracked before init", () => {
|
|
const agents = trackedFiles(".codex/agents/*.toml");
|
|
const workflows = trackedFiles(".codex/workflows/*.md");
|
|
const skills = trackedFiles(".agents/skills/*/SKILL.md");
|
|
|
|
expect(agents).toEqual(expect.arrayContaining([".codex/agents/producer.toml", ".codex/agents/gameplay-programmer.toml", ".codex/agents/godot-specialist.toml"]));
|
|
expect(workflows).toEqual(expect.arrayContaining([".codex/workflows/vertical-slice.md", ".codex/workflows/bugfix.md", ".codex/workflows/qa-plan.md"]));
|
|
expect(skills).toEqual(expect.arrayContaining([".agents/skills/cgs-start/SKILL.md", ".agents/skills/cgs-bugfix/SKILL.md", ".agents/skills/cgs-vertical-slice/SKILL.md"]));
|
|
|
|
for (const file of [...agents, ...workflows, ...skills]) {
|
|
const body = readFileSync(path.join(repoRoot, file), "utf8");
|
|
expect(body.trim().length).toBeGreaterThan(80);
|
|
expect(body).not.toContain("@generated");
|
|
expect(body).not.toContain("generatedSurface");
|
|
}
|
|
});
|
|
|
|
test("game-facing root surface folders do not contain Truthmark maintenance surfaces", () => {
|
|
expect(filesUnder(".codex/agents").some((file) => /truth/i.test(file))).toBe(false);
|
|
expect(filesUnder(".agents/skills").some((file) => /truthmark/i.test(file))).toBe(false);
|
|
});
|
|
|
|
test("init preserves tracked template instruction bodies", () => {
|
|
const root = mkdtempSync(path.join(tmpdir(), "ogs-template-preserve-"));
|
|
const agentPath = path.join(root, ".codex", "agents", "producer.toml");
|
|
const workflowPath = path.join(root, ".codex", "workflows", "bugfix.md");
|
|
const skillPath = path.join(root, ".agents", "skills", "cgs-start", "SKILL.md");
|
|
const agentsPath = path.join(root, "AGENTS.md");
|
|
mkdirSync(path.dirname(agentPath), { recursive: true });
|
|
mkdirSync(path.dirname(workflowPath), { recursive: true });
|
|
mkdirSync(path.dirname(skillPath), { recursive: true });
|
|
writeFileSync(agentPath, 'name = "producer"\ndescription = "Sentinel producer"\ndeveloper_instructions = """\nDo not overwrite this tracked template agent.\n"""\n');
|
|
writeFileSync(workflowPath, "# Bugfix Workflow\n\n## Purpose\n\nDo not overwrite this tracked template workflow.\n");
|
|
writeFileSync(skillPath, "---\nname: cgs-start\ndescription: Sentinel start skill\n---\n\n# Start\n\nDo not overwrite this tracked template skill.\n");
|
|
writeFileSync(agentsPath, "# Sentinel Game Studio\n\n## Project Goal\n\nDo not overwrite this tracked root instruction file.\n");
|
|
|
|
const before = new Map([
|
|
[agentPath, readFileSync(agentPath, "utf8")],
|
|
[workflowPath, readFileSync(workflowPath, "utf8")],
|
|
[skillPath, readFileSync(skillPath, "utf8")],
|
|
[agentsPath, readFileSync(agentsPath, "utf8")]
|
|
]);
|
|
|
|
initProject({ name: "Template Preserve", engine: "godot", mode: "prototype", nonInteractive: true }, root);
|
|
|
|
for (const [file, body] of before) expect(readFileSync(file, "utf8")).toBe(body);
|
|
});
|
|
|
|
test("template-surface validation runs before project state exists", () => {
|
|
const checks = validateTemplateSurfaces(repoRoot);
|
|
expect(checks.filter((check) => check.status === "fail")).toEqual([]);
|
|
expect(checks).toEqual(expect.arrayContaining([expect.objectContaining({ id: "template.agents.tracked", status: "pass" }), expect.objectContaining({ id: "template.workflows.tracked", status: "pass" }), expect.objectContaining({ id: "template.skills.tracked", status: "pass" })]));
|
|
});
|
|
});
|