Skip to content

Commit 7b619b5

Browse files
committed
feat(postinstall): add content validation for agent files
Signed-off-by: leocavalcante <leo@cavalcante.dev>
1 parent b542a65 commit 7b619b5

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

postinstall.mjs

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* This allows OpenCode to discover and use the agents.
88
*/
99

10-
import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from "node:fs"
10+
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync } from "node:fs"
1111
import { join } from "node:path"
1212

1313
import {
@@ -20,6 +20,55 @@ import {
2020
const packageRoot = getPackageRoot(import.meta.url)
2121
const AGENTS_SOURCE_DIR = getAgentsSourceDir(packageRoot)
2222

23+
/** Minimum character count for valid agent files */
24+
const MIN_CONTENT_LENGTH = 100
25+
26+
/** Keywords that should appear in valid agent files (case-insensitive) */
27+
const REQUIRED_KEYWORDS = ["agent", "task"]
28+
29+
/**
30+
* Validates that an agent file has valid content structure.
31+
*
32+
* Checks that the file:
33+
* 1. Starts with a markdown header (# )
34+
* 2. Contains at least MIN_CONTENT_LENGTH characters
35+
* 3. Contains at least one of the expected keywords
36+
*
37+
* @param {string} filePath - Path to the agent file to validate
38+
* @returns {{ valid: boolean, error?: string }} Validation result with optional error message
39+
*/
40+
function validateAgentContent(filePath) {
41+
const content = readFileSync(filePath, "utf-8")
42+
43+
// Check minimum length
44+
if (content.length < MIN_CONTENT_LENGTH) {
45+
return {
46+
valid: false,
47+
error: `File too short: ${content.length} characters (minimum ${MIN_CONTENT_LENGTH})`,
48+
}
49+
}
50+
51+
// Check for markdown header at start
52+
if (!content.startsWith("# ")) {
53+
return {
54+
valid: false,
55+
error: "File does not start with a markdown header (# )",
56+
}
57+
}
58+
59+
// Check for required keywords (case-insensitive)
60+
const lowerContent = content.toLowerCase()
61+
const hasKeyword = REQUIRED_KEYWORDS.some((keyword) => lowerContent.includes(keyword))
62+
if (!hasKeyword) {
63+
return {
64+
valid: false,
65+
error: `File missing required keywords: ${REQUIRED_KEYWORDS.join(", ")}`,
66+
}
67+
}
68+
69+
return { valid: true }
70+
}
71+
2372
/**
2473
* Main entry point for the postinstall script.
2574
*
@@ -82,6 +131,12 @@ function main() {
82131
)
83132
}
84133

134+
// Validate content structure
135+
const validation = validateAgentContent(targetPath)
136+
if (!validation.valid) {
137+
throw new Error(`Invalid agent file content: ${validation.error}`)
138+
}
139+
85140
successes.push(file)
86141
console.log(` Installed: ${file}`)
87142
} catch (err) {

0 commit comments

Comments
 (0)