feat(pi-workflow): reuse standard agent profiles
This commit is contained in:
@@ -7,6 +7,8 @@ import {
|
||||
MAX_ASSIGNMENTS_PER_RUN,
|
||||
MAX_CONCURRENCY,
|
||||
MAX_REVIEW_CYCLES,
|
||||
PROFILE_ROLES,
|
||||
type ProfileRole,
|
||||
type WorkflowConfig,
|
||||
} from "./domain.ts";
|
||||
|
||||
@@ -15,10 +17,13 @@ const TOP_LEVEL_KEYS = new Set([
|
||||
"maxAssignmentsPerRun",
|
||||
"maxReviewCycles",
|
||||
"analysisTools",
|
||||
"standardAgents",
|
||||
"worktrees",
|
||||
]);
|
||||
const CONCURRENCY_KEYS = new Set(["default", "ceiling"]);
|
||||
const STANDARD_AGENT_KEYS = new Set(["enabled", "roles"]);
|
||||
const WORKTREE_KEYS = new Set(["root"]);
|
||||
const PROFILE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
||||
|
||||
export interface LoadWorkflowConfigOptions {
|
||||
cwd: string;
|
||||
@@ -97,6 +102,15 @@ function cloneConfig(config: WorkflowConfig): WorkflowConfig {
|
||||
maxAssignmentsPerRun: config.maxAssignmentsPerRun,
|
||||
maxReviewCycles: config.maxReviewCycles,
|
||||
analysisTools: [...config.analysisTools],
|
||||
standardAgents: {
|
||||
enabled: config.standardAgents.enabled,
|
||||
roles: Object.fromEntries(
|
||||
Object.entries(config.standardAgents.roles).map(([name, roles]) => [
|
||||
name,
|
||||
[...roles],
|
||||
]),
|
||||
),
|
||||
},
|
||||
worktrees: { ...config.worktrees },
|
||||
};
|
||||
}
|
||||
@@ -192,6 +206,57 @@ function applyConfigLayer(
|
||||
);
|
||||
}
|
||||
|
||||
if (value.standardAgents !== undefined) {
|
||||
if (!isRecord(value.standardAgents)) {
|
||||
throw new Error(`${label}.standardAgents must be an object`);
|
||||
}
|
||||
assertKnownKeys(
|
||||
value.standardAgents,
|
||||
STANDARD_AGENT_KEYS,
|
||||
`${label}.standardAgents`,
|
||||
);
|
||||
if (value.standardAgents.enabled !== undefined) {
|
||||
if (typeof value.standardAgents.enabled !== "boolean") {
|
||||
throw new Error(`${label}.standardAgents.enabled must be a boolean`);
|
||||
}
|
||||
next.standardAgents.enabled = value.standardAgents.enabled;
|
||||
}
|
||||
if (value.standardAgents.roles !== undefined) {
|
||||
if (!isRecord(value.standardAgents.roles)) {
|
||||
throw new Error(`${label}.standardAgents.roles must be an object`);
|
||||
}
|
||||
const roles: Record<string, ProfileRole[]> = {};
|
||||
for (const [name, rawRoles] of Object.entries(
|
||||
value.standardAgents.roles,
|
||||
)) {
|
||||
if (!PROFILE_NAME.test(name)) {
|
||||
throw new Error(
|
||||
`${label}.standardAgents.roles agent names must be lowercase kebab case`,
|
||||
);
|
||||
}
|
||||
const requested = stringArray(
|
||||
rawRoles,
|
||||
`${label}.standardAgents.roles.${name}`,
|
||||
);
|
||||
if (requested.length === 0) {
|
||||
throw new Error(
|
||||
`${label}.standardAgents.roles.${name} must not be empty`,
|
||||
);
|
||||
}
|
||||
const invalid = requested.filter(
|
||||
(role) => !PROFILE_ROLES.includes(role as ProfileRole),
|
||||
);
|
||||
if (invalid.length > 0) {
|
||||
throw new Error(
|
||||
`${label}.standardAgents.roles.${name} contains unsupported role ${invalid.join(", ")}`,
|
||||
);
|
||||
}
|
||||
roles[name] = requested as ProfileRole[];
|
||||
}
|
||||
next.standardAgents.roles = roles;
|
||||
}
|
||||
}
|
||||
|
||||
if (value.worktrees !== undefined) {
|
||||
if (!isRecord(value.worktrees)) {
|
||||
throw new Error(`${label}.worktrees must be an object`);
|
||||
|
||||
Reference in New Issue
Block a user