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');
|
|
|
|
|
|
2025-11-23 21:28:50 -06:00
|
|
|
const COMMAND_TARGET_KEYS = ['workflow', 'validate-workflow', 'exec', 'action', 'tmpl', 'data'];
|
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
|
|
|
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(),
|
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(),
|
2025-11-04 10:31:36 -06:00
|
|
|
checklist: createNonEmptyString('agent.menu[].checklist').optional(),
|
|
|
|
|
document: createNonEmptyString('agent.menu[].document').optional(),
|
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`,
|
|
|
|
|
});
|
|
|
|
|
}
|