/** * PM2-client-free log tailing for `botmux logs`. * * `pm2 logs` is a PM2 client, and any PM2 client invoked with no live God * lazily births one (pm2 Client.start → pingDaemon false → launchDaemon). * That made the read command a check/use race against `restart * --include-pm2`: a God observed under the fleet lock could be retired after * the lock released but before the spawned client connected, and the * connecting client would then create a replacement God inside the * kill→start window. Tailing the log FILES pm2 itself writes removes the PM2 * client entirely — no interleaving of this command can create a God, and * logs keep working while the fleet is stopped. */ export interface LogTailSource { /** Display label, e.g. the PM2 process name. */ label: string; stream: 'out' | 'err'; file: string; } export declare function formatLogLine(source: LogTailSource, line: string): string; /** Last `n` complete lines of a text chunk (trailing newline ignored). */ export declare function lastLinesOfChunk(chunk: string, n: number): string[]; export interface LogFileFollowerOptions { sources: readonly LogTailSource[]; writeLine: (formatted: string) => void; pollIntervalMs?: number; } /** * Print the last N lines of every existing source, then follow appends. * Correctness boundaries this models explicitly: * - An unterminated trailing line is NEVER emitted as a line; it is carried * as `partial` (from the initial tail too) and emitted once completed, so * "abc" + later "def\n" prints one "abcdef" line. * - Atomic rotation (rename + recreate at the same path) is detected by * dev+ino generation identity, not by size heuristics — a new file whose * size already exceeds the old offset would otherwise be read mid-stream. * (On filesystems reporting ino=0 this degrades to the size checks.) * - In-place truncation (`pm2 flush`) resets to the top of the new content. * - Files may appear later (fleet starts while tailing) or disappear. */ export declare class LogFileFollower { private readonly states; private readonly writeLine; private readonly pollIntervalMs; private timer; constructor(opts: LogFileFollowerOptions); /** Emit the initial `--lines` window and position offsets at end-of-file. */ printInitialTail(lines: number): void; start(): void; stop(): void; /** One poll pass; exposed so tests can drive it deterministically. */ pollOnce(): void; } //# sourceMappingURL=log-tail.d.ts.map