import { loadConfig } from '../config.js'; export interface AgentIdentity { canonical: string; names: Set; } /** * Resolve an agent, configured alias, or role name to the canonical roster * agent. Projects without an explicit roster keep accepting free-form agent * names for backward compatibility. */ export function resolveAgentName(cwd: string, recipient: string): string { const raw = recipient?.trim(); if (!raw) throw new Error('Agent recipient is required'); const key = raw.toLowerCase(); let config; try { config = loadConfig(cwd); } catch { return raw; } const role = Object.entries(config.roles).find(([name]) => name.toLowerCase() === key); if (role) return role[1].preferredAgent; const agents = config.agents; if (!agents || Object.keys(agents).length === 0) return raw; for (const [canonical, entry] of Object.entries(agents)) { if (canonical.toLowerCase() === key || entry.aliases.some((alias) => alias.toLowerCase() === key)) { return canonical; } } throw new Error(`Unknown agent, alias, or role: "${raw}"`); } /** All names that should compare equal for task/handoff/inbox matching. */ export function agentIdentity(cwd: string, recipient: string): AgentIdentity { const canonical = resolveAgentName(cwd, recipient); const config = loadConfig(cwd); const names = new Set([canonical.toLowerCase()]); const entry = config.agents?.[canonical]; for (const alias of entry?.aliases ?? []) names.add(alias.toLowerCase()); for (const [role, roleConfig] of Object.entries(config.roles)) { if (roleConfig.preferredAgent.toLowerCase() === canonical.toLowerCase()) names.add(role.toLowerCase()); } return { canonical, names }; }