Skip to content

Commit 26131ad

Browse files
committed
test(agents): add YAML frontmatter validation for agent files
Signed-off-by: leocavalcante <leo@cavalcante.dev>
1 parent beb5e3a commit 26131ad

1 file changed

Lines changed: 64 additions & 1 deletion

File tree

tests/agents.test.ts

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { afterEach, beforeEach, describe, expect, it } from "bun:test"
2-
import { existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from "node:fs"
2+
import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"
33
import { tmpdir } from "node:os"
44
import { join } from "node:path"
55

@@ -57,3 +57,66 @@ describe("agent files existence", () => {
5757
expect(files).toHaveLength(3)
5858
})
5959
})
60+
61+
describe("agent files YAML frontmatter", () => {
62+
const agentsDir = join(import.meta.dir, "..", "agents")
63+
const agentFiles = ["opencoder.md", "opencoder-planner.md", "opencoder-builder.md"]
64+
65+
/**
66+
* Parses YAML frontmatter from a markdown file.
67+
* Returns the frontmatter as an object or null if not found.
68+
*/
69+
function parseFrontmatter(content: string): Record<string, string> | null {
70+
const match = content.match(/^---\n([\s\S]*?)\n---/)
71+
if (!match?.[1]) return null
72+
73+
const frontmatter: Record<string, string> = {}
74+
const lines = match[1].split("\n")
75+
for (const line of lines) {
76+
const colonIndex = line.indexOf(":")
77+
if (colonIndex > 0) {
78+
const key = line.slice(0, colonIndex).trim()
79+
const value = line
80+
.slice(colonIndex + 1)
81+
.trim()
82+
.replace(/^["']|["']$/g, "")
83+
frontmatter[key] = value
84+
}
85+
}
86+
return frontmatter
87+
}
88+
89+
for (const agentFile of agentFiles) {
90+
describe(agentFile, () => {
91+
it("should have valid YAML frontmatter", () => {
92+
const content = readFileSync(join(agentsDir, agentFile), "utf-8")
93+
const frontmatter = parseFrontmatter(content)
94+
expect(frontmatter).not.toBeNull()
95+
})
96+
97+
it("should have a version field", () => {
98+
const content = readFileSync(join(agentsDir, agentFile), "utf-8")
99+
const frontmatter = parseFrontmatter(content)
100+
expect(frontmatter).not.toBeNull()
101+
expect(frontmatter?.version).toBeDefined()
102+
expect(frontmatter?.version).toMatch(/^\d+\.\d+\.\d+$/)
103+
})
104+
105+
it("should have a requires field", () => {
106+
const content = readFileSync(join(agentsDir, agentFile), "utf-8")
107+
const frontmatter = parseFrontmatter(content)
108+
expect(frontmatter).not.toBeNull()
109+
expect(frontmatter?.requires).toBeDefined()
110+
expect(frontmatter?.requires).toMatch(/^>=?\d+\.\d+\.\d+$/)
111+
})
112+
113+
it("should have an updated field with valid date", () => {
114+
const content = readFileSync(join(agentsDir, agentFile), "utf-8")
115+
const frontmatter = parseFrontmatter(content)
116+
expect(frontmatter).not.toBeNull()
117+
expect(frontmatter?.updated).toBeDefined()
118+
expect(frontmatter?.updated).toMatch(/^\d{4}-\d{2}-\d{2}$/)
119+
})
120+
})
121+
}
122+
})

0 commit comments

Comments
 (0)