(options: ConfigWatcherOptions)
| 21 | * HTTP transport creates a fresh server per request, so tool changes take effect immediately. |
| 22 | */ |
| 23 | export function startConfigWatcher(options: ConfigWatcherOptions): (() => void) | null { |
| 24 | const { connectorManager, initialTools } = options; |
| 25 | const configPath = resolveTomlConfigPath(); |
| 26 | if (!configPath) { |
| 27 | return null; |
| 28 | } |
| 29 | |
| 30 | let debounceTimer: NodeJS.Timeout | null = null; |
| 31 | let isReloading = false; |
| 32 | let reloadPending = false; |
| 33 | |
| 34 | // Track last known-good config for rollback (sources + tools) |
| 35 | let lastGoodSources: SourceConfig[] = connectorManager.getAllSourceConfigs(); |
| 36 | let lastGoodTools: ToolConfig[] | undefined = initialTools; |
| 37 | |
| 38 | const scheduleReload = () => { |
| 39 | if (debounceTimer) { |
| 40 | clearTimeout(debounceTimer); |
| 41 | } |
| 42 | debounceTimer = setTimeout(reload, DEBOUNCE_MS); |
| 43 | }; |
| 44 | |
| 45 | const reload = async () => { |
| 46 | if (isReloading) { |
| 47 | reloadPending = true; |
| 48 | return; |
| 49 | } |
| 50 | isReloading = true; |
| 51 | reloadPending = false; |
| 52 | |
| 53 | try { |
| 54 | console.error(`\nDetected change in ${configPath}, reloading configuration...`); |
| 55 | |
| 56 | // Parse and validate new config — if this throws, keep existing connections |
| 57 | const newConfig = loadTomlConfig(); |
| 58 | if (!newConfig) { |
| 59 | console.error("Config reload: failed to load TOML config, keeping existing connections."); |
| 60 | return; |
| 61 | } |
| 62 | |
| 63 | // Save current config for rollback |
| 64 | const oldSources = lastGoodSources; |
| 65 | const oldTools = lastGoodTools; |
| 66 | |
| 67 | // Disconnect all existing sources |
| 68 | await connectorManager.disconnect(); |
| 69 | |
| 70 | try { |
| 71 | // Reconnect with new sources |
| 72 | await connectorManager.connectWithSources(newConfig.sources); |
| 73 | |
| 74 | // Re-initialize tool registry with new config |
| 75 | initializeToolRegistry({ |
| 76 | sources: newConfig.sources, |
| 77 | tools: newConfig.tools, |
| 78 | }); |
| 79 | |
| 80 | // Update last known-good config |
no test coverage detected