import type { BoardTask } from "./board.js"; import { type ArgsOf, type Event, type HelloArgs, type HelloResult, type Op, type PeerRow, type ResultOf, type SendResult, type WorkerReport } from "./protocol.js"; /** A delivered reply or agent item (M9 adds the kind). */ export type DeliverItem = Pick, "seq" | "text" | "kind" | "from" | "relation" | "mode">; export interface JobIdentity { id: string; token: string; socket: string; } /** * Set in a worker's environment by the PTY host. The token is removed from the * environment once read (M9), so a /reload finds the identity kept in this process. */ export declare function jobIdentity(env?: NodeJS.ProcessEnv): JobIdentity | undefined; /** * Sends the latest report, one request at a time, reconnecting after daemon * restarts; never throws. State changes go out at once, row text at most * every SUMMARY_INTERVAL_MS. */ export declare class Reporter { private client; private latest; private sent; private sentAt; private urgentPending; private timer; private dueAt; private inflight; private retryMs; /** M22: after a failed request nothing goes out before this (not even a state change). */ private backoffUntil; private closed; private job; private onDeliver; /** Row text and context use alone go out at most this often (tests shorten it). */ private intervalMs; /** M31: said on every new connection before the first report. */ private hello; /** M31: what the daemon answered (undefined: no answer yet, or a daemon from before M31). */ daemonHello: HelloResult | undefined; constructor(job: JobIdentity, onDeliver?: (item: DeliverItem) => void, intervalMs?: number, hello?: HelloArgs); /** `urgent`: send now even when only the row text changed (a model summary). */ update(report: WorkerReport, urgent?: boolean): void; /** Send what is pending (bounded wait), then disconnect. */ close(): Promise; private drain; private schedule; private send; /** Tell the daemon a reply reached pi; best effort, a lost ack means a resend that is deduplicated. */ ack(seq: number, exact?: boolean): void; /** * M9: a request on this worker's own connection, which the daemon knows as this job * once a report went through on it. */ call(op: O, args: ArgsOf): Promise>; private request; } /** M31: a reply as an agent sees it: once each, in order, acked when its handler returns. */ export interface AgentReply { seq: number; text: string; /** "steer": join the work under way; "followUp" or absent: after it. */ mode?: "steer" | "followUp"; } /** M31: the report an agent gives; what it leaves out is filled in (a full snapshot goes). */ export type AgentReport = Partial & Pick; /** * M50: an item from another session (the `agent-items` capability): a message (a peer's, * or a task the hub or the concierge handed over), a child's report, or a notice (a watch * that fired). `text` is the envelope the daemon wraps it in: who it is from, that it * carries no user authority. */ export interface AgentMessage { seq: number; kind: "message" | "report" | "notice"; text: string; /** The sender's name, and what it is to this session (parent, child, sibling, tree, external). */ from: string; relation: string; } export interface RoostAgentOptions { name: string; version?: string; /** What it can do (docs/protocol.md); "report" and "replies" are assumed. */ capabilities?: string[]; /** A user's reply; acked once this returns (or its promise settles). */ onReply?: (reply: AgentReply) => void | Promise; /** * M50: messages, reports and notices from other sessions. Given, the agent takes them * (it says `agent-items` and `peers`): they come in seq order with the replies, one at a * time, each acked once this returns. Not given, other sessions cannot message it. */ onMessage?: (message: AgentMessage) => void | Promise; /** Defaults to this process's environment. */ env?: NodeJS.ProcessEnv; } /** * M31: the agent side of the protocol for an agent other than pi, in a few calls: * * const agent = RoostAgent.fromEnv({ name: "my-agent", onReply: (r) => work(r.text) }); * agent?.report({ state: "working", summary: "reading the code" }); * * fromEnv gives undefined outside a roost job. Replies are handed over one at a time, in * seq order, never twice (the daemon resends unacked ones after a reconnect). */ export declare class RoostAgent { private reporter; /** Highest seq handed to the handler, and highest whose handler has returned (acked). */ private handled; private completed; private queue; private onReply; private onMessage; /** M35: where the last finished seq is kept, so a restarted agent does not redo a reply whose ack was lost. */ private mark; private constructor(); static fromEnv(o: RoostAgentOptions): RoostAgent | undefined; /** Its state now; sent at once when the state changed, the row text at most every few seconds. */ report(r: AgentReport): void; /** The daemon's hello answer, once connected (undefined before, or from a daemon before M31). */ get daemon(): HelloResult | undefined; /** Send what is pending, then disconnect. */ close(): Promise; /** M47: any op of the protocol (docs/protocol.md), as this job: answered, or refused by the daemon (an Error with its message). */ call(op: O, args: ArgsOf): Promise>; /** The sessions this one can reach (its tree; others when the user allows external messages). */ peers(): Promise; /** A message to a session, by id or by a name peers lists; the answer says whether it was delivered, queued or started it. */ send(to: string, message: string): Promise; /** Be told once (a notice to onMessage) when that session is next idle, or has ended. */ watch(id: string, when: "idle" | "ended"): Promise>; /** The board, every task (open, claimed, done, dropped), oldest first. */ tasks(): Promise; /** Take an open task: this job holds it until taskDone or releaseTask. Refused when another live session holds it (conflict), when it waits on tasks not done (blocked), or when it is done or dropped. */ claimTask(id: number): Promise; /** Mark the task this job holds done, with its result; tasks that waited on it become claimable. */ taskDone(id: number, result?: string): Promise; /** Give the task this job holds back to the board (open again). */ releaseTask(id: number): Promise; /** Put a task on the board for any session; after: task ids it waits on. */ addTask(title: string, opts?: { detail?: string; after?: number[]; }): Promise; private deliver; }