{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/agents/agents.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Agent discovery and configuration\n */\n\nimport { execSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parse as parseYaml } from \"yaml\";\nimport { type ModelScopeConfig, parseModelScopeConfig } from \"../runs/shared/model-scope.ts\";\nimport type {\n\tAcceptanceInput,\n\tAcceptanceRole,\n\tAgentRunnerConfig,\n\tOutputMode,\n\tToolBudgetConfig,\n\tTurnBudgetConfig,\n} from \"../shared/types.ts\";\nimport { parseRunnerRetryConfig } from \"../shared/runner-config.ts\";\nimport { getAgentDir, getProjectConfigDir } from \"../shared/utils.ts\";\nimport { mergeAgentsForScope } from \"./agent-selection.ts\";\nimport { KNOWN_FIELDS } from \"./agent-serializer.ts\";\nimport { parseChain, parseJsonChain } from \"./chain-serializer.ts\";\nimport { parseFrontmatter, parseFrontmatterList } from \"./frontmatter.ts\";\nimport { buildRuntimeName, parsePackageName } from \"./identity.ts\";\n\nexport { buildRuntimeName, frontmatterNameForConfig, parsePackageName } from \"./identity.ts\";\n\nimport { validateAcceptanceInput } from \"../runs/shared/acceptance.ts\";\nimport { type PermissionRules, validatePermissionRules } from \"../runs/shared/permissions.ts\";\nimport { resolveTurnBudgetConfig } from \"../runs/shared/turn-budget.ts\";\nimport { parseMemoryFrontmatter } from \"./agent-memory.ts\";\n\nexport type AgentScope = \"user\" | \"project\" | \"both\";\n\nexport type AgentSource = \"builtin\" | \"package\" | \"user\" | \"project\";\ntype SystemPromptMode = \"append\" | \"replace\";\nexport type AgentDefaultContext = \"fresh\" | \"fork\";\n\nexport type AgentMemoryScope = \"project\" | \"user\";\n\nexport interface AgentMemoryConfig {\n\tscope: AgentMemoryScope;\n\tpath: string;\n}\n\nexport const BUILTIN_AGENT_NAMES = [\n\t\"advisor\",\n\t\"delegate\",\n\t\"fanout\",\n\t\"oracle\",\n\t\"researcher\",\n\t\"reviewer\",\n\t\"scout\",\n\t\"worker\",\n\t\"workflow-worker\",\n] as const;\n\nexport function defaultSystemPromptMode(name: string): SystemPromptMode {\n\treturn name === \"delegate\" ? \"append\" : \"replace\";\n}\n\nexport function defaultInheritProjectContext(name: string): boolean {\n\treturn name === \"delegate\";\n}\n\nexport function defaultInheritSkills(): boolean {\n\treturn false;\n}\n\nexport interface BuiltinAgentOverrideBase {\n\tdescription?: string;\n\tmodel?: string;\n\tfallbackModels?: string[];\n\tthinking?: string | false;\n\tsystemPromptMode: SystemPromptMode;\n\tinheritProjectContext: boolean;\n\tinheritSkills: boolean;\n\tdefaultContext?: AgentDefaultContext;\n\tacceptanceRole?: AcceptanceRole;\n\tdisabled?: boolean;\n\tsystemPrompt: string;\n\tskills?: string[];\n\tskillPath?: string[];\n\ttools?: string[];\n\tmcpDirectTools?: string[];\n\textensions?: string[];\n\tsubagentOnlyExtensions?: string[];\n\tcompletionGuard?: boolean;\n\ttoolBudget?: ToolBudgetConfig;\n}\n\ninterface BuiltinAgentOverrideConfig {\n\tdescription?: string;\n\tmodel?: string | false;\n\tfallbackModels?: string[] | false;\n\tthinking?: string | false;\n\tsystemPromptMode?: SystemPromptMode;\n\tinheritProjectContext?: boolean;\n\tinheritSkills?: boolean;\n\tdefaultContext?: AgentDefaultContext | false;\n\tacceptanceRole?: AcceptanceRole | false;\n\tdisabled?: boolean;\n\tsystemPrompt?: string;\n\tskills?: string[] | false;\n\ttools?: string[] | false;\n\textensions?: string[] | false;\n\tsubagentOnlyExtensions?: string[] | false;\n\tcompletionGuard?: boolean;\n\ttoolBudget?: ToolBudgetConfig | false;\n}\n\ninterface BuiltinAgentOverrideInfo {\n\tscope: \"user\" | \"project\";\n\tpath: string;\n\tbase: BuiltinAgentOverrideBase;\n}\n\nexport interface AgentModelSourceInfo {\n\ttype: \"subagents.defaultModel\";\n\tscope: \"user\" | \"project\";\n\tpath: string;\n\tmodel: string;\n}\n\nexport interface AgentConfig {\n\tname: string;\n\trunner?: AgentRunnerConfig;\n\tlocalName?: string;\n\tpackageName?: string;\n\tdescription: string;\n\taliases?: string[];\n\ttools?: string[];\n\tmcpDirectTools?: string[];\n\tmodel?: string;\n\tfallbackModels?: string[];\n\tthinking?: string | false;\n\tsystemPromptMode: SystemPromptMode;\n\tinheritProjectContext: boolean;\n\tinheritSkills: boolean;\n\tdefaultContext?: AgentDefaultContext;\n\tdefaultAsync?: boolean;\n\tdefaultTimeoutMs?: number;\n\tdefaultTurnBudget?: TurnBudgetConfig;\n\tdefaultAcceptance?: AcceptanceInput;\n\tacceptanceRole?: AcceptanceRole;\n\tsystemPrompt: string;\n\tsource: AgentSource;\n\tfilePath: string;\n\tskills?: string[];\n\tskillPath?: string[];\n\textensions?: string[];\n\textensionsFromDefault?: boolean;\n\tsubagentOnlyExtensions?: string[];\n\toutput?: string;\n\tdefaultReads?: string[];\n\tdefaultProgress?: boolean;\n\tinteractive?: boolean;\n\tmaxSubagentDepth?: number;\n\tcompletionGuard?: boolean;\n\ttoolBudget?: ToolBudgetConfig;\n\tpermissions?: PermissionRules;\n\tmemory?: AgentMemoryConfig;\n\tdisabled?: boolean;\n\textraFields?: Record<string, string>;\n\toverride?: BuiltinAgentOverrideInfo;\n\tmodelSource?: AgentModelSourceInfo;\n}\n\ntype ProjectRootResolution = \"nearest\" | \"git-root\";\n\ninterface SubagentSettings {\n\toverrides: Record<string, BuiltinAgentOverrideConfig>;\n\tdefaultModel?: string;\n\tdefaultThinking?: string;\n\tdefaultExtensions?: string[];\n\tdisableBuiltins?: boolean;\n\tdisableThinking?: boolean;\n\tmodelScope?: ModelScopeConfig;\n}\n\nconst EMPTY_SUBAGENT_SETTINGS: SubagentSettings = { overrides: {} };\nconst agentFrontmatterFields = new WeakMap<AgentConfig, Set<string>>();\n\nexport interface ChainStepConfig {\n\tagent?: string;\n\ttask?: string;\n\tphase?: string;\n\tlabel?: string;\n\tas?: string;\n\toutputSchema?: string | Record<string, unknown>;\n\toutput?: string | false;\n\toutputMode?: OutputMode;\n\treads?: string[] | false;\n\tmodel?: string;\n\tskills?: string[] | false;\n\tprogress?: boolean;\n\tparallel?: unknown;\n\texpand?: unknown;\n\tcollect?: unknown;\n\tconcurrency?: number;\n\tfailFast?: boolean;\n\tworktree?: boolean;\n\tacceptance?: AcceptanceInput;\n\ttoolBudget?: ToolBudgetConfig;\n}\n\nexport interface ChainConfig {\n\tname: string;\n\tlocalName?: string;\n\tpackageName?: string;\n\tdescription: string;\n\tsource: AgentSource;\n\tfilePath: string;\n\tsteps: ChainStepConfig[];\n\textraFields?: Record<string, string>;\n}\n\nexport interface ChainDiscoveryDiagnostic {\n\tsource: AgentSource;\n\tfilePath: string;\n\terror: string;\n}\n\ninterface AgentDiscoveryResult {\n\tagents: AgentConfig[];\n\tprojectAgentsDir: string | null;\n\tmodelScope?: ModelScopeConfig;\n}\n\nfunction getUserChainDir(): string {\n\treturn path.join(getAgentDir(), \"chains\");\n}\n\ninterface PackageSubagentPaths {\n\tagents: string[];\n\tchains: string[];\n}\n\nlet cachedGlobalNpmRoot: string | null = null;\n\nfunction readJsonFileBestEffort(filePath: string): unknown {\n\ttry {\n\t\treturn JSON.parse(fs.readFileSync(filePath, \"utf-8\"));\n\t} catch {\n\t\t// Installed package scans are opportunistic; bad third-party manifests\n\t\t// should not break local agent discovery.\n\t\treturn null;\n\t}\n}\n\nfunction readOptionalJsonFile(filePath: string): unknown {\n\ttry {\n\t\treturn JSON.parse(fs.readFileSync(filePath, \"utf-8\"));\n\t} catch (error) {\n\t\tconst code =\n\t\t\ttypeof error === \"object\" && error !== null && \"code\" in error\n\t\t\t\t? (error as { code?: unknown }).code\n\t\t\t\t: undefined;\n\t\tif (code === \"ENOENT\") return null;\n\t\tthrow error;\n\t}\n}\n\nfunction isSafePackagePath(value: string): boolean {\n\treturn (\n\t\tvalue.length > 0 &&\n\t\t!path.isAbsolute(value) &&\n\t\tvalue.split(/[\\\\/]/).every((part) => part.length > 0 && part !== \".\" && part !== \"..\")\n\t);\n}\n\nfunction parseNpmPackageName(source: string): string | undefined {\n\tconst spec = source.slice(4).trim();\n\tif (!spec) return undefined;\n\tconst match = spec.match(/^(@?[^@]+(?:\\/[^@]+)?)(?:@(.+))?$/);\n\tconst packageName = match?.[1] ?? spec;\n\treturn isSafePackagePath(packageName) ? packageName : undefined;\n}\n\nfunction stripGitRef(repoPath: string): string {\n\tconst atIndex = repoPath.indexOf(\"@\");\n\tconst hashIndex = repoPath.indexOf(\"#\");\n\tconst refIndex = [atIndex, hashIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];\n\treturn refIndex === undefined ? repoPath : repoPath.slice(0, refIndex);\n}\n\nfunction parseGitPackagePath(source: string): { host: string; repoPath: string } | undefined {\n\tconst spec = source.slice(4).trim();\n\tif (!spec) return undefined;\n\n\tlet host = \"\";\n\tlet repoPath = \"\";\n\tconst scpLike = spec.match(/^git@([^:]+):(.+)$/);\n\tif (scpLike) {\n\t\thost = scpLike[1] ?? \"\";\n\t\trepoPath = scpLike[2] ?? \"\";\n\t} else if (/^[a-z][a-z0-9+.-]*:\\/\\//i.test(spec)) {\n\t\ttry {\n\t\t\tconst url = new URL(spec);\n\t\t\thost = url.hostname;\n\t\t\trepoPath = url.pathname.replace(/^\\/+/, \"\");\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t} else {\n\t\tconst slashIndex = spec.indexOf(\"/\");\n\t\tif (slashIndex < 0) return undefined;\n\t\thost = spec.slice(0, slashIndex);\n\t\trepoPath = spec.slice(slashIndex + 1);\n\t}\n\n\tconst normalizedPath = stripGitRef(repoPath)\n\t\t.replace(/\\.git$/, \"\")\n\t\t.replace(/^\\/+/, \"\");\n\tif (\n\t\t!host ||\n\t\t!isSafePackagePath(host) ||\n\t\t!isSafePackagePath(normalizedPath) ||\n\t\tnormalizedPath.split(/[\\\\/]/).length < 2\n\t) {\n\t\treturn undefined;\n\t}\n\treturn { host, repoPath: normalizedPath };\n}\n\nfunction resolveSettingsPackageRoot(source: string, baseDir: string): string | undefined {\n\tconst trimmed = source.trim();\n\tif (!trimmed) return undefined;\n\tif (trimmed.startsWith(\"git:\")) {\n\t\tconst parsed = parseGitPackagePath(trimmed);\n\t\treturn parsed ? path.join(baseDir, \"git\", parsed.host, parsed.repoPath) : undefined;\n\t}\n\tif (trimmed.startsWith(\"npm:\")) {\n\t\tconst packageName = parseNpmPackageName(trimmed);\n\t\treturn packageName ? path.join(baseDir, \"npm\", \"node_modules\", packageName) : undefined;\n\t}\n\tconst normalized = trimmed.startsWith(\"file:\") ? trimmed.slice(5) : trimmed;\n\tif (normalized === \"~\") return os.homedir();\n\tif (normalized.startsWith(\"~/\")) return path.join(os.homedir(), normalized.slice(2));\n\tif (path.isAbsolute(normalized)) return normalized;\n\tif (normalized === \".\" || normalized === \"..\" || normalized.startsWith(\"./\") || normalized.startsWith(\"../\")) {\n\t\treturn path.resolve(baseDir, normalized);\n\t}\n\treturn undefined;\n}\n\nfunction getGlobalNpmRoot(): string | null {\n\tconst offline = process.env.PI_OFFLINE?.toLowerCase();\n\tif (offline === \"1\" || offline === \"true\" || offline === \"yes\") return null;\n\tif (cachedGlobalNpmRoot !== null) return cachedGlobalNpmRoot;\n\n\tconst windowsGlobalRoot =\n\t\tprocess.platform === \"win32\" && process.env.APPDATA\n\t\t\t? path.join(process.env.APPDATA, \"npm\", \"node_modules\")\n\t\t\t: undefined;\n\tif (windowsGlobalRoot) {\n\t\ttry {\n\t\t\tif (fs.statSync(windowsGlobalRoot).isDirectory()) {\n\t\t\t\tcachedGlobalNpmRoot = fs.realpathSync(windowsGlobalRoot);\n\t\t\t\treturn cachedGlobalNpmRoot;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Fall through if the directory disappears while resolving it.\n\t\t}\n\t}\n\n\ttry {\n\t\tcachedGlobalNpmRoot = fs.realpathSync(execSync(\"npm root -g\", { encoding: \"utf-8\", timeout: 15_000 }).trim());\n\t\treturn cachedGlobalNpmRoot;\n\t} catch {\n\t\tcachedGlobalNpmRoot = \"\";\n\t\treturn null;\n\t}\n}\n\nfunction stringArray(value: unknown): string[] {\n\tif (!Array.isArray(value)) return [];\n\treturn value.filter((entry): entry is string => typeof entry === \"string\" && entry.trim().length > 0);\n}\n\nfunction extractSubagentPathsFromPackageRoot(packageRoot: string): PackageSubagentPaths {\n\tconst packageJsonPath = path.join(packageRoot, \"package.json\");\n\tconst pkg = readJsonFileBestEffort(packageJsonPath);\n\tif (!pkg || typeof pkg !== \"object\" || Array.isArray(pkg)) return { agents: [], chains: [] };\n\n\tconst roots: Record<string, unknown>[] = [];\n\tconst piSubagents = (pkg as { \"pi-subagents\"?: unknown })[\"pi-subagents\"];\n\tif (piSubagents && typeof piSubagents === \"object\" && !Array.isArray(piSubagents)) {\n\t\troots.push(piSubagents as Record<string, unknown>);\n\t}\n\n\tconst pi = (pkg as { pi?: unknown }).pi;\n\tif (pi && typeof pi === \"object\" && !Array.isArray(pi)) {\n\t\tconst subagents = (pi as { subagents?: unknown }).subagents;\n\t\tif (subagents && typeof subagents === \"object\" && !Array.isArray(subagents)) {\n\t\t\troots.push(subagents as Record<string, unknown>);\n\t\t}\n\t}\n\n\tconst agents: string[] = [];\n\tconst chains: string[] = [];\n\tfor (const root of roots) {\n\t\tfor (const entry of stringArray(root.agents)) agents.push(path.resolve(packageRoot, entry));\n\t\tfor (const entry of stringArray(root.chains)) chains.push(path.resolve(packageRoot, entry));\n\t}\n\treturn { agents, chains };\n}\n\nfunction collectPackageRootsFromNodeModules(nodeModulesDir: string): string[] {\n\tconst roots: string[] = [];\n\tif (!fs.existsSync(nodeModulesDir)) return roots;\n\n\tlet entries: fs.Dirent[];\n\ttry {\n\t\tentries = fs.readdirSync(nodeModulesDir, { withFileTypes: true });\n\t} catch {\n\t\treturn roots;\n\t}\n\n\tfor (const entry of entries) {\n\t\tif (entry.name.startsWith(\".\")) continue;\n\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n\n\t\tif (entry.name.startsWith(\"@\")) {\n\t\t\tconst scopeDir = path.join(nodeModulesDir, entry.name);\n\t\t\tlet scopeEntries: fs.Dirent[];\n\t\t\ttry {\n\t\t\t\tscopeEntries = fs.readdirSync(scopeDir, { withFileTypes: true });\n\t\t\t} catch {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfor (const scopeEntry of scopeEntries) {\n\t\t\t\tif (scopeEntry.name.startsWith(\".\")) continue;\n\t\t\t\tif (!scopeEntry.isDirectory() && !scopeEntry.isSymbolicLink()) continue;\n\t\t\t\troots.push(path.join(scopeDir, scopeEntry.name));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\troots.push(path.join(nodeModulesDir, entry.name));\n\t}\n\treturn roots;\n}\n\nfunction collectSettingsPackageRoots(settingsFile: string, baseDir: string): string[] {\n\tconst settings = readOptionalJsonFile(settingsFile);\n\tif (!settings || typeof settings !== \"object\" || Array.isArray(settings)) return [];\n\tconst packages = (settings as { packages?: unknown }).packages;\n\tif (!Array.isArray(packages)) return [];\n\n\tconst roots: string[] = [];\n\tfor (const entry of packages) {\n\t\tconst packageSource =\n\t\t\ttypeof entry === \"string\"\n\t\t\t\t? entry\n\t\t\t\t: typeof entry === \"object\" && entry !== null && typeof (entry as { source?: unknown }).source === \"string\"\n\t\t\t\t\t? (entry as { source: string }).source\n\t\t\t\t\t: undefined;\n\t\tif (!packageSource) continue;\n\t\tconst packageRoot = resolveSettingsPackageRoot(packageSource, baseDir);\n\t\tif (packageRoot) roots.push(packageRoot);\n\t}\n\treturn roots;\n}\n\nfunction collectPackageSubagentPaths(\n\tcwd: string,\n\toptions: { includeUser: boolean; includeProject: boolean } = { includeUser: true, includeProject: true },\n): PackageSubagentPaths {\n\tconst agentDir = getAgentDir();\n\tconst packageRoot = findConfiguredProjectRoot(cwd) ?? cwd;\n\tconst packageRoots = fs.existsSync(path.join(cwd, \"package.json\")) ? [cwd, packageRoot] : [packageRoot];\n\n\tif (options.includeProject) {\n\t\tconst projectConfigDir = getProjectConfigDir(packageRoot);\n\t\tpackageRoots.push(\n\t\t\t...collectPackageRootsFromNodeModules(path.join(projectConfigDir, \"npm\", \"node_modules\")),\n\t\t\t...collectSettingsPackageRoots(path.join(projectConfigDir, \"settings.json\"), projectConfigDir),\n\t\t);\n\t}\n\n\tif (options.includeUser) {\n\t\tpackageRoots.push(\n\t\t\t...collectPackageRootsFromNodeModules(path.join(agentDir, \"npm\", \"node_modules\")),\n\t\t\t...collectSettingsPackageRoots(path.join(agentDir, \"settings.json\"), agentDir),\n\t\t);\n\t}\n\n\tif (options.includeUser) {\n\t\tconst globalRoot = getGlobalNpmRoot();\n\t\tif (globalRoot) packageRoots.push(...collectPackageRootsFromNodeModules(globalRoot));\n\t}\n\n\tconst seenRoots = new Set<string>();\n\tconst seenAgents = new Set<string>();\n\tconst seenChains = new Set<string>();\n\tconst agents: string[] = [];\n\tconst chains: string[] = [];\n\tfor (const packageRoot of packageRoots) {\n\t\tconst resolvedRoot = path.resolve(packageRoot);\n\t\tif (seenRoots.has(resolvedRoot)) continue;\n\t\tseenRoots.add(resolvedRoot);\n\t\tconst paths = extractSubagentPathsFromPackageRoot(resolvedRoot);\n\t\tfor (const agentDir of paths.agents) {\n\t\t\tif (seenAgents.has(agentDir)) continue;\n\t\t\tseenAgents.add(agentDir);\n\t\t\tagents.push(agentDir);\n\t\t}\n\t\tfor (const chainDir of paths.chains) {\n\t\t\tif (seenChains.has(chainDir)) continue;\n\t\t\tseenChains.add(chainDir);\n\t\t\tchains.push(chainDir);\n\t\t}\n\t}\n\treturn { agents, chains };\n}\n\nfunction normalizeAgentAliases(rawAliases: string[] | undefined, agentName: string): string[] | undefined {\n\tconst aliases = [...new Set((rawAliases ?? []).map((alias) => alias.trim()).filter(Boolean))].filter(\n\t\t(alias) => alias !== agentName,\n\t);\n\treturn aliases.length > 0 ? aliases : undefined;\n}\n\nfunction effectiveAgentMatch(matches: AgentConfig[]): { agent?: AgentConfig; error?: string } {\n\tconst distinctNames = [...new Set(matches.map((agent) => agent.name))];\n\tif (distinctNames.length === 1) {\n\t\tconst sourceRank = new Map<AgentConfig[\"source\"], number>([\n\t\t\t[\"builtin\", 0],\n\t\t\t[\"package\", 1],\n\t\t\t[\"user\", 2],\n\t\t\t[\"project\", 3],\n\t\t]);\n\t\tconst agent = [...matches].sort((a, b) => (sourceRank.get(b.source) ?? 0) - (sourceRank.get(a.source) ?? 0))[0];\n\t\treturn agent ? { agent } : {};\n\t}\n\treturn {};\n}\n\nexport function resolveAgentName(name: string, agents: AgentConfig[]): { agent?: AgentConfig; error?: string } {\n\tconst raw = name.trim();\n\tconst exact = agents.filter((agent) => agent.name === raw || agent.localName === raw);\n\tif (exact.length === 1) return exact[0] ? { agent: exact[0] } : {};\n\tif (exact.length > 1) {\n\t\tconst effective = effectiveAgentMatch(exact);\n\t\tif (effective.agent) return effective;\n\t\treturn { error: `Ambiguous agent name '${name}': ${exact.map((agent) => agent.name).join(\", \")}` };\n\t}\n\n\tconst aliases = agents.filter((agent) => agent.aliases?.includes(raw));\n\tif (aliases.length === 1) return aliases[0] ? { agent: aliases[0] } : {};\n\tif (aliases.length > 1) {\n\t\tconst effective = effectiveAgentMatch(aliases);\n\t\tif (effective.agent) return effective;\n\t\treturn { error: `Ambiguous agent alias '${name}': ${aliases.map((agent) => agent.name).join(\", \")}` };\n\t}\n\treturn {};\n}\n\nfunction splitToolList(rawTools: string[] | undefined): { tools?: string[]; mcpDirectTools?: string[] } {\n\tconst mcpDirectTools: string[] = [];\n\tconst tools: string[] = [];\n\tfor (const tool of rawTools ?? []) {\n\t\tif (tool.startsWith(\"mcp:\")) {\n\t\t\tmcpDirectTools.push(tool.slice(4));\n\t\t} else {\n\t\t\ttools.push(tool);\n\t\t}\n\t}\n\treturn {\n\t\t...(rawTools !== undefined ? { tools } : {}),\n\t\t...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),\n\t};\n}\n\nfunction joinToolList(config: Pick<AgentConfig, \"tools\" | \"mcpDirectTools\">): string[] | undefined {\n\tconst joined = [...(config.tools ?? []), ...(config.mcpDirectTools ?? []).map((tool) => `mcp:${tool}`)];\n\treturn joined.length > 0 ? joined : undefined;\n}\n\nfunction arraysEqual(a: string[] | undefined, b: string[] | undefined): boolean {\n\tif (!a && !b) return true;\n\tif (!a || !b) return false;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i++) {\n\t\tif (a[i] !== b[i]) return false;\n\t}\n\treturn true;\n}\n\nfunction cloneOverrideBase(agent: AgentConfig): BuiltinAgentOverrideBase {\n\treturn {\n\t\tdescription: agent.description,\n\t\t...(agent.model !== undefined ? { model: agent.model } : {}),\n\t\t...(agent.fallbackModels ? { fallbackModels: [...agent.fallbackModels] } : {}),\n\t\t...(agent.thinking !== undefined ? { thinking: agent.thinking } : {}),\n\t\tsystemPromptMode: agent.systemPromptMode,\n\t\tinheritProjectContext: agent.inheritProjectContext,\n\t\tinheritSkills: agent.inheritSkills,\n\t\t...(agent.defaultContext !== undefined ? { defaultContext: agent.defaultContext } : {}),\n\t\t...(agent.acceptanceRole !== undefined ? { acceptanceRole: agent.acceptanceRole } : {}),\n\t\t...(agent.disabled !== undefined ? { disabled: agent.disabled } : {}),\n\t\tsystemPrompt: agent.systemPrompt,\n\t\t...(agent.skills ? { skills: [...agent.skills] } : {}),\n\t\t...(agent.skillPath ? { skillPath: [...agent.skillPath] } : {}),\n\t\t...(agent.tools ? { tools: [...agent.tools] } : {}),\n\t\t...(agent.mcpDirectTools ? { mcpDirectTools: [...agent.mcpDirectTools] } : {}),\n\t\t...(!agent.extensionsFromDefault && agent.extensions ? { extensions: [...agent.extensions] } : {}),\n\t\t...(agent.subagentOnlyExtensions ? { subagentOnlyExtensions: [...agent.subagentOnlyExtensions] } : {}),\n\t\t...(agent.completionGuard !== undefined ? { completionGuard: agent.completionGuard } : {}),\n\t\t...(agent.toolBudget !== undefined ? { toolBudget: agent.toolBudget } : {}),\n\t};\n}\n\nfunction cloneOverrideValue(override: BuiltinAgentOverrideConfig): BuiltinAgentOverrideConfig {\n\treturn {\n\t\t...(override.description !== undefined ? { description: override.description } : {}),\n\t\t...(override.model !== undefined ? { model: override.model } : {}),\n\t\t...(override.fallbackModels !== undefined\n\t\t\t? { fallbackModels: override.fallbackModels === false ? false : [...override.fallbackModels] }\n\t\t\t: {}),\n\t\t...(override.thinking !== undefined ? { thinking: override.thinking } : {}),\n\t\t...(override.systemPromptMode !== undefined ? { systemPromptMode: override.systemPromptMode } : {}),\n\t\t...(override.inheritProjectContext !== undefined\n\t\t\t? { inheritProjectContext: override.inheritProjectContext }\n\t\t\t: {}),\n\t\t...(override.inheritSkills !== undefined ? { inheritSkills: override.inheritSkills } : {}),\n\t\t...(override.defaultContext !== undefined ? { defaultContext: override.defaultContext } : {}),\n\t\t...(override.acceptanceRole !== undefined ? { acceptanceRole: override.acceptanceRole } : {}),\n\t\t...(override.disabled !== undefined ? { disabled: override.disabled } : {}),\n\t\t...(override.systemPrompt !== undefined ? { systemPrompt: override.systemPrompt } : {}),\n\t\t...(override.skills !== undefined ? { skills: override.skills === false ? false : [...override.skills] } : {}),\n\t\t...(override.tools !== undefined ? { tools: override.tools === false ? false : [...override.tools] } : {}),\n\t\t...(override.extensions !== undefined\n\t\t\t? { extensions: override.extensions === false ? false : [...override.extensions] }\n\t\t\t: {}),\n\t\t...(override.subagentOnlyExtensions !== undefined\n\t\t\t? {\n\t\t\t\t\tsubagentOnlyExtensions:\n\t\t\t\t\t\toverride.subagentOnlyExtensions === false ? false : [...override.subagentOnlyExtensions],\n\t\t\t\t}\n\t\t\t: {}),\n\t\t...(override.completionGuard !== undefined ? { completionGuard: override.completionGuard } : {}),\n\t\t...(override.toolBudget !== undefined\n\t\t\t? {\n\t\t\t\t\ttoolBudget:\n\t\t\t\t\t\toverride.toolBudget === false\n\t\t\t\t\t\t\t? false\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\t...override.toolBudget,\n\t\t\t\t\t\t\t\t\t...(Array.isArray(override.toolBudget.block)\n\t\t\t\t\t\t\t\t\t\t? { block: [...override.toolBudget.block] }\n\t\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\n\nfunction isProjectRootCandidate(dir: string): boolean {\n\treturn isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, \".agents\"));\n}\n\nfunction findProjectRootCandidates(cwd: string): string[] {\n\tconst roots: string[] = [];\n\tlet currentDir = cwd;\n\twhile (true) {\n\t\tif (isProjectRootCandidate(currentDir)) roots.push(currentDir);\n\n\t\tconst parentDir = path.dirname(currentDir);\n\t\tif (parentDir === currentDir) return roots;\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nfunction findNearestGitRoot(cwd: string): string | null {\n\tlet currentDir = cwd;\n\twhile (true) {\n\t\tif (fs.existsSync(path.join(currentDir, \".git\"))) return currentDir;\n\n\t\tconst parentDir = path.dirname(currentDir);\n\t\tif (parentDir === currentDir) return null;\n\t\tcurrentDir = parentDir;\n\t}\n}\n\nfunction readProjectRootResolution(projectRoot: string): ProjectRootResolution | undefined {\n\tconst settingsPath = path.join(getProjectConfigDir(projectRoot), \"settings.json\");\n\tif (!fs.existsSync(settingsPath)) return undefined;\n\tconst settings = readSettingsFileStrict(settingsPath);\n\tconst subagents = settings.subagents;\n\tif (!subagents || typeof subagents !== \"object\" || Array.isArray(subagents)) return undefined;\n\n\tconst value = (subagents as Record<string, unknown>).projectRootResolution;\n\tif (value === undefined) return undefined;\n\tif (value === \"nearest\" || value === \"git-root\") return value;\n\tthrow new Error(\n\t\t`Subagent settings in '${settingsPath}' have invalid 'projectRootResolution'; expected 'nearest' or 'git-root'.`,\n\t);\n}\n\nexport function findNearestProjectRoot(cwd: string): string | null {\n\treturn findProjectRootCandidates(cwd)[0] ?? null;\n}\n\nfunction findConfiguredProjectRoot(cwd: string): string | null {\n\tconst candidates = findProjectRootCandidates(cwd);\n\tconst nearestRoot = candidates[0];\n\tif (!nearestRoot) return null;\n\n\tconst nearestMode = readProjectRootResolution(nearestRoot);\n\tif (nearestMode === \"nearest\") return nearestRoot;\n\n\tconst gitRoot = findNearestGitRoot(cwd);\n\tconst gitProjectRoot = gitRoot\n\t\t? candidates.find((candidate) => path.resolve(candidate) === path.resolve(gitRoot))\n\t\t: undefined;\n\tif (gitProjectRoot && (nearestMode === \"git-root\" || readProjectRootResolution(gitProjectRoot) === \"git-root\")) {\n\t\treturn gitProjectRoot;\n\t}\n\n\treturn nearestRoot;\n}\n\nfunction getUserAgentSettingsPath(): string {\n\treturn path.join(getAgentDir(), \"settings.json\");\n}\n\nfunction getProjectAgentSettingsPath(cwd: string): string | null {\n\tconst projectRoot = findConfiguredProjectRoot(cwd);\n\treturn projectRoot ? path.join(getProjectConfigDir(projectRoot), \"settings.json\") : null;\n}\n\nfunction readSettingsFileStrict(filePath: string): Record<string, unknown> {\n\tif (!fs.existsSync(filePath)) return {};\n\tlet raw: string;\n\ttry {\n\t\traw = fs.readFileSync(filePath, \"utf-8\");\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Failed to read settings file '${filePath}': ${message}`, { cause: error });\n\t}\n\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tthrow new Error(`Failed to parse settings file '${filePath}': ${message}`, { cause: error });\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Settings file '${filePath}' must contain a JSON object.`);\n\t}\n\treturn parsed as Record<string, unknown>;\n}\n\nfunction writeSettingsFile(filePath: string, settings: Record<string, unknown>): void {\n\tfs.mkdirSync(path.dirname(filePath), { recursive: true });\n\tfs.writeFileSync(filePath, `${JSON.stringify(settings, null, 2)}\\n`, \"utf-8\");\n}\n\nfunction parseOverrideStringArrayOrFalse(\n\tvalue: unknown,\n\tmeta: { filePath: string; name: string; field: string },\n): string[] | false | undefined {\n\tif (value === undefined) return undefined;\n\tif (value === false) return false;\n\tif (!Array.isArray(value)) {\n\t\tthrow new Error(\n\t\t\t`Builtin override '${meta.name}' in '${meta.filePath}' has invalid '${meta.field}'; expected an array of strings or false.`,\n\t\t);\n\t}\n\n\tconst items: string[] = [];\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${meta.name}' in '${meta.filePath}' has invalid '${meta.field}'; expected an array of strings or false.`,\n\t\t\t);\n\t\t}\n\t\tconst trimmed = item.trim();\n\t\tif (trimmed) items.push(trimmed);\n\t}\n\treturn items;\n}\n\nfunction parseBuiltinOverrideEntry(\n\tname: string,\n\tvalue: unknown,\n\tfilePath: string,\n): BuiltinAgentOverrideConfig | undefined {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(`Builtin override '${name}' in '${filePath}' must be an object.`);\n\t}\n\n\tconst input = value as Record<string, unknown>;\n\tconst override: BuiltinAgentOverrideConfig = {};\n\n\tif (\"description\" in input) {\n\t\tif (typeof input.description === \"string\" && input.description.trim()) {\n\t\t\toverride.description = input.description.trim();\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'description'; expected a non-empty string.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"model\" in input) {\n\t\tif (typeof input.model === \"string\" || input.model === false) override.model = input.model;\n\t\telse\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'model'; expected a string or false.`,\n\t\t\t);\n\t}\n\n\tif (\"thinking\" in input) {\n\t\tif (typeof input.thinking === \"string\" || input.thinking === false) override.thinking = input.thinking;\n\t\telse\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'thinking'; expected a string or false.`,\n\t\t\t);\n\t}\n\n\tif (\"systemPromptMode\" in input) {\n\t\tif (input.systemPromptMode === \"append\" || input.systemPromptMode === \"replace\") {\n\t\t\toverride.systemPromptMode = input.systemPromptMode;\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'systemPromptMode'; expected 'append' or 'replace'.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"inheritProjectContext\" in input) {\n\t\tif (typeof input.inheritProjectContext === \"boolean\") {\n\t\t\toverride.inheritProjectContext = input.inheritProjectContext;\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'inheritProjectContext'; expected a boolean.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"inheritSkills\" in input) {\n\t\tif (typeof input.inheritSkills === \"boolean\") {\n\t\t\toverride.inheritSkills = input.inheritSkills;\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'inheritSkills'; expected a boolean.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"defaultContext\" in input) {\n\t\tif (input.defaultContext === \"fresh\" || input.defaultContext === \"fork\" || input.defaultContext === false) {\n\t\t\toverride.defaultContext = input.defaultContext;\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'defaultContext'; expected 'fresh', 'fork', or false.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"acceptanceRole\" in input) {\n\t\tif (input.acceptanceRole === \"read-only\" || input.acceptanceRole === \"writer\" || input.acceptanceRole === false) {\n\t\t\toverride.acceptanceRole = input.acceptanceRole;\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'acceptanceRole'; expected 'read-only', 'writer', or false.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"disabled\" in input) {\n\t\tif (typeof input.disabled === \"boolean\") {\n\t\t\toverride.disabled = input.disabled;\n\t\t} else {\n\t\t\tthrow new Error(`Builtin override '${name}' in '${filePath}' has invalid 'disabled'; expected a boolean.`);\n\t\t}\n\t}\n\n\tif (\"completionGuard\" in input) {\n\t\tif (typeof input.completionGuard === \"boolean\") {\n\t\t\toverride.completionGuard = input.completionGuard;\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'completionGuard'; expected a boolean.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"toolBudget\" in input) {\n\t\tif (input.toolBudget === false) {\n\t\t\toverride.toolBudget = false;\n\t\t} else if (input.toolBudget && typeof input.toolBudget === \"object\" && !Array.isArray(input.toolBudget)) {\n\t\t\toverride.toolBudget = input.toolBudget as ToolBudgetConfig;\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Builtin override '${name}' in '${filePath}' has invalid 'toolBudget'; expected an object or false.`,\n\t\t\t);\n\t\t}\n\t}\n\n\tif (\"systemPrompt\" in input) {\n\t\tif (typeof input.systemPrompt === \"string\") override.systemPrompt = input.systemPrompt;\n\t\telse\n\t\t\tthrow new Error(`Builtin override '${name}' in '${filePath}' has invalid 'systemPrompt'; expected a string.`);\n\t}\n\n\tconst fallbackModels = parseOverrideStringArrayOrFalse(input.fallbackModels, {\n\t\tfilePath,\n\t\tname,\n\t\tfield: \"fallbackModels\",\n\t});\n\tif (fallbackModels !== undefined) override.fallbackModels = fallbackModels;\n\n\tconst skills = parseOverrideStringArrayOrFalse(input.skills, { filePath, name, field: \"skills\" });\n\tif (skills !== undefined) override.skills = skills;\n\n\tconst tools = parseOverrideStringArrayOrFalse(input.tools, { filePath, name, field: \"tools\" });\n\tif (tools !== undefined) override.tools = tools;\n\n\tconst extensions = parseOverrideStringArrayOrFalse(input.extensions, { filePath, name, field: \"extensions\" });\n\tif (extensions !== undefined) override.extensions = extensions;\n\n\tconst subagentOnlyExtensions = parseOverrideStringArrayOrFalse(input.subagentOnlyExtensions, {\n\t\tfilePath,\n\t\tname,\n\t\tfield: \"subagentOnlyExtensions\",\n\t});\n\tif (subagentOnlyExtensions !== undefined) override.subagentOnlyExtensions = subagentOnlyExtensions;\n\n\treturn Object.keys(override).length > 0 ? override : undefined;\n}\n\nfunction readSubagentSettings(filePath: string | null): SubagentSettings {\n\tif (!filePath) return EMPTY_SUBAGENT_SETTINGS;\n\tconst settings = readSettingsFileStrict(filePath);\n\tconst subagents = settings.subagents;\n\tif (!subagents || typeof subagents !== \"object\" || Array.isArray(subagents)) return EMPTY_SUBAGENT_SETTINGS;\n\n\tconst subagentsObject = subagents as Record<string, unknown>;\n\tlet disableBuiltins: boolean | undefined;\n\tif (\"disableBuiltins\" in subagentsObject) {\n\t\tif (typeof subagentsObject.disableBuiltins === \"boolean\") {\n\t\t\tdisableBuiltins = subagentsObject.disableBuiltins;\n\t\t} else {\n\t\t\tthrow new Error(`Subagent settings in '${filePath}' have invalid 'disableBuiltins'; expected a boolean.`);\n\t\t}\n\t}\n\tlet disableThinking: boolean | undefined;\n\tif (\"disableThinking\" in subagentsObject) {\n\t\tif (typeof subagentsObject.disableThinking === \"boolean\") {\n\t\t\tdisableThinking = subagentsObject.disableThinking;\n\t\t} else {\n\t\t\tthrow new Error(`Subagent settings in '${filePath}' have invalid 'disableThinking'; expected a boolean.`);\n\t\t}\n\t}\n\tlet defaultModel: string | undefined;\n\tif (\"defaultModel\" in subagentsObject) {\n\t\tif (typeof subagentsObject.defaultModel === \"string\" && subagentsObject.defaultModel.trim()) {\n\t\t\tdefaultModel = subagentsObject.defaultModel.trim();\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Subagent settings in '${filePath}' have invalid 'defaultModel'; expected a non-empty string.`,\n\t\t\t);\n\t\t}\n\t}\n\tlet defaultThinking: string | undefined;\n\tif (\"defaultThinking\" in subagentsObject) {\n\t\tif (typeof subagentsObject.defaultThinking === \"string\" && subagentsObject.defaultThinking.trim()) {\n\t\t\tdefaultThinking = subagentsObject.defaultThinking.trim();\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t`Subagent settings in '${filePath}' have invalid 'defaultThinking'; expected a non-empty string.`,\n\t\t\t);\n\t\t}\n\t}\n\tlet defaultExtensions: string[] | undefined;\n\tif (\"defaultExtensions\" in subagentsObject) {\n\t\tif (\n\t\t\t!Array.isArray(subagentsObject.defaultExtensions) ||\n\t\t\tsubagentsObject.defaultExtensions.some((item) => typeof item !== \"string\" || !item.trim())\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t`Subagent settings in '${filePath}' have invalid 'defaultExtensions'; expected an array of non-empty strings.`,\n\t\t\t);\n\t\t}\n\t\tdefaultExtensions = subagentsObject.defaultExtensions.map((item) => item.trim());\n\t}\n\tconst modelScope = parseModelScopeConfig(subagentsObject.modelScope, { filePath });\n\n\tconst parsed: Record<string, BuiltinAgentOverrideConfig> = {};\n\tconst agentOverrides = subagentsObject.agentOverrides;\n\tconst parsedSettings: SubagentSettings = {\n\t\toverrides: parsed,\n\t\t...(defaultModel !== undefined ? { defaultModel } : {}),\n\t\t...(defaultThinking !== undefined ? { defaultThinking } : {}),\n\t\t...(defaultExtensions !== undefined ? { defaultExtensions } : {}),\n\t\t...(disableBuiltins !== undefined ? { disableBuiltins } : {}),\n\t\t...(disableThinking !== undefined ? { disableThinking } : {}),\n\t\t...(modelScope !== undefined ? { modelScope } : {}),\n\t};\n\tif (!agentOverrides || typeof agentOverrides !== \"object\" || Array.isArray(agentOverrides)) {\n\t\treturn parsedSettings;\n\t}\n\tfor (const [name, value] of Object.entries(agentOverrides)) {\n\t\tconst override = parseBuiltinOverrideEntry(name, value, filePath);\n\t\tif (override) parsed[name] = override;\n\t}\n\treturn parsedSettings;\n}\n\nfunction resolveSubagentDefaultModel(\n\tuserSettings: SubagentSettings,\n\tprojectSettings: SubagentSettings,\n\tuserSettingsPath: string,\n\tprojectSettingsPath: string | null,\n): AgentModelSourceInfo | undefined {\n\tif (projectSettingsPath && projectSettings.defaultModel !== undefined) {\n\t\treturn {\n\t\t\ttype: \"subagents.defaultModel\",\n\t\t\tscope: \"project\",\n\t\t\tpath: projectSettingsPath,\n\t\t\tmodel: projectSettings.defaultModel,\n\t\t};\n\t}\n\treturn userSettings.defaultModel !== undefined\n\t\t? { type: \"subagents.defaultModel\", scope: \"user\", path: userSettingsPath, model: userSettings.defaultModel }\n\t\t: undefined;\n}\n\nfunction applySubagentDefaultModel(\n\tagents: AgentConfig[],\n\tdefaultModel: AgentModelSourceInfo | undefined,\n): AgentConfig[] {\n\tif (!defaultModel) return agents;\n\treturn agents.map((agent) => {\n\t\tif (agent.model !== undefined) return agent;\n\t\tconst next = { ...agent, model: defaultModel.model, modelSource: defaultModel };\n\t\tconst frontmatterFields = agentFrontmatterFields.get(agent);\n\t\tif (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);\n\t\treturn next;\n\t});\n}\n\nfunction resolveSubagentDefaultThinking(\n\tuserSettings: SubagentSettings,\n\tprojectSettings: SubagentSettings,\n\tprojectSettingsPath: string | null,\n): string | undefined {\n\tif (projectSettingsPath && projectSettings.defaultThinking !== undefined) return projectSettings.defaultThinking;\n\treturn userSettings.defaultThinking;\n}\n\nfunction applySubagentDefaultThinking(agents: AgentConfig[], defaultThinking: string | undefined): AgentConfig[] {\n\tif (defaultThinking === undefined) return agents;\n\treturn agents.map((agent) => {\n\t\tif (agent.thinking !== undefined) return agent;\n\t\tconst next = { ...agent, thinking: defaultThinking };\n\t\tconst frontmatterFields = agentFrontmatterFields.get(agent);\n\t\tif (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);\n\t\treturn next;\n\t});\n}\n\nfunction resolveSubagentDefaultExtensions(\n\tuserSettings: SubagentSettings,\n\tprojectSettings: SubagentSettings,\n\tprojectSettingsPath: string | null,\n): string[] | undefined {\n\tif (projectSettingsPath && projectSettings.defaultExtensions !== undefined) return projectSettings.defaultExtensions;\n\treturn userSettings.defaultExtensions;\n}\n\nfunction applySubagentDefaultExtensions(agents: AgentConfig[], defaultExtensions: string[] | undefined): AgentConfig[] {\n\tif (defaultExtensions === undefined) return agents;\n\treturn agents.map((agent) => {\n\t\tif (agent.extensions !== undefined) return agent;\n\t\tconst next = { ...agent, extensions: [...defaultExtensions], extensionsFromDefault: true };\n\t\tconst frontmatterFields = agentFrontmatterFields.get(agent);\n\t\tif (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);\n\t\treturn next;\n\t});\n}\n\nfunction applySubagentDefaults(\n\tagents: AgentConfig[],\n\tdefaultModel: AgentModelSourceInfo | undefined,\n\tdefaultThinking: string | undefined,\n\tdefaultExtensions: string[] | undefined,\n): AgentConfig[] {\n\treturn applySubagentDefaultExtensions(\n\t\tapplySubagentDefaultThinking(applySubagentDefaultModel(agents, defaultModel), defaultThinking),\n\t\tdefaultExtensions,\n\t);\n}\n\nfunction applyBuiltinOverride(\n\tagent: AgentConfig,\n\toverride: BuiltinAgentOverrideConfig,\n\tmeta: { scope: \"user\" | \"project\"; path: string },\n): AgentConfig {\n\tconst next: AgentConfig = {\n\t\t...agent,\n\t\toverride: { ...meta, base: cloneOverrideBase(agent) },\n\t};\n\n\tif (override.description !== undefined) next.description = override.description;\n\tif (override.model !== undefined) {\n\t\tif (override.model === false) delete next.model;\n\t\telse next.model = override.model;\n\t}\n\tif (override.fallbackModels !== undefined) {\n\t\tif (override.fallbackModels === false) delete next.fallbackModels;\n\t\telse next.fallbackModels = [...override.fallbackModels];\n\t}\n\tif (override.thinking !== undefined) {\n\t\tif (override.thinking === false) delete next.thinking;\n\t\telse next.thinking = override.thinking;\n\t}\n\tif (override.systemPromptMode !== undefined) next.systemPromptMode = override.systemPromptMode;\n\tif (override.inheritProjectContext !== undefined) next.inheritProjectContext = override.inheritProjectContext;\n\tif (override.inheritSkills !== undefined) next.inheritSkills = override.inheritSkills;\n\tif (override.defaultContext !== undefined) {\n\t\tif (override.defaultContext === false) delete next.defaultContext;\n\t\telse next.defaultContext = override.defaultContext;\n\t}\n\tif (override.acceptanceRole !== undefined) {\n\t\tif (override.acceptanceRole === false) delete next.acceptanceRole;\n\t\telse next.acceptanceRole = override.acceptanceRole;\n\t}\n\tif (override.disabled !== undefined) next.disabled = override.disabled;\n\tif (override.systemPrompt !== undefined) next.systemPrompt = override.systemPrompt;\n\tif (override.skills !== undefined) {\n\t\tif (override.skills === false) delete next.skills;\n\t\telse next.skills = [...override.skills];\n\t}\n\tif (override.tools !== undefined) {\n\t\tconst { tools, mcpDirectTools } = splitToolList(override.tools === false ? [] : override.tools);\n\t\tif (tools === undefined) delete next.tools;\n\t\telse next.tools = tools;\n\t\tif (mcpDirectTools === undefined) delete next.mcpDirectTools;\n\t\telse next.mcpDirectTools = mcpDirectTools;\n\t}\n\tif (override.extensions !== undefined) {\n\t\tif (override.extensions === false) delete next.extensions;\n\t\telse next.extensions = [...override.extensions];\n\t}\n\tif (override.subagentOnlyExtensions !== undefined) {\n\t\tif (override.subagentOnlyExtensions === false) delete next.subagentOnlyExtensions;\n\t\telse next.subagentOnlyExtensions = [...override.subagentOnlyExtensions];\n\t}\n\tif (override.completionGuard !== undefined) next.completionGuard = override.completionGuard;\n\tif (override.toolBudget !== undefined) {\n\t\tif (override.toolBudget === false) delete next.toolBudget;\n\t\telse next.toolBudget = override.toolBudget;\n\t}\n\n\treturn next;\n}\n\nfunction clearBuiltinThinking(agent: AgentConfig, meta: { scope: \"user\" | \"project\"; path: string }): AgentConfig {\n\tif (agent.thinking === undefined) return agent;\n\tconst { thinking: _thinking, ...next } = agent;\n\treturn { ...next, override: agent.override ?? { ...meta, base: cloneOverrideBase(agent) } };\n}\n\nfunction applyBuiltinOverrides(\n\tbuiltinAgents: AgentConfig[],\n\tuserSettings: SubagentSettings,\n\tprojectSettings: SubagentSettings,\n\tuserSettingsPath: string,\n\tprojectSettingsPath: string | null,\n): AgentConfig[] {\n\tconst projectBulkDisabled = projectSettings.disableBuiltins === true && projectSettingsPath !== null;\n\tconst userBulkDisabled = projectSettings.disableBuiltins === undefined && userSettings.disableBuiltins === true;\n\tconst projectThinkingConfigured = projectSettings.disableThinking !== undefined && projectSettingsPath !== null;\n\tconst disableThinking = projectThinkingConfigured\n\t\t? projectSettings.disableThinking === true\n\t\t: userSettings.disableThinking === true;\n\tconst disableThinkingMeta = projectThinkingConfigured\n\t\t? { scope: \"project\" as const, path: projectSettingsPath! }\n\t\t: { scope: \"user\" as const, path: userSettingsPath };\n\n\tconst applyGlobalThinking = (agent: AgentConfig, hasExplicitThinkingOverride: boolean): AgentConfig => {\n\t\tif (!disableThinking || hasExplicitThinkingOverride) return agent;\n\t\treturn clearBuiltinThinking(agent, disableThinkingMeta);\n\t};\n\n\treturn builtinAgents.map((agent) => {\n\t\tconst projectOverride = projectSettings.overrides[agent.name];\n\t\tif (projectOverride && projectSettingsPath) {\n\t\t\treturn applyGlobalThinking(\n\t\t\t\tapplyBuiltinOverride(agent, projectOverride, { scope: \"project\", path: projectSettingsPath }),\n\t\t\t\tprojectOverride.thinking !== undefined,\n\t\t\t);\n\t\t}\n\n\t\tif (projectBulkDisabled && projectSettingsPath) {\n\t\t\treturn applyGlobalThinking(\n\t\t\t\tapplyBuiltinOverride(agent, { disabled: true }, { scope: \"project\", path: projectSettingsPath }),\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\n\t\tconst userOverride = userSettings.overrides[agent.name];\n\t\tif (userOverride) {\n\t\t\treturn applyGlobalThinking(\n\t\t\t\tapplyBuiltinOverride(agent, userOverride, { scope: \"user\", path: userSettingsPath }),\n\t\t\t\t!projectThinkingConfigured && userOverride.thinking !== undefined,\n\t\t\t);\n\t\t}\n\n\t\tif (userBulkDisabled) {\n\t\t\treturn applyGlobalThinking(\n\t\t\t\tapplyBuiltinOverride(agent, { disabled: true }, { scope: \"user\", path: userSettingsPath }),\n\t\t\t\tfalse,\n\t\t\t);\n\t\t}\n\n\t\treturn applyGlobalThinking(agent, false);\n\t});\n}\n\nexport function agentHasFrontmatterField(agent: AgentConfig, ...fields: string[]): boolean {\n\tconst frontmatterFields = agentFrontmatterFields.get(agent);\n\treturn frontmatterFields ? fields.some((field) => frontmatterFields.has(field)) : false;\n}\n\nfunction applyCustomAgentOverride(\n\tagent: AgentConfig,\n\toverride: BuiltinAgentOverrideConfig,\n\tmeta: { scope: \"user\" | \"project\"; path: string },\n): AgentConfig {\n\tlet next: AgentConfig | undefined;\n\tlet anyFilled = false;\n\n\tconst mutable = (): AgentConfig => {\n\t\tnext ??= { ...agent };\n\t\treturn next;\n\t};\n\n\tconst fill = <K extends keyof AgentConfig>(field: K, frontmatterFields: string[], value: AgentConfig[K]): void => {\n\t\tif (agentHasFrontmatterField(agent, ...frontmatterFields)) return;\n\t\tconst target = mutable();\n\t\tif (value === undefined) delete target[field];\n\t\telse target[field] = value;\n\t\tanyFilled = true;\n\t};\n\n\tif (override.description !== undefined) {\n\t\tmutable().description = override.description;\n\t\tanyFilled = true;\n\t}\n\tif (override.model !== undefined) {\n\t\tfill(\"model\", [\"model\"], override.model === false ? undefined : override.model);\n\t}\n\tif (override.fallbackModels !== undefined) {\n\t\tfill(\n\t\t\t\"fallbackModels\",\n\t\t\t[\"fallbackModels\"],\n\t\t\toverride.fallbackModels === false ? undefined : [...override.fallbackModels],\n\t\t);\n\t}\n\tif (override.thinking !== undefined) {\n\t\tfill(\"thinking\", [\"thinking\"], override.thinking === false ? undefined : override.thinking);\n\t}\n\tif (override.systemPromptMode !== undefined) {\n\t\tfill(\"systemPromptMode\", [\"systemPromptMode\"], override.systemPromptMode);\n\t}\n\tif (override.inheritProjectContext !== undefined) {\n\t\tfill(\"inheritProjectContext\", [\"inheritProjectContext\"], override.inheritProjectContext);\n\t}\n\tif (override.inheritSkills !== undefined) {\n\t\tfill(\"inheritSkills\", [\"inheritSkills\"], override.inheritSkills);\n\t}\n\tif (override.defaultContext !== undefined) {\n\t\tfill(\n\t\t\t\"defaultContext\",\n\t\t\t[\"defaultContext\"],\n\t\t\toverride.defaultContext === false ? undefined : override.defaultContext,\n\t\t);\n\t}\n\tif (override.acceptanceRole !== undefined) {\n\t\tfill(\n\t\t\t\"acceptanceRole\",\n\t\t\t[\"acceptanceRole\"],\n\t\t\toverride.acceptanceRole === false ? undefined : override.acceptanceRole,\n\t\t);\n\t}\n\tif (override.disabled !== undefined && agent.disabled === undefined) {\n\t\tmutable().disabled = override.disabled;\n\t\tanyFilled = true;\n\t}\n\tif (override.skills !== undefined) {\n\t\tfill(\"skills\", [\"skill\", \"skills\"], override.skills === false ? undefined : [...override.skills]);\n\t}\n\tif (override.tools !== undefined && !agentHasFrontmatterField(agent, \"tools\")) {\n\t\tconst { tools, mcpDirectTools } = splitToolList(override.tools === false ? [] : override.tools);\n\t\tconst target = mutable();\n\t\tif (tools === undefined) delete target.tools;\n\t\telse target.tools = tools;\n\t\tif (mcpDirectTools === undefined) delete target.mcpDirectTools;\n\t\telse target.mcpDirectTools = mcpDirectTools;\n\t\tanyFilled = true;\n\t}\n\tif (override.extensions !== undefined) {\n\t\tfill(\"extensions\", [\"extensions\"], override.extensions === false ? undefined : [...override.extensions]);\n\t}\n\tif (override.subagentOnlyExtensions !== undefined) {\n\t\tfill(\n\t\t\t\"subagentOnlyExtensions\",\n\t\t\t[\"subagentOnlyExtensions\"],\n\t\t\toverride.subagentOnlyExtensions === false ? undefined : [...override.subagentOnlyExtensions],\n\t\t);\n\t}\n\tif (override.completionGuard !== undefined) {\n\t\tfill(\"completionGuard\", [\"completionGuard\"], override.completionGuard);\n\t}\n\tif (override.toolBudget !== undefined) {\n\t\tfill(\"toolBudget\", [\"toolBudget\"], override.toolBudget === false ? undefined : override.toolBudget);\n\t}\n\n\tif (!anyFilled || !next) return agent;\n\tnext.override = { ...meta, base: cloneOverrideBase(agent) };\n\tconst frontmatterFields = agentFrontmatterFields.get(agent);\n\tif (frontmatterFields) agentFrontmatterFields.set(next, frontmatterFields);\n\treturn next;\n}\n\nfunction applyCustomAgentOverrides(\n\tagents: AgentConfig[],\n\tuserSettings: SubagentSettings,\n\tprojectSettings: SubagentSettings,\n\tuserSettingsPath: string,\n\tprojectSettingsPath: string | null,\n): AgentConfig[] {\n\treturn agents.map((agent) => {\n\t\tconst projectOverride = projectSettings.overrides[agent.name];\n\t\tif (projectOverride && projectSettingsPath) {\n\t\t\treturn applyCustomAgentOverride(agent, projectOverride, { scope: \"project\", path: projectSettingsPath });\n\t\t}\n\n\t\tconst userOverride = userSettings.overrides[agent.name];\n\t\tif (userOverride) {\n\t\t\treturn applyCustomAgentOverride(agent, userOverride, { scope: \"user\", path: userSettingsPath });\n\t\t}\n\n\t\treturn agent;\n\t});\n}\n\nexport function buildBuiltinOverrideConfig(\n\tbase: BuiltinAgentOverrideBase,\n\tdraft: Pick<\n\t\tAgentConfig,\n\t\t| \"model\"\n\t\t| \"fallbackModels\"\n\t\t| \"thinking\"\n\t\t| \"systemPromptMode\"\n\t\t| \"inheritProjectContext\"\n\t\t| \"inheritSkills\"\n\t\t| \"defaultContext\"\n\t\t| \"acceptanceRole\"\n\t\t| \"disabled\"\n\t\t| \"systemPrompt\"\n\t\t| \"skills\"\n\t\t| \"tools\"\n\t\t| \"mcpDirectTools\"\n\t\t| \"extensions\"\n\t\t| \"subagentOnlyExtensions\"\n\t\t| \"completionGuard\"\n\t\t| \"toolBudget\"\n\t> &\n\t\tPartial<Pick<AgentConfig, \"description\">>,\n): BuiltinAgentOverrideConfig | undefined {\n\tconst override: BuiltinAgentOverrideConfig = {};\n\n\tif (draft.description !== undefined) {\n\t\tconst description = draft.description.trim();\n\t\tif (description && description !== base.description) override.description = description;\n\t}\n\tif (draft.model !== base.model) override.model = draft.model ?? false;\n\tif (!arraysEqual(draft.fallbackModels, base.fallbackModels))\n\t\toverride.fallbackModels = draft.fallbackModels ? [...draft.fallbackModels] : false;\n\tif (draft.thinking !== base.thinking) override.thinking = draft.thinking ?? false;\n\tif (draft.systemPromptMode !== base.systemPromptMode) override.systemPromptMode = draft.systemPromptMode;\n\tif (draft.inheritProjectContext !== base.inheritProjectContext)\n\t\toverride.inheritProjectContext = draft.inheritProjectContext;\n\tif (draft.inheritSkills !== base.inheritSkills) override.inheritSkills = draft.inheritSkills;\n\tif (draft.defaultContext !== base.defaultContext) override.defaultContext = draft.defaultContext ?? false;\n\tif (draft.acceptanceRole !== base.acceptanceRole) override.acceptanceRole = draft.acceptanceRole ?? false;\n\tif (draft.disabled !== base.disabled) override.disabled = draft.disabled ?? false;\n\tif (draft.systemPrompt !== base.systemPrompt) override.systemPrompt = draft.systemPrompt;\n\tif (!arraysEqual(draft.skills, base.skills)) override.skills = draft.skills ? [...draft.skills] : false;\n\n\tconst baseTools = joinToolList(base);\n\tconst draftTools = joinToolList(draft);\n\tif (!arraysEqual(draftTools, baseTools)) override.tools = draftTools ? [...draftTools] : false;\n\tif (!arraysEqual(draft.extensions, base.extensions))\n\t\toverride.extensions = draft.extensions ? [...draft.extensions] : false;\n\tif (!arraysEqual(draft.subagentOnlyExtensions, base.subagentOnlyExtensions)) {\n\t\toverride.subagentOnlyExtensions = draft.subagentOnlyExtensions ? [...draft.subagentOnlyExtensions] : false;\n\t}\n\tif ((draft.completionGuard !== false) !== (base.completionGuard !== false)) {\n\t\toverride.completionGuard = draft.completionGuard !== false;\n\t}\n\tif (JSON.stringify(draft.toolBudget) !== JSON.stringify(base.toolBudget))\n\t\toverride.toolBudget = draft.toolBudget ?? false;\n\n\treturn Object.keys(override).length > 0 ? override : undefined;\n}\n\nexport function saveBuiltinAgentOverride(\n\tcwd: string,\n\tname: string,\n\tscope: \"user\" | \"project\",\n\toverride: BuiltinAgentOverrideConfig,\n): string {\n\tconst filePath = scope === \"project\" ? getProjectAgentSettingsPath(cwd) : getUserAgentSettingsPath();\n\tif (!filePath) throw new Error(\"Project override is not available here. No project config root was found.\");\n\n\tconst settings = readSettingsFileStrict(filePath);\n\tconst subagents =\n\t\tsettings.subagents && typeof settings.subagents === \"object\" && !Array.isArray(settings.subagents)\n\t\t\t? { ...(settings.subagents as Record<string, unknown>) }\n\t\t\t: {};\n\tconst agentOverrides =\n\t\tsubagents.agentOverrides &&\n\t\ttypeof subagents.agentOverrides === \"object\" &&\n\t\t!Array.isArray(subagents.agentOverrides)\n\t\t\t? { ...(subagents.agentOverrides as Record<string, unknown>) }\n\t\t\t: {};\n\n\tagentOverrides[name] = cloneOverrideValue(override);\n\tsubagents.agentOverrides = agentOverrides;\n\tsettings.subagents = subagents;\n\twriteSettingsFile(filePath, settings);\n\treturn filePath;\n}\n\nexport function removeBuiltinAgentOverride(\n\tcwd: string,\n\tname: string,\n\tscope: \"user\" | \"project\",\n): { path: string; removed: boolean } {\n\tconst filePath = scope === \"project\" ? getProjectAgentSettingsPath(cwd) : getUserAgentSettingsPath();\n\tif (!filePath) throw new Error(\"Project override is not available here. No project config root was found.\");\n\tif (!fs.existsSync(filePath)) return { path: filePath, removed: false };\n\n\tconst settings = readSettingsFileStrict(filePath);\n\tconst subagents = settings.subagents;\n\tif (!subagents || typeof subagents !== \"object\" || Array.isArray(subagents))\n\t\treturn { path: filePath, removed: false };\n\tconst nextSubagents = { ...(subagents as Record<string, unknown>) };\n\tconst agentOverrides = nextSubagents.agentOverrides;\n\tif (!agentOverrides || typeof agentOverrides !== \"object\" || Array.isArray(agentOverrides))\n\t\treturn { path: filePath, removed: false };\n\n\tconst nextOverrides = { ...(agentOverrides as Record<string, unknown>) };\n\tif (!Object.hasOwn(nextOverrides, name)) return { path: filePath, removed: false };\n\tdelete nextOverrides[name];\n\tif (Object.keys(nextOverrides).length > 0) nextSubagents.agentOverrides = nextOverrides;\n\telse delete nextSubagents.agentOverrides;\n\n\tif (Object.keys(nextSubagents).length > 0) settings.subagents = nextSubagents;\n\telse delete settings.subagents;\n\n\twriteSettingsFile(filePath, settings);\n\treturn { path: filePath, removed: true };\n}\n\nexport function mergeBuiltinAgentOverride(\n\tcwd: string,\n\tname: string,\n\tscope: \"user\" | \"project\",\n\tfields: BuiltinAgentOverrideConfig,\n): string {\n\tconst filePath = scope === \"project\" ? getProjectAgentSettingsPath(cwd) : getUserAgentSettingsPath();\n\tif (!filePath) throw new Error(\"Project override is not available here. No project config root was found.\");\n\n\tconst settings = readSettingsFileStrict(filePath);\n\tconst subagents =\n\t\tsettings.subagents && typeof settings.subagents === \"object\" && !Array.isArray(settings.subagents)\n\t\t\t? { ...(settings.subagents as Record<string, unknown>) }\n\t\t\t: {};\n\tconst agentOverrides =\n\t\tsubagents.agentOverrides &&\n\t\ttypeof subagents.agentOverrides === \"object\" &&\n\t\t!Array.isArray(subagents.agentOverrides)\n\t\t\t? { ...(subagents.agentOverrides as Record<string, unknown>) }\n\t\t\t: {};\n\n\tconst existing = agentOverrides[name];\n\tconst base =\n\t\texisting && typeof existing === \"object\" && !Array.isArray(existing) ? (existing as Record<string, unknown>) : {};\n\tagentOverrides[name] = { ...base, ...cloneOverrideValue(fields) };\n\tsubagents.agentOverrides = agentOverrides;\n\tsettings.subagents = subagents;\n\twriteSettingsFile(filePath, settings);\n\treturn filePath;\n}\n\nexport function removeBuiltinAgentOverrideFields(\n\tcwd: string,\n\tname: string,\n\tscope: \"user\" | \"project\",\n\tfields: string[],\n): { path: string; removed: boolean } {\n\tconst filePath = scope === \"project\" ? getProjectAgentSettingsPath(cwd) : getUserAgentSettingsPath();\n\tif (!filePath) throw new Error(\"Project override is not available here. No project config root was found.\");\n\tif (!fs.existsSync(filePath)) return { path: filePath, removed: false };\n\n\tconst settings = readSettingsFileStrict(filePath);\n\tconst subagents = settings.subagents;\n\tif (!subagents || typeof subagents !== \"object\" || Array.isArray(subagents))\n\t\treturn { path: filePath, removed: false };\n\tconst agentOverrides = (subagents as Record<string, unknown>).agentOverrides;\n\tif (!agentOverrides || typeof agentOverrides !== \"object\" || Array.isArray(agentOverrides))\n\t\treturn { path: filePath, removed: false };\n\n\tconst entry = (agentOverrides as Record<string, unknown>)[name];\n\tif (!entry || typeof entry !== \"object\" || Array.isArray(entry)) return { path: filePath, removed: false };\n\n\tconst nextEntry: Record<string, unknown> = { ...(entry as Record<string, unknown>) };\n\tlet removed = false;\n\tfor (const field of fields) {\n\t\tif (Object.hasOwn(nextEntry, field)) {\n\t\t\tdelete nextEntry[field];\n\t\t\tremoved = true;\n\t\t}\n\t}\n\tif (!removed) return { path: filePath, removed: false };\n\n\tconst nextSubagents = { ...(subagents as Record<string, unknown>) };\n\tif (Object.keys(nextEntry).length > 0) {\n\t\t(nextSubagents.agentOverrides as Record<string, unknown>)[name] = nextEntry;\n\t} else {\n\t\tconst nextOverrides = { ...(agentOverrides as Record<string, unknown>) };\n\t\tdelete nextOverrides[name];\n\t\tif (Object.keys(nextOverrides).length > 0) nextSubagents.agentOverrides = nextOverrides;\n\t\telse delete nextSubagents.agentOverrides;\n\t}\n\tif (Object.keys(nextSubagents).length > 0) settings.subagents = nextSubagents;\n\telse delete settings.subagents;\n\twriteSettingsFile(filePath, settings);\n\treturn { path: filePath, removed: true };\n}\n\nconst DISCOVERY_PRUNED_DIR_NAMES = new Set([\".git\", \"node_modules\"]);\n\nfunction isDiscoveryNestedProjectRoot(dir: string): boolean {\n\treturn isDirectory(getProjectConfigDir(dir)) || isDirectory(path.join(dir, \".agents\"));\n}\n\nfunction shouldPruneDiscoveryDir(rootDir: string, dir: string, dirName: string): boolean {\n\tif (DISCOVERY_PRUNED_DIR_NAMES.has(dirName)) return true;\n\tif (fs.existsSync(path.join(dir, \".git\"))) return true;\n\treturn path.resolve(dir) !== path.resolve(rootDir) && isDiscoveryNestedProjectRoot(dir);\n}\n\nfunction listFilesRecursive(dir: string, predicate: (fileName: string) => boolean, rootDir = dir): string[] {\n\tconst files: string[] = [];\n\tif (!fs.existsSync(dir)) return files;\n\n\tlet entries: fs.Dirent[];\n\ttry {\n\t\tentries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));\n\t} catch {\n\t\treturn files;\n\t}\n\n\tfor (const entry of entries) {\n\t\tconst filePath = path.join(dir, entry.name);\n\t\tif (entry.isDirectory()) {\n\t\t\tif (!shouldPruneDiscoveryDir(rootDir, filePath, entry.name)) {\n\t\t\t\tfiles.push(...listFilesRecursive(filePath, predicate, rootDir));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tif (!entry.isFile() && !entry.isSymbolicLink()) continue;\n\t\tif (!predicate(entry.name)) continue;\n\t\tfiles.push(filePath);\n\t}\n\treturn files;\n}\n\nfunction isLegacyAgentSkillPath(rootDir: string, filePath: string): boolean {\n\tconst relative = path.relative(rootDir, filePath);\n\tconst parts = relative.split(path.sep).map((part) => part.toLowerCase());\n\tif (path.basename(rootDir).toLowerCase() === \".agents\") {\n\t\tparts.unshift(\".agents\");\n\t}\n\treturn parts.some((part, index) => part === \".agents\" && parts[index + 1] === \"skills\");\n}\n\nfunction parseAgentRunnerFrontmatter(raw: string | undefined, agentName: string): AgentRunnerConfig | undefined {\n\tif (raw === undefined || !raw.trim()) return undefined;\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(raw);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Agent '${agentName}' has invalid runner frontmatter: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Agent '${agentName}' has invalid runner frontmatter; expected an object.`);\n\t}\n\tconst runner = parsed as Record<string, unknown>;\n\tif (runner.type === \"pi\") {\n\t\tif (Object.keys(runner).some((key) => key !== \"type\"))\n\t\t\tthrow new Error(`Agent '${agentName}' has invalid Pi runner frontmatter; only 'type' is supported.`);\n\t\treturn { type: \"pi\" };\n\t}\n\tif (runner.type !== \"external-cli\") {\n\t\tthrow new Error(`Agent '${agentName}' has invalid runner.type; expected 'pi' or 'external-cli'.`);\n\t}\n\tif (typeof runner.command !== \"string\" || !runner.command.trim()) {\n\t\tthrow new Error(`Agent '${agentName}' external-cli runner requires a non-empty command string.`);\n\t}\n\tif (\n\t\trunner.args !== undefined &&\n\t\t(!Array.isArray(runner.args) || runner.args.some((arg) => typeof arg !== \"string\"))\n\t) {\n\t\tthrow new Error(`Agent '${agentName}' external-cli runner args must be an array of strings.`);\n\t}\n\tif (runner.promptDelivery !== undefined && runner.promptDelivery !== \"stdin\") {\n\t\tthrow new Error(`Agent '${agentName}' external-cli runner promptDelivery must be 'stdin'.`);\n\t}\n\tconst retry = parseRunnerRetryConfig(runner.retry, `Agent '${agentName}' external-cli runner retry`);\n\tconst supported = new Set([\"type\", \"command\", \"args\", \"promptDelivery\", \"retry\"]);\n\tconst unknown = Object.keys(runner).filter((key) => !supported.has(key));\n\tif (unknown.length > 0)\n\t\tthrow new Error(`Agent '${agentName}' external-cli runner has unsupported fields: ${unknown.join(\", \")}.`);\n\tconst runnerArgs = Array.isArray(runner.args)\n\t\t? runner.args.filter((arg): arg is string => typeof arg === \"string\")\n\t\t: undefined;\n\treturn {\n\t\ttype: \"external-cli\",\n\t\tcommand: runner.command.trim(),\n\t\t...(runnerArgs?.length ? { args: runnerArgs } : {}),\n\t\t...(runner.promptDelivery ? { promptDelivery: \"stdin\" as const } : {}),\n\t\t...(retry ? { retry } : {}),\n\t};\n}\n\nfunction validateExternalRunnerProfile(\n\tfrontmatter: Record<string, string>,\n\tagentName: string,\n\trunner: AgentRunnerConfig | undefined,\n): void {\n\tif (runner?.type !== \"external-cli\") return;\n\tconst unsupported = [\n\t\t\"tools\",\n\t\t\"model\",\n\t\t\"fallbackModels\",\n\t\t\"thinking\",\n\t\t\"extensions\",\n\t\t\"subagentOnlyExtensions\",\n\t\t\"maxSubagentDepth\",\n\t\t\"completionGuard\",\n\t\t\"skills\",\n\t\t\"skill\",\n\t\t\"skillPath\",\n\t\t\"toolBudget\",\n\t\t\"permission\",\n\t\t\"permissions\",\n\t].filter((field) => frontmatter[field] !== undefined);\n\tif (unsupported.length > 0) {\n\t\tthrow new Error(\n\t\t\t`Agent '${agentName}' uses runner.type='external-cli' and declares unsupported Pi-only fields: ${unsupported.join(\", \")}.`,\n\t\t);\n\t}\n}\n\nfunction parseAgentAcceptanceFrontmatter(raw: string | undefined, agentName: string): AcceptanceInput | undefined {\n\tif (raw === undefined || !raw.trim()) return undefined;\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = parseYaml(raw);\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Agent '${agentName}' has invalid acceptance frontmatter: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t{ cause: error },\n\t\t);\n\t}\n\tconst errors = validateAcceptanceInput(parsed, `Agent '${agentName}' acceptance frontmatter`);\n\tif (errors.length > 0) throw new Error(errors.join(\" \"));\n\treturn parsed as AcceptanceInput;\n}\n\nfunction loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {\n\tconst agents: AgentConfig[] = [];\n\n\tfor (const filePath of listFilesRecursive(\n\t\tdir,\n\t\t(fileName) => fileName.endsWith(\".md\") && !fileName.endsWith(\".chain.md\"),\n\t)) {\n\t\tif (isLegacyAgentSkillPath(dir, filePath)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = fs.readFileSync(filePath, \"utf-8\");\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { frontmatter, body } = parseFrontmatter(content);\n\n\t\tif (!frontmatter.name || !frontmatter.description) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst localName = frontmatter.name;\n\t\tconst parsedPackage = parsePackageName(frontmatter.package, `Agent '${localName}' package`);\n\t\tif (parsedPackage.error) continue;\n\t\tconst packageName = parsedPackage.packageName;\n\t\tconst runtimeName = buildRuntimeName(localName, packageName);\n\n\t\tconst runner = parseAgentRunnerFrontmatter(frontmatter.runner, localName);\n\t\tvalidateExternalRunnerProfile(frontmatter, localName, runner);\n\t\tconst rawTools = parseFrontmatterList(frontmatter.tools);\n\t\tconst parsedTools = splitToolList(rawTools);\n\t\tconst tools = parsedTools.tools ?? [];\n\t\tconst mcpDirectTools = parsedTools.mcpDirectTools ?? [];\n\t\tconst defaultReads = parseFrontmatterList(frontmatter.defaultReads);\n\t\tconst aliases = normalizeAgentAliases(\n\t\t\tparseFrontmatterList(frontmatter.aliases ?? frontmatter.alias),\n\t\t\truntimeName,\n\t\t);\n\t\tconst skillStr = frontmatter.skill || frontmatter.skills;\n\t\tconst skills = parseFrontmatterList(skillStr);\n\t\tconst skillPath = parseFrontmatterList(frontmatter.skillPath);\n\t\tconst fallbackModels = parseFrontmatterList(frontmatter.fallbackModels);\n\t\tconst systemPromptMode =\n\t\t\tfrontmatter.systemPromptMode === \"replace\"\n\t\t\t\t? \"replace\"\n\t\t\t\t: frontmatter.systemPromptMode === \"append\"\n\t\t\t\t\t? \"append\"\n\t\t\t\t\t: defaultSystemPromptMode(localName);\n\t\tconst inheritProjectContext =\n\t\t\tfrontmatter.inheritProjectContext === \"true\"\n\t\t\t\t? true\n\t\t\t\t: frontmatter.inheritProjectContext === \"false\"\n\t\t\t\t\t? false\n\t\t\t\t\t: defaultInheritProjectContext(localName);\n\t\tconst inheritSkills =\n\t\t\tfrontmatter.inheritSkills === \"true\"\n\t\t\t\t? true\n\t\t\t\t: frontmatter.inheritSkills === \"false\"\n\t\t\t\t\t? false\n\t\t\t\t\t: defaultInheritSkills();\n\t\tconst defaultContext =\n\t\t\tfrontmatter.defaultContext === \"fork\"\n\t\t\t\t? (\"fork\" as const)\n\t\t\t\t: frontmatter.defaultContext === \"fresh\"\n\t\t\t\t\t? (\"fresh\" as const)\n\t\t\t\t\t: undefined;\n\t\tlet defaultAsync: boolean | undefined;\n\t\tif (frontmatter.async !== undefined) {\n\t\t\tif (frontmatter.async === \"true\") defaultAsync = true;\n\t\t\telse if (frontmatter.async === \"false\") defaultAsync = false;\n\t\t\telse throw new Error(`Agent '${localName}' has invalid async frontmatter; expected true or false.`);\n\t\t}\n\t\tlet defaultTimeoutMs: number | undefined;\n\t\tif (frontmatter.timeoutMs !== undefined) {\n\t\t\tconst parsed = Number(frontmatter.timeoutMs);\n\t\t\tif (!Number.isInteger(parsed) || parsed <= 0) {\n\t\t\t\tthrow new Error(`Agent '${localName}' has invalid timeoutMs frontmatter; expected a positive integer.`);\n\t\t\t}\n\t\t\tdefaultTimeoutMs = parsed;\n\t\t}\n\t\tlet defaultTurnBudget: TurnBudgetConfig | undefined;\n\t\tif (frontmatter.turnBudget?.trim()) {\n\t\t\tconst parsed = JSON.parse(frontmatter.turnBudget) as unknown;\n\t\t\tconst resolved = resolveTurnBudgetConfig(parsed, `Agent '${localName}' turnBudget frontmatter`);\n\t\t\tif (resolved.error) throw new Error(resolved.error);\n\t\t\tdefaultTurnBudget = resolved.turnBudget;\n\t\t}\n\t\tconst defaultAcceptance = parseAgentAcceptanceFrontmatter(frontmatter.acceptance, localName);\n\t\tlet acceptanceRole: AcceptanceRole | undefined;\n\t\tif (frontmatter.acceptanceRole?.trim()) {\n\t\t\tif (frontmatter.acceptanceRole === \"read-only\" || frontmatter.acceptanceRole === \"writer\")\n\t\t\t\tacceptanceRole = frontmatter.acceptanceRole;\n\t\t\telse\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Agent '${localName}' has invalid acceptanceRole frontmatter; expected 'read-only' or 'writer'.`,\n\t\t\t\t);\n\t\t}\n\n\t\tconst extensions = parseFrontmatterList(frontmatter.extensions);\n\t\tconst subagentOnlyExtensions = parseFrontmatterList(frontmatter.subagentOnlyExtensions);\n\n\t\tconst extraFields: Record<string, string> = {};\n\t\tfor (const [key, value] of Object.entries(frontmatter)) {\n\t\t\tif (!KNOWN_FIELDS.has(key)) extraFields[key] = value;\n\t\t}\n\n\t\tconst parsedMaxSubagentDepth = Number(frontmatter.maxSubagentDepth);\n\t\tif (frontmatter.permission !== undefined && frontmatter.permissions !== undefined) {\n\t\t\tthrow new Error(`Agent '${localName}' cannot declare both permission and permissions frontmatter.`);\n\t\t}\n\t\tconst permissionSource = frontmatter.permissions ?? frontmatter.permission;\n\t\tconst permissions = permissionSource?.trim()\n\t\t\t? validatePermissionRules(parseYaml(permissionSource), `Agent '${localName}' permissions`)\n\t\t\t: undefined;\n\t\tlet toolBudget: ToolBudgetConfig | undefined;\n\t\tif (frontmatter.toolBudget?.trim()) {\n\t\t\tconst parsed = JSON.parse(frontmatter.toolBudget) as unknown;\n\t\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\t\t\tthrow new Error(`Agent '${localName}' has invalid toolBudget frontmatter; expected a JSON object.`);\n\t\t\t}\n\t\t\ttoolBudget = parsed as ToolBudgetConfig;\n\t\t}\n\t\tconst completionGuard =\n\t\t\tfrontmatter.completionGuard === \"false\" ? false : frontmatter.completionGuard === \"true\" ? true : undefined;\n\n\t\tconst maxSubagentDepth =\n\t\t\tNumber.isInteger(parsedMaxSubagentDepth) && parsedMaxSubagentDepth >= 0 ? parsedMaxSubagentDepth : undefined;\n\t\tconst memory = parseMemoryFrontmatter(frontmatter.memory);\n\t\tconst agent: AgentConfig = {\n\t\t\tname: runtimeName,\n\t\t\t...(runner !== undefined ? { runner } : {}),\n\t\t\tlocalName,\n\t\t\t...(packageName !== undefined ? { packageName } : {}),\n\t\t\tdescription: frontmatter.description,\n\t\t\t...(aliases !== undefined ? { aliases } : {}),\n\t\t\t...(rawTools !== undefined ? { tools } : {}),\n\t\t\t...(mcpDirectTools.length > 0 ? { mcpDirectTools } : {}),\n\t\t\t...(frontmatter.model !== undefined ? { model: frontmatter.model } : {}),\n\t\t\t...(fallbackModels?.length ? { fallbackModels } : {}),\n\t\t\t...(frontmatter.thinking !== undefined\n\t\t\t\t? { thinking: frontmatter.thinking === \"false\" ? false : frontmatter.thinking }\n\t\t\t\t: {}),\n\t\t\tsystemPromptMode,\n\t\t\tinheritProjectContext,\n\t\t\tinheritSkills,\n\t\t\t...(defaultContext !== undefined ? { defaultContext } : {}),\n\t\t\t...(defaultAsync !== undefined ? { defaultAsync } : {}),\n\t\t\t...(defaultTimeoutMs !== undefined ? { defaultTimeoutMs } : {}),\n\t\t\t...(defaultTurnBudget !== undefined ? { defaultTurnBudget } : {}),\n\t\t\t...(defaultAcceptance !== undefined ? { defaultAcceptance } : {}),\n\t\t\t...(acceptanceRole !== undefined ? { acceptanceRole } : {}),\n\t\t\tsystemPrompt: body,\n\t\t\tsource,\n\t\t\tfilePath,\n\t\t\t...(skills?.length ? { skills } : {}),\n\t\t\t...(skillPath?.length ? { skillPath } : {}),\n\t\t\t...(extensions !== undefined ? { extensions } : {}),\n\t\t\t...(subagentOnlyExtensions !== undefined ? { subagentOnlyExtensions } : {}),\n\t\t\t...(frontmatter.output !== undefined ? { output: frontmatter.output } : {}),\n\t\t\t...(defaultReads?.length ? { defaultReads } : {}),\n\t\t\tdefaultProgress: frontmatter.defaultProgress === \"true\",\n\t\t\tinteractive: frontmatter.interactive === \"true\",\n\t\t\t...(maxSubagentDepth !== undefined ? { maxSubagentDepth } : {}),\n\t\t\t...(completionGuard !== undefined ? { completionGuard } : {}),\n\t\t\t...(toolBudget !== undefined ? { toolBudget } : {}),\n\t\t\t...(permissions !== undefined ? { permissions } : {}),\n\t\t\t...(memory !== undefined ? { memory } : {}),\n\t\t\t...(Object.keys(extraFields).length > 0 ? { extraFields } : {}),\n\t\t};\n\t\tagentFrontmatterFields.set(agent, new Set(Object.keys(frontmatter)));\n\t\tagents.push(agent);\n\t}\n\n\treturn agents;\n}\n\nfunction loadChainsFromDir(\n\tdir: string,\n\tsource: AgentSource,\n): { chains: ChainConfig[]; diagnostics: ChainDiscoveryDiagnostic[] } {\n\tconst chains = new Map<string, ChainConfig>();\n\tconst diagnostics: ChainDiscoveryDiagnostic[] = [];\n\n\tfor (const filePath of listFilesRecursive(\n\t\tdir,\n\t\t(fileName) => fileName.endsWith(\".chain.md\") || fileName.endsWith(\".chain.json\"),\n\t)) {\n\t\tlet content: string;\n\t\ttry {\n\t\t\tcontent = fs.readFileSync(filePath, \"utf-8\");\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst chain = filePath.endsWith(\".chain.json\")\n\t\t\t\t? parseJsonChain(content, source, filePath)\n\t\t\t\t: parseChain(content, source, filePath);\n\t\t\tconst existing = chains.get(chain.name);\n\t\t\tif (existing?.filePath.endsWith(\".chain.json\") && filePath.endsWith(\".chain.md\")) continue;\n\t\t\tchains.set(chain.name, chain);\n\t\t} catch (error) {\n\t\t\tdiagnostics.push({ source, filePath, error: error instanceof Error ? error.message : String(error) });\n\t\t}\n\t}\n\n\treturn { chains: Array.from(chains.values()), diagnostics };\n}\n\nfunction isDirectory(p: string): boolean {\n\ttry {\n\t\treturn fs.statSync(p).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction resolveNearestProjectAgentDirs(cwd: string): { readDirs: string[]; preferredDir: string | null } {\n\tconst projectRoot = findConfiguredProjectRoot(cwd);\n\tif (!projectRoot) return { readDirs: [], preferredDir: null };\n\n\tconst legacyDir = path.join(projectRoot, \".agents\");\n\tconst preferredDir = path.join(getProjectConfigDir(projectRoot), \"agents\");\n\tconst readDirs: string[] = [];\n\tif (isDirectory(legacyDir)) readDirs.push(legacyDir);\n\tif (isDirectory(preferredDir)) readDirs.push(preferredDir);\n\n\treturn {\n\t\treadDirs,\n\t\tpreferredDir,\n\t};\n}\n\nfunction resolveNearestProjectChainDirs(cwd: string): { readDirs: string[]; preferredDir: string | null } {\n\tconst projectRoot = findConfiguredProjectRoot(cwd);\n\tif (!projectRoot) return { readDirs: [], preferredDir: null };\n\n\tconst preferredDir = path.join(getProjectConfigDir(projectRoot), \"chains\");\n\treturn {\n\t\treadDirs: isDirectory(preferredDir) ? [preferredDir] : [],\n\t\tpreferredDir,\n\t};\n}\nexport function resolveBuiltinAgentsDir(moduleDir: string): string {\n\tconst candidates = [\n\t\t...(moduleDir.includes(\"$bunfs\") ? [path.join(path.dirname(process.execPath), \"agents\")] : []),\n\t\tpath.resolve(moduleDir, \"..\", \"..\", \"agents\"),\n\t\tpath.resolve(moduleDir, \"..\", \"..\", \"..\", \"agents\"),\n\t];\n\tconst existing = candidates.find((candidate) => isDirectory(candidate));\n\tif (existing) return existing;\n\tthrow new Error(`Builtin subagent agents directory not found. Checked: ${candidates.join(\", \")}`);\n}\n\nconst BUILTIN_AGENTS_DIR = resolveBuiltinAgentsDir(path.dirname(fileURLToPath(import.meta.url)));\n\nexport const EXTRA_AGENT_DIRS_ENV = \"PI_SUBAGENT_EXTRA_AGENT_DIRS\";\n\n// Additional read-only directories to scan for agent definitions, supplied by the\n// launcher via PI_SUBAGENT_EXTRA_AGENT_DIRS (PATH-style, split on os/path delimiter).\n// Lets a hermetic wrapper (e.g. a Nix-store install) expose bundled agents without\n// copying or symlinking them into the writable agent dir. Loaded as \"user\" source,\n// at lower precedence than agents the user placed in their own agent dir.\nfunction extraUserAgentDirs(): string[] {\n\tconst raw = process.env[EXTRA_AGENT_DIRS_ENV];\n\tif (!raw) return [];\n\treturn raw\n\t\t.split(path.delimiter)\n\t\t.map((dir) => dir.trim())\n\t\t.filter((dir) => dir.length > 0);\n}\n\nexport function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryResult {\n\tconst userDirOld = path.join(getAgentDir(), \"agents\");\n\tconst userDirNew = path.join(os.homedir(), \".agents\");\n\tconst { readDirs: projectAgentDirs, preferredDir: projectAgentsDir } = resolveNearestProjectAgentDirs(cwd);\n\tconst userSettingsPath = getUserAgentSettingsPath();\n\tconst projectSettingsPath = getProjectAgentSettingsPath(cwd);\n\tconst userSettings = scope === \"project\" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(userSettingsPath);\n\tconst projectSettings = scope === \"user\" ? EMPTY_SUBAGENT_SETTINGS : readSubagentSettings(projectSettingsPath);\n\tconst defaultModel = resolveSubagentDefaultModel(\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\tconst defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);\n\tconst defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);\n\tconst modelScope = projectSettings.modelScope ?? userSettings.modelScope;\n\tconst packageSubagentPaths = collectPackageSubagentPaths(cwd, {\n\t\tincludeUser: scope !== \"project\",\n\t\tincludeProject: scope !== \"user\",\n\t});\n\n\tconst builtinAgents = applyBuiltinOverrides(\n\t\tapplySubagentDefaults(\n\t\t\tloadAgentsFromDir(BUILTIN_AGENTS_DIR, \"builtin\"),\n\t\t\tdefaultModel,\n\t\t\tdefaultThinking,\n\t\t\tdefaultExtensions,\n\t\t),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\n\tconst userAgentsExtra =\n\t\tscope === \"project\" ? [] : extraUserAgentDirs().flatMap((dir) => loadAgentsFromDir(dir, \"user\"));\n\tconst userAgentsOld = scope === \"project\" ? [] : loadAgentsFromDir(userDirOld, \"user\");\n\tconst userAgentsNew = scope === \"project\" ? [] : loadAgentsFromDir(userDirNew, \"user\");\n\tconst userAgents = applyCustomAgentOverrides(\n\t\tapplySubagentDefaults(\n\t\t\t[...userAgentsExtra, ...userAgentsOld, ...userAgentsNew],\n\t\t\tdefaultModel,\n\t\t\tdefaultThinking,\n\t\t\tdefaultExtensions,\n\t\t),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\n\tconst projectAgents = applyCustomAgentOverrides(\n\t\tapplySubagentDefaults(\n\t\t\tscope === \"user\" ? [] : projectAgentDirs.flatMap((dir) => loadAgentsFromDir(dir, \"project\")),\n\t\t\tdefaultModel,\n\t\t\tdefaultThinking,\n\t\t\tdefaultExtensions,\n\t\t),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\tconst packageAgents = applyCustomAgentOverrides(\n\t\tapplySubagentDefaults(\n\t\t\tpackageSubagentPaths.agents.flatMap((dir) => loadAgentsFromDir(dir, \"package\")),\n\t\t\tdefaultModel,\n\t\t\tdefaultThinking,\n\t\t\tdefaultExtensions,\n\t\t),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\tconst agents = mergeAgentsForScope(scope, userAgents, projectAgents, builtinAgents, packageAgents).filter(\n\t\t(agent) => agent.disabled !== true,\n\t);\n\n\treturn { agents, projectAgentsDir, ...(modelScope !== undefined ? { modelScope } : {}) };\n}\n\nexport function discoverAgentsAll(cwd: string): {\n\tbuiltin: AgentConfig[];\n\tpackage: AgentConfig[];\n\tuser: AgentConfig[];\n\tproject: AgentConfig[];\n\tchains: ChainConfig[];\n\tchainDiagnostics: ChainDiscoveryDiagnostic[];\n\tuserDir: string;\n\tprojectDir: string | null;\n\tuserChainDir: string;\n\tprojectChainDir: string | null;\n\tuserSettingsPath: string;\n\tprojectSettingsPath: string | null;\n} {\n\tconst userDirOld = path.join(getAgentDir(), \"agents\");\n\tconst userDirNew = path.join(os.homedir(), \".agents\");\n\tconst userChainDir = getUserChainDir();\n\tconst { readDirs: projectDirs, preferredDir: projectDir } = resolveNearestProjectAgentDirs(cwd);\n\tconst { readDirs: projectChainDirs, preferredDir: projectChainDir } = resolveNearestProjectChainDirs(cwd);\n\tconst userSettingsPath = getUserAgentSettingsPath();\n\tconst projectSettingsPath = getProjectAgentSettingsPath(cwd);\n\tconst userSettings = readSubagentSettings(userSettingsPath);\n\tconst projectSettings = readSubagentSettings(projectSettingsPath);\n\tconst defaultModel = resolveSubagentDefaultModel(\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\tconst defaultThinking = resolveSubagentDefaultThinking(userSettings, projectSettings, projectSettingsPath);\n\tconst defaultExtensions = resolveSubagentDefaultExtensions(userSettings, projectSettings, projectSettingsPath);\n\tconst packageSubagentPaths = collectPackageSubagentPaths(cwd);\n\n\tconst builtin = applyBuiltinOverrides(\n\t\tapplySubagentDefaults(\n\t\t\tloadAgentsFromDir(BUILTIN_AGENTS_DIR, \"builtin\"),\n\t\t\tdefaultModel,\n\t\t\tdefaultThinking,\n\t\t\tdefaultExtensions,\n\t\t),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\tconst user = applyCustomAgentOverrides(\n\t\tapplySubagentDefaults(\n\t\t\t[\n\t\t\t\t...extraUserAgentDirs().flatMap((dir) => loadAgentsFromDir(dir, \"user\")),\n\t\t\t\t...loadAgentsFromDir(userDirOld, \"user\"),\n\t\t\t\t...loadAgentsFromDir(userDirNew, \"user\"),\n\t\t\t],\n\t\t\tdefaultModel,\n\t\t\tdefaultThinking,\n\t\t\tdefaultExtensions,\n\t\t),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\tconst packageMap = new Map<string, AgentConfig>();\n\tfor (const dir of packageSubagentPaths.agents) {\n\t\tfor (const agent of loadAgentsFromDir(dir, \"package\")) {\n\t\t\tif (!packageMap.has(agent.name)) packageMap.set(agent.name, agent);\n\t\t}\n\t}\n\tconst packageAgents = applyCustomAgentOverrides(\n\t\tapplySubagentDefaults(Array.from(packageMap.values()), defaultModel, defaultThinking, defaultExtensions),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\tconst projectMap = new Map<string, AgentConfig>();\n\tfor (const dir of projectDirs) {\n\t\tfor (const agent of loadAgentsFromDir(dir, \"project\")) {\n\t\t\tprojectMap.set(agent.name, agent);\n\t\t}\n\t}\n\tconst project = applyCustomAgentOverrides(\n\t\tapplySubagentDefaults(Array.from(projectMap.values()), defaultModel, defaultThinking, defaultExtensions),\n\t\tuserSettings,\n\t\tprojectSettings,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t);\n\n\tconst chainMap = new Map<string, ChainConfig>();\n\tconst packageChainDiagnostics: ChainDiscoveryDiagnostic[] = [];\n\tconst packageChainMap = new Map<string, ChainConfig>();\n\tfor (const dir of packageSubagentPaths.chains) {\n\t\tconst loaded = loadChainsFromDir(dir, \"package\");\n\t\tpackageChainDiagnostics.push(...loaded.diagnostics);\n\t\tfor (const chain of loaded.chains) {\n\t\t\tif (!packageChainMap.has(chain.name)) packageChainMap.set(chain.name, chain);\n\t\t}\n\t}\n\tconst projectChainDiagnostics: ChainDiscoveryDiagnostic[] = [];\n\tfor (const dir of projectChainDirs) {\n\t\tconst loaded = loadChainsFromDir(dir, \"project\");\n\t\tprojectChainDiagnostics.push(...loaded.diagnostics);\n\t\tfor (const chain of loaded.chains) {\n\t\t\tchainMap.set(chain.name, chain);\n\t\t}\n\t}\n\tconst userChains = loadChainsFromDir(userChainDir, \"user\");\n\tconst chains = [...Array.from(packageChainMap.values()), ...userChains.chains, ...Array.from(chainMap.values())];\n\tconst chainDiagnostics = [...packageChainDiagnostics, ...userChains.diagnostics, ...projectChainDiagnostics];\n\n\tconst userDir = process.env.PI_CODING_AGENT_DIR ? userDirOld : fs.existsSync(userDirNew) ? userDirNew : userDirOld;\n\n\treturn {\n\t\tbuiltin,\n\t\tpackage: packageAgents,\n\t\tuser,\n\t\tproject,\n\t\tchains,\n\t\tchainDiagnostics,\n\t\tuserDir,\n\t\tprojectDir,\n\t\tuserChainDir,\n\t\tprojectChainDir,\n\t\tuserSettingsPath,\n\t\tprojectSettingsPath,\n\t};\n}\n"]}