export interface ViewReapplySet { configPath: string; files: string[]; } /** * Resolve the current reapply set for `cwd`: the config file plus every * listed view's entry and import graph. Throws the config loader's * ValidationError when `lobu.config.ts` is missing or malformed — the caller * treats that as "no reapply loop", never as fatal. */ export declare function collectViewReapplySet(cwd: string): Promise; export interface ViewReapplyEvents { /** A reapply file changed (debounced): re-apply, then rebuild the set. */ onChange: () => Promise; /** Log line for operator-visible reapply state. */ onLog?: (message: string) => void; } /** * Reapply `set.files` on change and call `onChange` after 750 ms quiet. * Returns `close` plus `update`. * * One coordinator lives for the whole loop: `update` replaces only the * native `fs.watch` subscriptions (so a new import joins the set after an * apply) and preserves the pending timer, the in-flight apply and the dirty * flag. Closing the coordinator on every apply instead would clear a timer * scheduled by a save that landed mid-apply, silently discarding it. * `close` is terminal: it clears the timer, drops the subscriptions, and * stops the finally handler from scheduling anything further. * * Concurrent change bursts collapse into one call; a change DURING a * re-apply schedules exactly one follow-up, so rapid saves never stack * applies. When `update` adds a file that was not watched before, one * follow-up is requested through the same dirty/schedule mechanism: a save * to that file may have landed after the apply read it but before its new * subscription existed, so no file subscription could have observed it. The * same holds when an existing path changes native file identity (an atomic * rename replaces the inode while the old Node per-file subscription stays * attached to the replaced file). The baseline advances at fire time to the * disk state the apply is about to read, so the triggering save itself never * reconciles; only a save that lands DURING the apply does. The next * stable graph and unchanged identities add nothing and schedule nothing * further. * * Native file identity for a watched path (`dev:ino:size:mtimeMs`). An * atomic rename replaces the inode at the same path while the old Node * per-file subscription stays attached to the replaced file, so path * equality alone cannot detect the swap. `dev:ino` alone is insufficient: * Linux (overlayfs/tmpfs) reuses a freed inode number immediately, so two * rapid atomic renames can alias back to the same `dev:ino`, and a * truncate-in-place save keeps the same `dev:ino` with new bytes. `size` * plus `mtimeMs` (sub-millisecond float, distinct even ~0.3 ms apart) * disambiguate both. A missing file maps to null so a later reappearance * also reconciles. */ export declare function fileIdentity(path: string): string | null; export declare function startViewReapply(set: ViewReapplySet, events: ViewReapplyEvents): { close: () => void; update: (next: ViewReapplySet) => void; }; //# sourceMappingURL=view-reapply.d.ts.map