/** * The state one `lookout ui` process carries between requests. * * A server is a pile of handlers, and every one of them needs to know the same * four things: which project is being served, what was remembered about where * to look, whether a check is in flight, and why the last one died. Those used * to be module-level `let`s in the middle of the request router, which is why * nothing else could be moved out of it. * * The project is behind an accessor rather than exported directly, because it * is the one piece with no sensible empty value: the verb resolves it before * the server ever listens, and a handler reading it earlier is a bug worth an * exception rather than a silent empty board. */ import type { ChildProcess } from "node:child_process"; import { type ResolvedConfig } from "../types.js"; import type { QueueItem } from "./queue.js"; import { type UiSettings } from "./stored-settings.js"; export declare function currentProject(): ResolvedConfig; /** * The project, or null when there is not one yet. * * The settings panel is the one reader that legitimately runs before anything * is configured: it is the screen you open to configure it. Everything else * wants the throwing accessor. */ export declare function currentProjectOrNull(): ResolvedConfig | null; export declare function onProjectChange(fn: () => void): () => void; /** * How many subscribers are registered right now. * * For the suite's leak guard: this list is process-wide and a test file that * leaves an entry in it hands the next file a callback that fires on its own * project changes. See `test/setup.ts`. */ export declare function projectChangeListenerCount(): number; export declare function setCurrentProject(next: ResolvedConfig): void; export declare const session: { /** * The directory this process was started in, or null for a --config/--url * run that was never about a directory at all. * * Not the project being served: those are the same until somebody points the * settings panel somewhere else, and once they differ this is the one that * remembers where they pointed it. A pointer cannot live inside the thing it * points to, and this is the directory that is not it. */ launchDir: string | null; /** Where the page has been pointed, and where the app actually is. */ settings: UiSettings; /** * The check in flight, if the page started one. * * It carries the project it was started against rather than only that * project's directory, because a run can be stopped after the page has been * pointed somewhere else, and what has to be written down then is the end of * THIS run, in the log it was narrating to. * * `stopping` is set the moment somebody presses stop and stays set until the * child is gone. It is what tells the exit handler that the run was ended on * purpose rather than that it fell over, and what stops a second press from * signalling a group that is already closing its browser. */ running: { child: ChildProcess; project: ResolvedConfig; stopping: boolean; /** * Which of lookout's own verbs is in the slot. * * There is one slot and two things that want it: the check the header * button starts, and the ruling the queue's head row asks for. The page * says which it is about to stop, because "stop" over a nine-minute check * and "stop" over a ruling somebody just asked for are different presses. */ kind: "check" | "verify-fix"; /** The issue a ruling is about. Absent for a check, which is about none. */ issue?: string; } | null; /** * Why the last run this page started ended badly, if it did. * * The child used to be spawned with its output discarded and only an `error` * handler attached, which fires when the process cannot be LAUNCHED and never * when it exits non-zero. A run that started and died a second later (target * down, unreadable config, nothing captured) left the page idle and blank * with the one artifact that explained it, its stderr, thrown away. */ lastFailure: { code: number | null; message: string; } | null; /** * The issues waiting to be handed over, head first. * * This is the current project's response cache. `queue.json` is authoritative * because another Lookout process can update the same project. */ queue: QueueItem[]; /** Project whose queue is cached above, or null before the first project load. */ queueProjectDir: string | null; /** * Bumped on every change to the queue. * * The status payload is cached on a key built by hand out of the things that * move, and none of them is this file: `diskKey` stats the backlog, the event * log and the issues directory, and `queue.json` is a sibling of all three. * Without this term the page would be served a queue from before the press. */ queueRev: number; /** The mtime the queue was last read or written at, so an outside edit shows. */ queueMtime: number; }; export declare function checkIsRunning(resolved?: ResolvedConfig): boolean; /** * Whether the run in flight has been told to stop and has not gone yet. * * A separate question from whether one is running, because for the second or * two between the signal and the last browser closing, both are true: the page * has to say the press landed rather than offer the button again. */ export declare function checkIsStopping(resolved?: ResolvedConfig): boolean;