import { watch } from "chokidar"; import { join } from "node:path"; import type { DispatchConfig } from "../types/index.js"; import { loadConfig } from "./loader.js"; export function createConfigWatcher( dir: string, onChange: (config: DispatchConfig) => void, ): { close(): void } { const tomlPath = join(dir, "dispatch.toml"); let debounceTimer: ReturnType | null = null; const watcher = watch(tomlPath, { ignoreInitial: true, persistent: false, }); const handleChange = () => { if (debounceTimer !== null) { clearTimeout(debounceTimer); } debounceTimer = setTimeout(() => { debounceTimer = null; console.log(`dispatch: reloading config from ${tomlPath}`); try { const config = loadConfig(dir); onChange(config); } catch (err) { console.warn(`dispatch: retaining last known config due to parse error: ${err instanceof Error ? err.message : String(err)}`); } }, 300); }; watcher.on("change", handleChange); watcher.on("add", handleChange); watcher.on("unlink", handleChange); watcher.on("error", (err) => { console.warn(`dispatch: config watcher error: ${err instanceof Error ? err.message : String(err)}`); }); return { close() { if (debounceTimer !== null) { clearTimeout(debounceTimer); debounceTimer = null; } watcher.close().catch((err) => { console.warn(`dispatch: error closing config watcher: ${err instanceof Error ? err.message : String(err)}`); }); }, }; }