import { type Clock } from "./clock.js"; import { type ConciergeConfig, type ConciergeStatus } from "./concierge.js"; import type { BoardTask } from "./board.js"; import { type RoostEvent } from "./events.js"; import type { DispatchArgs, Event, JobRow } from "./protocol.js"; import type { JobRecord } from "./store.js"; /** Whatever the daemon calls a connected session: a job or a foreground pi. */ export interface ConciergePeer { kind: "job" | "fg"; id: string; } /** The ops of the concierge's family (the daemon's routing is one line). */ export type ConciergeOp = "concierge" | "concierge-ask" | "concierge-say" | "concierge-policy" | "concierge-suggest" | "concierge-reply" | "concierge-act" | "concierge-order"; export declare const CONCIERGE_OPS: readonly ConciergeOp[]; /** The parts of a job's record the concierge's own launch is built from. */ export type ConciergeLaunchSource = Pick; /** Who is on the other end of a connection `C`. */ export interface ConciergeSessionsPort { /** The connection's peer (throws what the daemon throws for a connection that is not one). */ require(conn: C): ConciergePeer; /** The connection's peer, if it has one (none: the hub's). */ optional(conn: C): ConciergePeer | undefined; /** Runs `what` on job `id` as the hub's op (the policy let the concierge). */ asHub(conn: C, what: "stop" | "respawn", id: string): Promise; } /** The jobs: sessions the daemon runs. */ export interface ConciergeJobsPort { exists(id: string): boolean; /** The job's worker is up. */ live(id: string): boolean; row(id: string): JobRow | undefined; /** Every row (the digest's fleet; a target by name). */ list(): JobRow[]; /** The job's state name from its state file (a suggestion lives while the row is blocked). */ stateOf(id: string): string | undefined; /** The record the concierge's own launch is built from. */ launchOf(id: string): ConciergeLaunchSource | undefined; /** A session file some job already owns. */ sessionFileUsed(file: string): boolean; /** The path exists on disk. */ pathExists(path: string): boolean; dispatch(launch: DispatchArgs, extra?: { role: "concierge"; }): Promise<{ id: string; name: string; }>; respawn(id: string): Promise; /** Stops the job's host. */ terminate(id: string): Promise; /** An answer as a reply (the user's, or by `by`). */ reply(args: { id: string; text: string; mode?: string; }, by?: { who: string; whoId: string | null; }): Promise<{ delivered: boolean; saved: boolean; error?: string; }>; /** The digest as an agent item to job `id`; `reached`: it is with the session, or kept for it. */ deliver(id: string, text: string): Promise<{ outcome: string; reached: boolean; }>; /** The job's row changed (the hub's line). */ pushJob(id: string): void; } /** The event feed. */ export interface ConciergeEventsPort { since(q: { after: number; limit: number; }): { events: RoostEvent[]; cursor: number; }; cursor(): number; } /** A file the module keeps (the daemon's writes atomically under the roost's home). */ export interface ConciergeStore { read(): unknown; write(v: unknown): void; } export interface ConciergeDeps { sessions: ConciergeSessionsPort; jobs: ConciergeJobsPort; events: ConciergeEventsPort; /** The state file (concierge.json) and the orders (orders.json). */ store: ConciergeStore; ordersStore: ConciergeStore; record(e: Omit): void; /** To the hub's subscribers. */ push(event: Event): void; log(level: "info" | "warn" | "error", msg: string, extra?: Record): void; /** The `concierge` setting, with its defaults. */ config(): ConciergeConfig; /** The shared task board (the digest lists it). */ board(): BoardTask[]; /** The daemon is going down: nothing is woken. */ shuttingDown(): boolean; clock?: Clock; /** A burst of events is one wake (default 5 s). */ coalesceMs?: number; /** A wake held back by the hourly cap or a full queue is tried again after this (default 60 s). */ retryMs?: number; /** How often the heartbeat looks (default 30 s). */ tickMs?: number; /** Tests shorten the heartbeat below what the setting allows (default: the setting's). */ heartbeatMs?: number; } export interface Concierge { /** Loads both files; call once the jobs are known (a suggestion for a row that no longer waits is dropped). */ load(): void; /** Arms the heartbeat and nudges once (what happened while the service was off). */ start(): void; /** Clears every timer. */ stop(): void; /** An op of the family (args as the socket brings them). */ op(name: ConciergeOp, conn: C, args: any): Promise; /** Something happened: wake it once the burst is over. */ nudge(): void; status(): ConciergeStatus; isConcierge(id: string | undefined | null): boolean; /** The peer is the concierge's own job. */ isPeer(peer: ConciergePeer): boolean; /** An event of its own doing (not in its digests, not news to it). */ own(e: Pick): boolean; /** A name a session reports for itself: not the concierge's, unless it is the concierge. */ safeName(id: string, name: string | null | undefined): string | null; /** The launch of a session the concierge starts (built from its own job's). */ launch(launch: DispatchArgs): DispatchArgs; /** Whether the policy lets it start, stop and restart sessions. */ mayAct(): boolean; /** `{ suggested }` for a row the concierge has a suggestion for (null: stale), else `{}`. */ suggestionField(id: string, st: { state?: unknown; question?: unknown; }): { suggested?: JobRow["suggested"]; }; /** A suggestion for the row is spent or stale; true when there was one. */ dropSuggestion(id: string): boolean; /** A job was removed (call after its record goes): the concierge's is the concierge off; another's suggestion goes. */ removed(id: string): void; } export declare function createConcierge(deps: ConciergeDeps): Concierge;