mirror of
https://github.com/EveryInc/compound-engineering-plugin.git
synced 2026-06-19 15:41:46 +02:00
286 lines
8.2 KiB
TypeScript
286 lines
8.2 KiB
TypeScript
import { describe, expect, test } from "bun:test"
|
|
import { spawnSync } from "node:child_process"
|
|
import { mkdtempSync, writeFileSync, readFileSync } from "node:fs"
|
|
import { tmpdir } from "node:os"
|
|
import path from "node:path"
|
|
|
|
const SKILL_DIRS = [
|
|
path.join(
|
|
__dirname,
|
|
"../plugins/compound-engineering/skills/ce-compound",
|
|
),
|
|
path.join(
|
|
__dirname,
|
|
"../plugins/compound-engineering/skills/ce-compound-refresh",
|
|
),
|
|
] as const
|
|
|
|
function scriptPath(skillDir: string): string {
|
|
return path.join(skillDir, "scripts/validate-frontmatter.py")
|
|
}
|
|
|
|
function runValidator(
|
|
skillDir: string,
|
|
docPath: string,
|
|
): { code: number; stdout: string; stderr: string } {
|
|
const result = spawnSync("python3", [scriptPath(skillDir), docPath], {
|
|
encoding: "utf8",
|
|
})
|
|
return {
|
|
code: result.status ?? -1,
|
|
stdout: result.stdout ?? "",
|
|
stderr: result.stderr ?? "",
|
|
}
|
|
}
|
|
|
|
function writeTempDoc(content: string): string {
|
|
const dir = mkdtempSync(path.join(tmpdir(), "fm-validator-"))
|
|
const filePath = path.join(dir, "doc.md")
|
|
writeFileSync(filePath, content, "utf8")
|
|
return filePath
|
|
}
|
|
|
|
const VALID_DOC = `---
|
|
title: "Sample valid doc"
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
related_pr: "PR #685 (with extra context after the hash)"
|
|
tags:
|
|
- validation
|
|
- frontmatter
|
|
---
|
|
|
|
Body.
|
|
`
|
|
|
|
describe("validate-frontmatter script", () => {
|
|
// Run every test against both skill copies of the script — they must
|
|
// behave identically since AGENTS.md requires duplication, not sharing.
|
|
for (const skillDir of SKILL_DIRS) {
|
|
const skillName = path.basename(skillDir)
|
|
|
|
describe(`in ${skillName}`, () => {
|
|
test("accepts a valid frontmatter doc", () => {
|
|
const docPath = writeTempDoc(VALID_DOC)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(0)
|
|
expect(result.stdout).toContain("OK:")
|
|
expect(result.stderr).toBe("")
|
|
})
|
|
|
|
test("rejects unquoted ' #' (the Codex bug)", () => {
|
|
const docPath = writeTempDoc(`---
|
|
title: "Sample"
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
related_pr: PR #685 (silently truncated)
|
|
---
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain("FAIL:")
|
|
expect(result.stderr).toContain("'related_pr' value contains ' #'")
|
|
expect(result.stderr).toContain("quote it")
|
|
})
|
|
|
|
test("rejects unquoted ': ' (mapping confusion)", () => {
|
|
const docPath = writeTempDoc(`---
|
|
title: fix: Close gaps from PR #568 feedback
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
---
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain("FAIL:")
|
|
expect(result.stderr).toMatch(/'title' value contains ': '/)
|
|
})
|
|
|
|
test("accepts unquoted scalar starting with '-' (valid plain scalar; '-' is a list marker only when followed by whitespace)", () => {
|
|
// YAML 1.2: bare `-foo` is a valid plain scalar. Only `- foo` (with
|
|
// whitespace after `-`) acts as a list-entry marker. The validator
|
|
// should not flag `-foo`.
|
|
const docPath = writeTempDoc(`---
|
|
title: -starts-with-dash
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
---
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(0)
|
|
})
|
|
|
|
test("accepts unquoted scalar starting with '?' (valid plain scalar; '?' is a complex-key marker only when followed by whitespace)", () => {
|
|
// YAML 1.2: bare `?foo` is a valid plain scalar. Only `? foo` (with
|
|
// whitespace after `?`) acts as a complex-mapping-key marker.
|
|
const docPath = writeTempDoc(`---
|
|
title: ?question-mark-prefix
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
---
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(0)
|
|
})
|
|
|
|
test("rejects file without frontmatter delimiter", () => {
|
|
const docPath = writeTempDoc("# Just a markdown doc\n\nNo frontmatter.\n")
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain("does not start with '---'")
|
|
})
|
|
|
|
test("rejects unterminated frontmatter", () => {
|
|
const docPath = writeTempDoc(`---
|
|
title: "Sample"
|
|
date: 2026-04-25
|
|
|
|
Body without closing delimiter.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain("not closed")
|
|
})
|
|
|
|
test("rejects '----' as closing delimiter (must match line exactly, not substring)", () => {
|
|
// text.find("\\n---", 4) would falsely accept '----'; line-anchored
|
|
// matching rejects it. Strict frontmatter parsers downstream require
|
|
// an exact '---' line, so this is a real bug to catch.
|
|
const docPath = writeTempDoc(`---
|
|
title: "Sample"
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
----
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain("not closed")
|
|
})
|
|
|
|
test("rejects '---extra' as closing delimiter", () => {
|
|
const docPath = writeTempDoc(`---
|
|
title: "Sample"
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
---extra
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(1)
|
|
expect(result.stderr).toContain("not closed")
|
|
})
|
|
|
|
test("accepts '---' delimiter with trailing whitespace", () => {
|
|
// Permissive on whitespace (rstrip the line) but strict on content.
|
|
const docPath = writeTempDoc(
|
|
"--- \n" +
|
|
'title: "Sample"\n' +
|
|
"date: 2026-04-25\n" +
|
|
"module: ce-compound\n" +
|
|
"problem_type: best_practice\n" +
|
|
"component: tooling\n" +
|
|
"severity: low\n" +
|
|
"--- \n" +
|
|
"\n" +
|
|
"Body.\n",
|
|
)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(0)
|
|
})
|
|
|
|
test("exits 2 (usage error) on missing file", () => {
|
|
const result = runValidator(skillDir, "/tmp/this-file-does-not-exist-fm.md")
|
|
expect(result.code).toBe(2)
|
|
expect(result.stderr).toContain("file not found")
|
|
})
|
|
|
|
test("exits 2 (usage error) on missing argument", () => {
|
|
const result = spawnSync("python3", [scriptPath(skillDir)], {
|
|
encoding: "utf8",
|
|
})
|
|
expect(result.status).toBe(2)
|
|
expect(result.stderr).toContain("usage")
|
|
})
|
|
|
|
test("ignores nested-mapping ': ' (only top-level scalars are checked)", () => {
|
|
// `: ` inside an array item or quoted value is fine — only top-level
|
|
// unquoted scalar values trigger the check.
|
|
const docPath = writeTempDoc(`---
|
|
title: "Sample"
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
tags:
|
|
- "fine: with colon-space when quoted"
|
|
---
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(0)
|
|
})
|
|
|
|
test("permits valid frontmatter with all the historically-tricky punctuation, when quoted", () => {
|
|
const docPath = writeTempDoc(`---
|
|
title: "fix: Close gaps from PR #568 feedback"
|
|
date: 2026-04-25
|
|
module: ce-compound
|
|
problem_type: best_practice
|
|
component: tooling
|
|
severity: low
|
|
related_pr: "PR #685 (with extra context)"
|
|
related_issue: "EveryInc/repo#42"
|
|
summary: "- a leading dash, : a colon-space, and # symbols all fine here"
|
|
---
|
|
|
|
Body.
|
|
`)
|
|
const result = runValidator(skillDir, docPath)
|
|
expect(result.code).toBe(0)
|
|
expect(result.stderr).toBe("")
|
|
})
|
|
})
|
|
}
|
|
|
|
test("script content is identical across skill copies (per AGENTS.md duplication rule)", () => {
|
|
const [a, b] = SKILL_DIRS
|
|
const aContent = readFileSync(scriptPath(a), "utf8")
|
|
const bContent = readFileSync(scriptPath(b), "utf8")
|
|
expect(aContent).toBe(bContent)
|
|
})
|
|
})
|