Add 5 pi extensions: pi-subagents, pi-crew, rpiv-pi, pi-interactive-shell, pi-intercom
This commit is contained in:
77
extensions/pi-crew/src/extension/validate-resources.ts
Normal file
77
extensions/pi-crew/src/extension/validate-resources.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { allAgents, discoverAgents } from "../agents/discover-agents.ts";
|
||||
import { allTeams, discoverTeams } from "../teams/discover-teams.ts";
|
||||
import { allWorkflows, discoverWorkflows } from "../workflows/discover-workflows.ts";
|
||||
import { validateWorkflowForTeam } from "../workflows/validate-workflow.ts";
|
||||
|
||||
export interface ValidationIssue {
|
||||
level: "error" | "warning";
|
||||
resource: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface ValidationReport {
|
||||
issues: ValidationIssue[];
|
||||
agents: number;
|
||||
teams: number;
|
||||
workflows: number;
|
||||
}
|
||||
|
||||
export function validateResources(cwd: string): ValidationReport {
|
||||
const agents = allAgents(discoverAgents(cwd));
|
||||
const teams = allTeams(discoverTeams(cwd));
|
||||
const workflows = allWorkflows(discoverWorkflows(cwd));
|
||||
const agentNames = new Set(agents.map((agent) => agent.name));
|
||||
const workflowNames = new Set(workflows.map((workflow) => workflow.name));
|
||||
const issues: ValidationIssue[] = [];
|
||||
|
||||
for (const agent of agents) {
|
||||
const modelValues = [agent.model, ...(agent.fallbackModels ?? [])].filter((value): value is string => typeof value === "string" && value.length > 0);
|
||||
for (const model of modelValues) {
|
||||
if (/\s/.test(model)) {
|
||||
issues.push({ level: "warning", resource: `agent:${agent.name}`, message: `Model reference '${model}' contains whitespace.` });
|
||||
}
|
||||
if (model.includes("/") && model.split("/").some((part) => part.trim() === "")) {
|
||||
issues.push({ level: "warning", resource: `agent:${agent.name}`, message: `Model reference '${model}' has an empty provider/model segment.` });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const team of teams) {
|
||||
for (const role of team.roles) {
|
||||
if (!agentNames.has(role.agent)) {
|
||||
issues.push({ level: "error", resource: `team:${team.name}`, message: `Role '${role.name}' references unknown agent '${role.agent}'.` });
|
||||
}
|
||||
}
|
||||
if (team.defaultWorkflow && !workflowNames.has(team.defaultWorkflow)) {
|
||||
issues.push({ level: "error", resource: `team:${team.name}`, message: `defaultWorkflow references unknown workflow '${team.defaultWorkflow}'.` });
|
||||
}
|
||||
const workflow = workflows.find((candidate) => candidate.name === team.defaultWorkflow);
|
||||
if (workflow) {
|
||||
for (const error of validateWorkflowForTeam(workflow, team)) {
|
||||
issues.push({ level: "error", resource: `workflow:${workflow.name}`, message: `Team '${team.name}': ${error}` });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const workflow of workflows) {
|
||||
if (workflow.steps.length === 0) {
|
||||
issues.push({ level: "warning", resource: `workflow:${workflow.name}`, message: "Workflow has no steps." });
|
||||
}
|
||||
}
|
||||
|
||||
return { issues, agents: agents.length, teams: teams.length, workflows: workflows.length };
|
||||
}
|
||||
|
||||
export function formatValidationReport(report: ValidationReport): string {
|
||||
const lines = [
|
||||
"pi-crew resource validation:",
|
||||
`Agents: ${report.agents}`,
|
||||
`Teams: ${report.teams}`,
|
||||
`Workflows: ${report.workflows}`,
|
||||
`Issues: ${report.issues.length}`,
|
||||
];
|
||||
if (report.issues.length > 0) {
|
||||
lines.push("", ...report.issues.map((issue) => `- ${issue.level.toUpperCase()} ${issue.resource}: ${issue.message}`));
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
Reference in New Issue
Block a user