| 155 | export type AgentConfigChangeListener = (configs: ReadonlyMap<string, AgentBaseConfig>, error?: Error) => void |
| 156 | |
| 157 | export class AgentConfigLoader { |
| 158 | private static instance?: AgentConfigLoader |
| 159 | |
| 160 | private readonly homeDir: string |
| 161 | private readonly directoryPath: string |
| 162 | private readonly initialLoadPromise: Promise<void> |
| 163 | private watcher?: FSWatcher |
| 164 | private cachedConfigs = new Map<string, AgentBaseConfig>() |
| 165 | private cachedAgentToolNames = new Map<string, string>() |
| 166 | private cachedToolNameToAgentName = new Map<string, string>() |
| 167 | private listeners = new Set<AgentConfigChangeListener>() |
| 168 | |
| 169 | private constructor(homeDir = os.homedir()) { |
| 170 | this.homeDir = homeDir |
| 171 | this.directoryPath = getAgentsConfigPath(homeDir) |
| 172 | this.initialLoadPromise = this.load() |
| 173 | .then(() => undefined) |
| 174 | .catch((error) => { |
| 175 | Logger.error("[AgentConfigLoader] Failed to load initial agent configs", error) |
| 176 | }) |
| 177 | .finally(() => |
| 178 | this.watch().catch((error) => Logger.error("[AgentConfigLoader] Failed to start watching agent configs", error)), |
| 179 | ) |
| 180 | } |
| 181 | |
| 182 | public static getInstance(homeDir = os.homedir()): AgentConfigLoader { |
| 183 | if (!AgentConfigLoader.instance) { |
| 184 | AgentConfigLoader.instance = new AgentConfigLoader(homeDir) |
| 185 | } |
| 186 | return AgentConfigLoader.instance |
| 187 | } |
| 188 | |
| 189 | /** |
| 190 | * Test-only helper to clear singleton state between unit tests. |
| 191 | */ |
| 192 | public static async resetInstanceForTests(): Promise<void> { |
| 193 | if (!AgentConfigLoader.instance) { |
| 194 | return |
| 195 | } |
| 196 | |
| 197 | await AgentConfigLoader.instance.dispose() |
| 198 | AgentConfigLoader.instance = undefined |
| 199 | } |
| 200 | |
| 201 | public getConfigPath(): string { |
| 202 | return this.directoryPath |
| 203 | } |
| 204 | |
| 205 | public async ready(): Promise<void> { |
| 206 | await this.initialLoadPromise |
| 207 | } |
| 208 | |
| 209 | public getCachedConfig(subagentName?: string): AgentBaseConfig | undefined { |
| 210 | if (!subagentName?.trim()) { |
| 211 | return undefined |
| 212 | } |
| 213 | return this.cachedConfigs.get(normalizeAgentName(subagentName)) |
| 214 | } |
nothing calls this directly
no outgoing calls
no test coverage detected