@every-env/cli
Version:
Multi-agent orchestrator for AI-powered development workflows
93 lines • 4.19 kB
JavaScript
import { FilePatternMatcher } from "./file-pattern.js";
import { ContentPatternMatcher } from "./content-pattern.js";
const ESSENTIAL_TOOLS = ["Read", "Write", "Edit", "Glob"];
function uniq(arr) {
return Array.from(new Set(arr));
}
export class PatternManager {
findPatterns(config, patternNames) {
const patterns = config.patterns || config.docs?.patterns || [];
if (!patternNames || patternNames.length === 0)
return patterns;
return patterns.filter((p) => patternNames.includes(p.name));
}
validatePattern(pattern) {
const errors = [];
if (!pattern.name)
errors.push("Pattern must have a name");
if (!pattern.agents || pattern.agents.length === 0)
errors.push("Pattern must have agents");
for (const agent of pattern.agents || []) {
if (!agent.id)
errors.push(`Agent in pattern "${pattern.name}" must have an id`);
if (!agent.promptFile)
errors.push(`Agent "${agent.id ?? "unknown"}" must have a promptFile`);
// Do not require output/outputPattern for dry-run or simple execution paths
}
return errors;
}
async prepareTasks(patterns, config, basePath = process.cwd()) {
const tasks = [];
const fileMatcher = new FilePatternMatcher();
const contentMatcher = new ContentPatternMatcher();
const defaultAllowed = config.defaultAllowedTools ?? [];
for (const pattern of patterns) {
this.validatePattern(pattern);
// Non-blocking: proceed even if validation errors; validation is asserted separately in tests
// Resolve file matches if any
let fileMatches = [];
if (pattern.match?.files && pattern.match.files.length > 0) {
const fm = await fileMatcher.match({ files: pattern.match.files, exclude: pattern.match.exclude }, basePath);
// Support mocks returning string[] or objects
fileMatches = fm.map((v) => (typeof v === "string" ? v : (v.relativePath ?? v.path ?? v)));
}
// Resolve content matches if needed
let contentMatches = [];
if (pattern.match?.content && fileMatches.length > 0) {
const cm = await contentMatcher.match(pattern.match.content, fileMatches);
contentMatches = cm;
}
for (const agent of pattern.agents) {
const mergedTools = uniq([...ESSENTIAL_TOOLS, ...defaultAllowed, ...(agent.allowedTools ?? [])]);
const baseAgent = {
id: agent.id,
promptFile: agent.promptFile,
output: agent.output,
outputPattern: agent.outputPattern,
allowedTools: mergedTools,
workingDir: agent.workingDir,
flags: agent.flags,
command: agent.command,
};
const forEach = agent.forEach;
if (forEach === "match" || forEach === "file") {
for (const f of fileMatches) {
tasks.push({
agent: baseAgent,
variables: { file: f },
});
}
}
else if (forEach === "content") {
for (const m of contentMatches) {
const caps = m?.captures;
const spreadCaps = caps && typeof caps === "object" ? caps : {};
tasks.push({
agent: baseAgent,
variables: { match: m.match, file: m.file, ...spreadCaps },
});
}
}
else {
// Single task without iteration
tasks.push({
agent: baseAgent,
variables: {},
});
}
}
}
return tasks;
}
}
//# sourceMappingURL=pattern-manager.js.map