241 lines
8.5 KiB
JavaScript
Raw Normal View History

feat: add agent schema validation with comprehensive testing (#774) Introduce automated validation for agent YAML files using Zod to ensure schema compliance across all agent definitions. This feature validates 17 agent files across core and module directories, catching structural errors and maintaining consistency. Schema Validation (tools/schema/agent.js): - Zod-based schema validating metadata, persona, menu, prompts, and critical actions - Module-aware validation: module field required for src/modules/**/agents/, optional for src/core/agents/ - Enforces kebab-case unique triggers and at least one command target per menu item - Validates persona.principles as array (not string) - Comprehensive refinements for data integrity CLI Validator (tools/validate-agent-schema.js): - Scans src/{core,modules/*}/agents/*.agent.yaml - Parses with js-yaml and validates using Zod schema - Reports detailed errors with file paths and field paths - Exits 1 on failures, 0 on success - Accepts optional project_root parameter for testing Testing (679 lines across 3 test files): - test/test-cli-integration.sh: CLI behavior and error handling tests - test/unit-test-schema.js: Direct schema validation unit tests - test/test-agent-schema.js: Comprehensive fixture-based tests - 50 test fixtures covering valid and invalid scenarios - ESLint configured to support CommonJS test files - Prettier configured to ignore intentionally broken fixtures CI Integration (.github/workflows/lint.yaml): - Renamed from format-check.yaml to lint.yaml - Added schema-validation job running npm run validate:schemas - Runs in parallel with prettier and eslint jobs - Validates on all pull requests Data Cleanup: - Fixed src/core/agents/bmad-master.agent.yaml: converted persona.principles from string to array format Documentation: - Updated schema-classification.md with validation section - Documents validator usage, enforcement rules, and CI integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 05:14:50 -07:00
// Zod schema definition for *.agent.yaml files
const assert = require('node:assert');
const { z } = require('zod');
const COMMAND_TARGET_KEYS = ['workflow', 'validate-workflow', 'exec', 'action', 'tmpl', 'data', 'run-workflow'];
const TRIGGER_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
// Public API ---------------------------------------------------------------
/**
* Validate an agent YAML payload against the schema derived from its file location.
* Exposed as the single public entry point, so callers do not reach into schema internals.
*
* @param {string} filePath Path to the agent file (used to infer module scope).
* @param {unknown} agentYaml Parsed YAML content.
* @returns {import('zod').SafeParseReturnType<unknown, unknown>} SafeParse result.
*/
function validateAgentFile(filePath, agentYaml) {
const expectedModule = deriveModuleFromPath(filePath);
const schema = agentSchema({ module: expectedModule });
return schema.safeParse(agentYaml);
}
module.exports = { validateAgentFile };
// Internal helpers ---------------------------------------------------------
/**
* Build a Zod schema for validating a single agent definition.
* The schema is generated per call so module-scoped agents can pass their expected
* module slug while core agents leave it undefined.
*
* @param {Object} [options]
* @param {string|null|undefined} [options.module] Module slug for module agents; omit or null for core agents.
* @returns {import('zod').ZodSchema} Configured Zod schema instance.
*/
function agentSchema(options = {}) {
const expectedModule = normalizeModuleOption(options.module);
return (
z
.object({
agent: buildAgentSchema(expectedModule),
})
.strict()
// Refinement: enforce trigger format and uniqueness rules after structural checks.
.superRefine((value, ctx) => {
const seenTriggers = new Set();
let index = 0;
for (const item of value.agent.menu) {
const triggerValue = item.trigger;
if (!TRIGGER_PATTERN.test(triggerValue)) {
ctx.addIssue({
code: 'custom',
path: ['agent', 'menu', index, 'trigger'],
message: 'agent.menu[].trigger must be kebab-case (lowercase words separated by hyphen)',
});
return;
}
if (seenTriggers.has(triggerValue)) {
ctx.addIssue({
code: 'custom',
path: ['agent', 'menu', index, 'trigger'],
message: `agent.menu[].trigger duplicates "${triggerValue}" within the same agent`,
});
return;
}
seenTriggers.add(triggerValue);
index += 1;
}
})
);
}
/**
* Assemble the full agent schema using the module expectation provided by the caller.
* @param {string|null} expectedModule Trimmed module slug or null for core agents.
*/
function buildAgentSchema(expectedModule) {
return z
.object({
metadata: buildMetadataSchema(expectedModule),
persona: buildPersonaSchema(),
critical_actions: z.array(createNonEmptyString('agent.critical_actions[]')).optional(),
menu: z.array(buildMenuItemSchema()).min(1, { message: 'agent.menu must include at least one entry' }),
prompts: z.array(buildPromptSchema()).optional(),
Major Enhancements: - Installation path is now fully configurable, allowing users to specify custom installation directories during setup - Default installation location changed to .bmad (hidden directory) for cleaner project root organization Web Bundle Improvements: - All web bundles (single agent and team) now include party mode support for multi-agent collaboration! - Advanced elicitation capabilities integrated into standalone agents - All bundles enhanced with party mode agent manifests - Added default-party.csv files to bmm, bmgd, and cis module teams - The default party file is what will be used with single agent bundles. teams can customize for different party configurations before web bundling through a setting in the team yaml file - New web bundle outputs for all agents (analyst, architect, dev, pm, sm, tea, tech-writer, ux-designer, game-*, creative-squad) Phase 4 Workflow Updates (In Progress): - Initiated shift to separate phase 4 implementation artifacts from documentation - Phase 4 implementation artifacts (stories, code review, sprint plan, context files) will move to dedicated location outside docs folder - Installer questions and configuration added for artifact path selection - Updated workflow.yaml files for code-review, sprint-planning, story-context, epic-tech-context, and retrospective workflows to support this, but still might require some udpates Additional Changes: - New agent and action command header models for standardization - Enhanced web-bundle-activation-steps fragment - Updated web-bundler.js to support new structure - VS Code settings updated for new .bmad directory - Party mode instructions and workflow enhanced for better orchestration IDE Installer Updates: - Show version number of installer in cli - improved Installer UX - Gemini TOML Improved to have clear loading instructions with @ commands - All tools agent launcher mds improved to use a central file template critical indication isntead of hardcoding in 2 different locations.
2025-11-09 17:39:05 -06:00
webskip: z.boolean().optional(),
feat: add agent schema validation with comprehensive testing (#774) Introduce automated validation for agent YAML files using Zod to ensure schema compliance across all agent definitions. This feature validates 17 agent files across core and module directories, catching structural errors and maintaining consistency. Schema Validation (tools/schema/agent.js): - Zod-based schema validating metadata, persona, menu, prompts, and critical actions - Module-aware validation: module field required for src/modules/**/agents/, optional for src/core/agents/ - Enforces kebab-case unique triggers and at least one command target per menu item - Validates persona.principles as array (not string) - Comprehensive refinements for data integrity CLI Validator (tools/validate-agent-schema.js): - Scans src/{core,modules/*}/agents/*.agent.yaml - Parses with js-yaml and validates using Zod schema - Reports detailed errors with file paths and field paths - Exits 1 on failures, 0 on success - Accepts optional project_root parameter for testing Testing (679 lines across 3 test files): - test/test-cli-integration.sh: CLI behavior and error handling tests - test/unit-test-schema.js: Direct schema validation unit tests - test/test-agent-schema.js: Comprehensive fixture-based tests - 50 test fixtures covering valid and invalid scenarios - ESLint configured to support CommonJS test files - Prettier configured to ignore intentionally broken fixtures CI Integration (.github/workflows/lint.yaml): - Renamed from format-check.yaml to lint.yaml - Added schema-validation job running npm run validate:schemas - Runs in parallel with prettier and eslint jobs - Validates on all pull requests Data Cleanup: - Fixed src/core/agents/bmad-master.agent.yaml: converted persona.principles from string to array format Documentation: - Updated schema-classification.md with validation section - Documents validator usage, enforcement rules, and CI integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 05:14:50 -07:00
})
.strict();
}
/**
* Validate metadata shape and cross-check module expectation against caller input.
* @param {string|null} expectedModule Trimmed module slug or null when core agent metadata is expected.
*/
function buildMetadataSchema(expectedModule) {
const schemaShape = {
id: createNonEmptyString('agent.metadata.id'),
name: createNonEmptyString('agent.metadata.name'),
title: createNonEmptyString('agent.metadata.title'),
icon: createNonEmptyString('agent.metadata.icon'),
module: createNonEmptyString('agent.metadata.module').optional(),
};
return (
z
.object(schemaShape)
.strict()
// Refinement: guard presence and correctness of metadata.module.
.superRefine((value, ctx) => {
const moduleValue = typeof value.module === 'string' ? value.module.trim() : null;
if (expectedModule && !moduleValue) {
ctx.addIssue({
code: 'custom',
path: ['module'],
message: 'module-scoped agents must declare agent.metadata.module',
});
} else if (!expectedModule && moduleValue) {
ctx.addIssue({
code: 'custom',
path: ['module'],
message: 'core agents must not include agent.metadata.module',
});
} else if (expectedModule && moduleValue !== expectedModule) {
ctx.addIssue({
code: 'custom',
path: ['module'],
message: `agent.metadata.module must equal "${expectedModule}"`,
});
}
})
);
}
function buildPersonaSchema() {
return z
.object({
role: createNonEmptyString('agent.persona.role'),
identity: createNonEmptyString('agent.persona.identity'),
communication_style: createNonEmptyString('agent.persona.communication_style'),
Major Enhancements: - Installation path is now fully configurable, allowing users to specify custom installation directories during setup - Default installation location changed to .bmad (hidden directory) for cleaner project root organization Web Bundle Improvements: - All web bundles (single agent and team) now include party mode support for multi-agent collaboration! - Advanced elicitation capabilities integrated into standalone agents - All bundles enhanced with party mode agent manifests - Added default-party.csv files to bmm, bmgd, and cis module teams - The default party file is what will be used with single agent bundles. teams can customize for different party configurations before web bundling through a setting in the team yaml file - New web bundle outputs for all agents (analyst, architect, dev, pm, sm, tea, tech-writer, ux-designer, game-*, creative-squad) Phase 4 Workflow Updates (In Progress): - Initiated shift to separate phase 4 implementation artifacts from documentation - Phase 4 implementation artifacts (stories, code review, sprint plan, context files) will move to dedicated location outside docs folder - Installer questions and configuration added for artifact path selection - Updated workflow.yaml files for code-review, sprint-planning, story-context, epic-tech-context, and retrospective workflows to support this, but still might require some udpates Additional Changes: - New agent and action command header models for standardization - Enhanced web-bundle-activation-steps fragment - Updated web-bundler.js to support new structure - VS Code settings updated for new .bmad directory - Party mode instructions and workflow enhanced for better orchestration IDE Installer Updates: - Show version number of installer in cli - improved Installer UX - Gemini TOML Improved to have clear loading instructions with @ commands - All tools agent launcher mds improved to use a central file template critical indication isntead of hardcoding in 2 different locations.
2025-11-09 17:39:05 -06:00
principles: z.union([
createNonEmptyString('agent.persona.principles'),
z
.array(createNonEmptyString('agent.persona.principles[]'))
.min(1, { message: 'agent.persona.principles must include at least one entry' }),
]),
feat: add agent schema validation with comprehensive testing (#774) Introduce automated validation for agent YAML files using Zod to ensure schema compliance across all agent definitions. This feature validates 17 agent files across core and module directories, catching structural errors and maintaining consistency. Schema Validation (tools/schema/agent.js): - Zod-based schema validating metadata, persona, menu, prompts, and critical actions - Module-aware validation: module field required for src/modules/**/agents/, optional for src/core/agents/ - Enforces kebab-case unique triggers and at least one command target per menu item - Validates persona.principles as array (not string) - Comprehensive refinements for data integrity CLI Validator (tools/validate-agent-schema.js): - Scans src/{core,modules/*}/agents/*.agent.yaml - Parses with js-yaml and validates using Zod schema - Reports detailed errors with file paths and field paths - Exits 1 on failures, 0 on success - Accepts optional project_root parameter for testing Testing (679 lines across 3 test files): - test/test-cli-integration.sh: CLI behavior and error handling tests - test/unit-test-schema.js: Direct schema validation unit tests - test/test-agent-schema.js: Comprehensive fixture-based tests - 50 test fixtures covering valid and invalid scenarios - ESLint configured to support CommonJS test files - Prettier configured to ignore intentionally broken fixtures CI Integration (.github/workflows/lint.yaml): - Renamed from format-check.yaml to lint.yaml - Added schema-validation job running npm run validate:schemas - Runs in parallel with prettier and eslint jobs - Validates on all pull requests Data Cleanup: - Fixed src/core/agents/bmad-master.agent.yaml: converted persona.principles from string to array format Documentation: - Updated schema-classification.md with validation section - Documents validator usage, enforcement rules, and CI integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 05:14:50 -07:00
})
.strict();
}
function buildPromptSchema() {
return z
.object({
id: createNonEmptyString('agent.prompts[].id'),
content: z.string().refine((value) => value.trim().length > 0, {
message: 'agent.prompts[].content must be a non-empty string',
}),
description: createNonEmptyString('agent.prompts[].description').optional(),
})
.strict();
}
/**
* Schema for individual menu entries ensuring they are actionable.
*/
function buildMenuItemSchema() {
return z
.object({
trigger: createNonEmptyString('agent.menu[].trigger'),
description: createNonEmptyString('agent.menu[].description'),
workflow: createNonEmptyString('agent.menu[].workflow').optional(),
feat: Extract BMGD module and implement workflow vendoring This commit extracts game development functionality from BMM into a standalone BMGD (BMad Game Development) module and implements workflow vendoring to enable module independence. BMGD Module Creation: - Moved agents: game-designer, game-dev, game-architect from BMM to BMGD - Moved team config: team-gamedev - Created new Game Dev Scrum Master agent using workflow vendoring pattern - Reorganized workflows into industry-standard game dev phases: * Phase 1 (Preproduction): brainstorm-game, game-brief * Phase 2 (Design): gdd, narrative * Phase 3 (Technical): game-architecture * Phase 4 (Production): vendored from BMM workflows - Updated all module metadata and config_source references Workflow Vendoring Feature: - Enables modules to copy workflows from other modules during installation - Build-time process that updates config_source in vendored workflows - New agent YAML attribute: workflow-install (build-time metadata) - Final compiled agents use workflow-install value for workflow attribute - Implementation in module manager: vendorCrossModuleWorkflows() - Allows standalone module installation without forced dependencies Technical Changes: - tools/cli/lib/yaml-xml-builder.js: Use workflow-install for workflow attribute - tools/cli/installers/lib/modules/manager.js: Add vendoring functions - tools/schema/agent.js: Add workflow-install to menu item schema - Updated 3 documentation files with workflow vendoring details BMM Workflow Updates: - workflow-status/init: Added game detection checkpoint - workflow-status/paths/game-design.yaml: Redirect to BMGD module - prd/instructions.md: Route game projects to BMGD - research/instructions-market.md: Reference BMGD for game development Documentation: - Created comprehensive BMGD module README - Added workflow vendoring documentation - Updated BMB agent creation and module creation guides
2025-11-05 20:44:22 -06:00
'workflow-install': createNonEmptyString('agent.menu[].workflow-install').optional(),
feat: add agent schema validation with comprehensive testing (#774) Introduce automated validation for agent YAML files using Zod to ensure schema compliance across all agent definitions. This feature validates 17 agent files across core and module directories, catching structural errors and maintaining consistency. Schema Validation (tools/schema/agent.js): - Zod-based schema validating metadata, persona, menu, prompts, and critical actions - Module-aware validation: module field required for src/modules/**/agents/, optional for src/core/agents/ - Enforces kebab-case unique triggers and at least one command target per menu item - Validates persona.principles as array (not string) - Comprehensive refinements for data integrity CLI Validator (tools/validate-agent-schema.js): - Scans src/{core,modules/*}/agents/*.agent.yaml - Parses with js-yaml and validates using Zod schema - Reports detailed errors with file paths and field paths - Exits 1 on failures, 0 on success - Accepts optional project_root parameter for testing Testing (679 lines across 3 test files): - test/test-cli-integration.sh: CLI behavior and error handling tests - test/unit-test-schema.js: Direct schema validation unit tests - test/test-agent-schema.js: Comprehensive fixture-based tests - 50 test fixtures covering valid and invalid scenarios - ESLint configured to support CommonJS test files - Prettier configured to ignore intentionally broken fixtures CI Integration (.github/workflows/lint.yaml): - Renamed from format-check.yaml to lint.yaml - Added schema-validation job running npm run validate:schemas - Runs in parallel with prettier and eslint jobs - Validates on all pull requests Data Cleanup: - Fixed src/core/agents/bmad-master.agent.yaml: converted persona.principles from string to array format Documentation: - Updated schema-classification.md with validation section - Documents validator usage, enforcement rules, and CI integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 05:14:50 -07:00
'validate-workflow': createNonEmptyString('agent.menu[].validate-workflow').optional(),
exec: createNonEmptyString('agent.menu[].exec').optional(),
action: createNonEmptyString('agent.menu[].action').optional(),
tmpl: createNonEmptyString('agent.menu[].tmpl').optional(),
data: createNonEmptyString('agent.menu[].data').optional(),
'run-workflow': createNonEmptyString('agent.menu[].run-workflow').optional(),
checklist: createNonEmptyString('agent.menu[].checklist').optional(),
document: createNonEmptyString('agent.menu[].document').optional(),
feat: Add ide-only and web-only menu item filtering for platform-specific commands ## Summary - Add ide-only and web-only boolean fields to agent menu schema - Filter menu items based on build target (web bundle vs local IDE) - Update BMM agent definitions with platform restrictions and improved descriptions - Update frame-expert agent icon to 📐 and add webskip flag ## Changes ### Schema & Bundler Updates - tools/schema/agent.js: Add ide-only and web-only optional boolean fields - tools/cli/lib/yaml-xml-builder.js: Filter ide-only items from web bundles - tools/cli/lib/xml-handler.js: Pass forWebBundle flag through build chain ### Agent Updates - frame-expert: Change icon to 📐, add webskip flag, improve principle formatting - pm: Mark workflow-init and correct-course as ide-only, advanced-elicitation as web-only - ux-designer: Rename trigger to create-ux-design, mark advanced-elicitation as web-only - sm: Rename triggers for consistency (story-context → create-story-context) - analyst: Add research workflow after brainstorm, mark advanced-elicitation as web-only - architect: Remove document field from validate-architecture, add web-only flag - dev: Update persona and critical actions for clarity - tech-writer: Add party-mode workflow, mark advanced-elicitation as web-only - tea: Mark advanced-elicitation as web-only - All agents: Standardize party-mode description This enables platform-specific functionality where some commands only make sense in IDE environments (workflow-init) or web interfaces (advanced-elicitation).
2025-11-15 19:39:53 -06:00
'ide-only': z.boolean().optional(),
'web-only': z.boolean().optional(),
feat: add agent schema validation with comprehensive testing (#774) Introduce automated validation for agent YAML files using Zod to ensure schema compliance across all agent definitions. This feature validates 17 agent files across core and module directories, catching structural errors and maintaining consistency. Schema Validation (tools/schema/agent.js): - Zod-based schema validating metadata, persona, menu, prompts, and critical actions - Module-aware validation: module field required for src/modules/**/agents/, optional for src/core/agents/ - Enforces kebab-case unique triggers and at least one command target per menu item - Validates persona.principles as array (not string) - Comprehensive refinements for data integrity CLI Validator (tools/validate-agent-schema.js): - Scans src/{core,modules/*}/agents/*.agent.yaml - Parses with js-yaml and validates using Zod schema - Reports detailed errors with file paths and field paths - Exits 1 on failures, 0 on success - Accepts optional project_root parameter for testing Testing (679 lines across 3 test files): - test/test-cli-integration.sh: CLI behavior and error handling tests - test/unit-test-schema.js: Direct schema validation unit tests - test/test-agent-schema.js: Comprehensive fixture-based tests - 50 test fixtures covering valid and invalid scenarios - ESLint configured to support CommonJS test files - Prettier configured to ignore intentionally broken fixtures CI Integration (.github/workflows/lint.yaml): - Renamed from format-check.yaml to lint.yaml - Added schema-validation job running npm run validate:schemas - Runs in parallel with prettier and eslint jobs - Validates on all pull requests Data Cleanup: - Fixed src/core/agents/bmad-master.agent.yaml: converted persona.principles from string to array format Documentation: - Updated schema-classification.md with validation section - Documents validator usage, enforcement rules, and CI integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
2025-10-20 05:14:50 -07:00
})
.strict()
.superRefine((value, ctx) => {
const hasCommandTarget = COMMAND_TARGET_KEYS.some((key) => {
const commandValue = value[key];
return typeof commandValue === 'string' && commandValue.trim().length > 0;
});
if (!hasCommandTarget) {
ctx.addIssue({
code: 'custom',
message: 'agent.menu[] entries must include at least one command target field',
});
}
});
}
/**
* Derive the expected module slug from a file path residing under src/modules/<module>/agents/.
* @param {string} filePath Absolute or relative agent path.
* @returns {string|null} Module slug if identifiable, otherwise null.
*/
function deriveModuleFromPath(filePath) {
assert(filePath, 'validateAgentFile expects filePath to be provided');
assert(typeof filePath === 'string', 'validateAgentFile expects filePath to be a string');
assert(filePath.startsWith('src/'), 'validateAgentFile expects filePath to start with "src/"');
const marker = 'src/modules/';
if (!filePath.startsWith(marker)) {
return null;
}
const remainder = filePath.slice(marker.length);
const slashIndex = remainder.indexOf('/');
return slashIndex === -1 ? null : remainder.slice(0, slashIndex);
}
function normalizeModuleOption(moduleOption) {
if (typeof moduleOption !== 'string') {
return null;
}
const trimmed = moduleOption.trim();
return trimmed.length > 0 ? trimmed : null;
}
// Primitive validators -----------------------------------------------------
function createNonEmptyString(label) {
return z.string().refine((value) => value.trim().length > 0, {
message: `${label} must be a non-empty string`,
});
}