Project Files
dist / validation / rules.js
const ALLOWED_AGENTS = new Set([
"build",
"plan",
"general",
"explore",
"oracle",
]);
export function getAllRules() {
return [
ruleHasFrontmatter(),
ruleValidYaml(),
ruleHasDescription(),
ruleDescriptionLength(),
ruleValidAgent(),
ruleValidModelFormat(),
ruleBodyNotEmpty(),
ruleArgsUsage(),
ruleFileRefFormat(),
ruleMaxLines(),
ruleSubtaskBoolean(),
ruleHasAgentField(),
];
}
function result(ruleId, severity, message, fix, line) {
return { ruleId, severity, message, fix, line };
}
// ---- Rule definitions ----
function ruleHasFrontmatter() {
return {
id: "has-frontmatter",
severity: "error",
description: "Command file must have YAML frontmatter",
check: (cmd) => {
if (cmd.frontmatter === null && !cmd.parseError?.includes("YAML")) {
return result("has-frontmatter", "error", "File must have a YAML frontmatter block (---)");
}
return null;
},
};
}
function ruleValidYaml() {
return {
id: "valid-yaml",
severity: "error",
description: "Frontmatter must be valid YAML",
check: (cmd) => {
if (cmd.parseError &&
(cmd.parseError.includes("YAML") ||
cmd.parseError.includes("frontmatter"))) {
return result("valid-yaml", "error", cmd.parseError);
}
return null;
},
};
}
function ruleHasDescription() {
return {
id: "has-description",
severity: "error",
description: 'Frontmatter must contain a "description" field',
check: (cmd) => {
if (cmd.frontmatter && !("description" in cmd.frontmatter)) {
return result("has-description", "error", 'Missing required field: "description" in frontmatter', "Add: description: Short description of what this command does");
}
if (cmd.frontmatter &&
cmd.frontmatter.description !== undefined &&
cmd.frontmatter.description === "") {
return result("has-description", "error", '"description" field is present but empty', "Add a non-empty description");
}
return null;
},
};
}
function ruleDescriptionLength() {
return {
id: "description-length",
severity: "warning",
description: "Description should be at least 10 characters",
check: (cmd) => {
const desc = cmd.frontmatter?.description;
if (desc && typeof desc === "string" && desc.trim().length < 10) {
return result("description-length", "warning", `Description is too short (${desc.trim().length} chars). Should be at least 10 characters.`, `Extend the description to be more descriptive (currently: "${desc.trim()}")`);
}
return null;
},
};
}
function ruleValidAgent() {
return {
id: "valid-agent",
severity: "warning",
description: "Agent field must be a known agent type",
check: (cmd) => {
const agent = cmd.frontmatter?.agent;
if (agent !== undefined && agent !== null) {
const agentStr = String(agent);
if (!ALLOWED_AGENTS.has(agentStr)) {
return result("valid-agent", "warning", `Unknown agent type: "${agentStr}". Allowed: ${[...ALLOWED_AGENTS].join(", ")}`, `Change to one of: ${[...ALLOWED_AGENTS].join(", ")}`);
}
}
return null;
},
};
}
function ruleValidModelFormat() {
return {
id: "valid-model-format",
severity: "warning",
description: "Model field should use provider/model format",
check: (cmd) => {
const model = cmd.frontmatter?.model;
if (model !== undefined && model !== null && model !== "") {
const modelStr = String(model);
if (!modelStr.includes("/")) {
return result("valid-model-format", "warning", `Model "${modelStr}" doesn't follow the "provider/model" format`, "Use format like: opencode-go/kimi-k2.6 or anthropic/claude-sonnet-4");
}
}
return null;
},
};
}
function ruleBodyNotEmpty() {
return {
id: "body-not-empty",
severity: "error",
description: "Command body (below frontmatter) must not be empty",
check: (cmd) => {
if (!cmd.body || cmd.body.trim().length === 0) {
return result("body-not-empty", "error", "Command body is empty. Add instructions after the frontmatter block.");
}
return null;
},
};
}
function ruleArgsUsage() {
return {
id: "args-usage",
severity: "warning",
description: "If command uses $ARGUMENTS or positional args, usage should be documented",
check: (cmd) => {
if (!cmd.body)
return null;
const hasGlobalArg = /\$ARGUMENTS\b/.test(cmd.body);
const hasPositional = /\$\d\b/.test(cmd.body);
if (!hasGlobalArg && !hasPositional)
return null;
const hasUsageSection = /\b(użycie|usage|przykład|example)\b/i.test(cmd.body);
if (!hasUsageSection) {
let msg = "Command uses ";
if (hasGlobalArg && hasPositional) {
msg += "$ARGUMENTS and positional arguments ($1, $2, ...)";
}
else if (hasGlobalArg) {
msg += "$ARGUMENTS";
}
else {
msg += "positional arguments ($1, $2, ...)";
}
msg += ' but no "Usage" or "Example" section found';
return result("args-usage", "warning", msg, 'Add a "## Usage" section explaining how to use the arguments');
}
return null;
},
};
}
function ruleFileRefFormat() {
return {
id: "file-ref-format",
severity: "warning",
description: "@file references should follow valid path format",
check: (cmd) => {
if (!cmd.body)
return null;
const refRegex = /@([^\s`"')\]}>]+)/g;
const refs = [];
let match;
while ((match = refRegex.exec(cmd.body)) !== null) {
const ref = match[1];
// Skip if it's an email or URL
if (ref.includes("@") || ref.startsWith("http"))
continue;
// Skip markdown links [text](@...)
const before = cmd.body.slice(Math.max(0, match.index - 1), match.index);
if (before === "(")
continue;
refs.push(ref);
}
if (refs.length > 0) {
const brokenRefs = refs.filter((r) => r.length > 3 && !r.includes("/") && !r.includes("\\"));
if (brokenRefs.length > 0) {
return result("file-ref-format", "warning", `File references may be invalid: ${brokenRefs.join(", ")}. Expected format: @path/to/file`, `Ensure paths use format: @src/components/Button.tsx`);
}
}
return null;
},
};
}
function ruleMaxLines() {
return {
id: "max-lines",
severity: "warning",
description: "Command file should not exceed 150 lines",
check: (cmd) => {
if (cmd.lineCount > 150) {
return result("max-lines", "warning", `File exceeds 150 lines (${cmd.lineCount} lines). Consider splitting into multiple commands.`, `Currently ${cmd.lineCount} lines. Max recommended: 150.`);
}
return null;
},
};
}
function ruleSubtaskBoolean() {
return {
id: "subtask-boolean",
severity: "warning",
description: "Subtask field must be a boolean (true/false)",
check: (cmd) => {
if (cmd.frontmatter && "subtask" in cmd.frontmatter) {
const val = cmd.frontmatter.subtask;
if (typeof val !== "boolean") {
return result("subtask-boolean", "warning", `"subtask" must be true or false, got: ${JSON.stringify(val)}`, `Change to: subtask: ${String(val === "true" || val === true)}`);
}
}
return null;
},
};
}
function ruleHasAgentField() {
return {
id: "has-agent-field",
severity: "info",
description: "Recommend adding an agent field",
check: (cmd) => {
if (cmd.frontmatter && !("agent" in cmd.frontmatter)) {
return result("has-agent-field", "info", 'No "agent" field in frontmatter. Recommended to add one.', "Add: agent: build");
}
return null;
},
};
}
//# sourceMappingURL=rules.js.map