import { standaloneConnectOpts, type CompletionResult, type FlagValues, type ParsedArgs, type SpaceAuth } from "@cotal-ai/core"; import { type ConnectFlags, type OutputWarning, type Styled } from "@cotal-ai/workspace"; import { type ScatterInstanceLiveness, type ScatterInstanceReply, type ManagerPin } from "../lib/control.js"; export declare const stopFlags: readonly [{ readonly name: "space"; readonly short: "s"; readonly type: "string"; readonly value: ""; readonly description: "target space (default: the resolved mesh)"; }, { readonly name: "server"; readonly type: "string"; readonly value: ""; readonly description: "broker URL (overrides the mesh registry entry)"; }, { readonly name: "creds"; readonly type: "string"; readonly value: ""; readonly description: "creds file for an off-registry connection"; }, { readonly name: "name"; readonly type: "string"; readonly value: ""; readonly description: string; }, { readonly name: "self"; readonly type: "boolean"; readonly description: "stop only the verified managed seat running this command"; }, { readonly name: "force"; readonly type: "boolean"; readonly description: "request native hard despawn (graceful:false); does not bypass authority"; }, { readonly name: "on"; readonly type: "string"; readonly value: ""; readonly description: "ask only this manager instance, by the id `ps` prints, in a space with several managers"; }, { readonly name: "json"; readonly short: "j"; readonly type: "boolean"; readonly description: "structured output on stdout"; }, { readonly name: "plain"; readonly type: "boolean"; readonly description: "plain line-oriented output"; }]; export declare const psFlags: readonly [{ readonly name: "space"; readonly short: "s"; readonly type: "string"; readonly value: ""; readonly description: "target space (default: the resolved mesh)"; }, { readonly name: "server"; readonly type: "string"; readonly value: ""; readonly description: "broker URL (overrides the mesh registry entry)"; }, { readonly name: "creds"; readonly type: "string"; readonly value: ""; readonly description: "creds file for an off-registry connection"; }, { readonly name: "on"; readonly type: "string"; readonly value: ""; readonly description: "ask only this manager instance, by the id `ps` prints, in a space with several managers"; }, { readonly name: "wide"; readonly type: "boolean"; readonly description: "also print the per-seat facts the manager already records: cwd, pid, spawner, lifecycle uid, host/instance"; }, { readonly name: "json"; readonly short: "j"; readonly type: "boolean"; readonly description: "structured output on stdout"; }, { readonly name: "plain"; readonly type: "boolean"; readonly description: "plain line-oriented output"; }, { readonly name: "slots"; readonly type: "boolean"; readonly description: "list the durable static slots instead of live seats; not with --wide"; }]; export declare const attachFlags: readonly [{ readonly name: "space"; readonly short: "s"; readonly type: "string"; readonly value: ""; readonly description: "target space (default: the resolved mesh)"; }, { readonly name: "server"; readonly type: "string"; readonly value: ""; readonly description: "broker URL (overrides the mesh registry entry)"; }, { readonly name: "creds"; readonly type: "string"; readonly value: ""; readonly description: "creds file for an off-registry connection"; }, { readonly name: "name"; readonly type: "string"; readonly value: ""; readonly description: string; }, { readonly name: "on"; readonly type: "string"; readonly value: ""; readonly description: "ask only this manager instance, by the id `ps` prints, in a space with several managers"; }, { readonly name: "no-reconnect"; readonly type: "boolean"; readonly description: "exit when the session ends instead of re-establishing it"; }]; /** `cotal input`: type into a seat without holding a terminal open. `--text` is a VALUE flag, so * its argument is taken verbatim and may begin with `/` or `-` (`--text "/compact"`) - which is * the point: a harness command is exactly the payload that would be eaten by a positional * grammar. `--no-enter` is a declared boolean literally named `no-enter` rather than a negation * of an `enter` flag: node's `parseArgs` does not negate under `strict`, and the CLI already * spells this shape (`--no-open`, `--no-replay`). */ export declare const inputFlags: readonly [{ readonly name: "space"; readonly short: "s"; readonly type: "string"; readonly value: ""; readonly description: "target space (default: the resolved mesh)"; }, { readonly name: "server"; readonly type: "string"; readonly value: ""; readonly description: "broker URL (overrides the mesh registry entry)"; }, { readonly name: "creds"; readonly type: "string"; readonly value: ""; readonly description: "creds file for an off-registry connection"; }, { readonly name: "name"; readonly type: "string"; readonly value: ""; readonly description: string; }, { readonly name: "text"; readonly type: "string"; readonly value: ""; readonly description: "the text to type, verbatim (required); quote it when it starts with / or -"; }, { readonly name: "no-enter"; readonly type: "boolean"; readonly description: "type the text without pressing Enter after it"; }, { readonly name: "on"; readonly type: "string"; readonly value: ""; readonly description: "ask only this manager instance, by the id `ps` prints, in a space with several managers"; }, { readonly name: "json"; readonly short: "j"; readonly type: "boolean"; readonly description: "structured output on stdout"; }, { readonly name: "plain"; readonly type: "boolean"; readonly description: "plain line-oriented output"; }]; export declare function managedAgentComplete(argv: string[]): CompletionResult; /** The named target grammar, checked before any command preparation. */ export declare function managedTarget(args: ParsedArgs, operation: "stop" | "attach", allowPicker?: boolean): string | undefined; export declare function validateStopArguments(args: ParsedArgs): void; export declare function stop(args: ParsedArgs): Promise; type AgentRow = { name: string; role?: string; agent: string; mode: string; status: string; uptimeMs: number; mesh: string; /** The harness-reported presence condition beside `mesh`; absent when none was reported. */ condition?: { code: string; source?: string; message?: string; since?: number; }; /** Epoch ms of the seat's last reported work progress; absent when none was reported. */ activeAt?: number; /** The manager's own presence-view state when it built the row; absent from older managers. */ meshView?: "current" | "stale" | "unpopulated"; /** Manager's exact principal + UID comparison for the name-matched presence row. */ presenceIdentityVerified?: boolean; /** Manager snapshot time, only on a current exact-identity presence row. */ presenceObservedAt?: number; /** Epoch ms of the seat's last heartbeat, only beside an `offline` verdict; absent from older managers. */ offlineSince?: number; authHealth?: string; authReason?: string; model?: string; variant?: string; provider?: string; cwd?: string; pid?: number; spawner?: string; instanceId?: string; host?: string; /** A `--resume` seat's fork provenance (#1500); title and hash once the seat has recorded them. */ resume?: { source: string; title?: string; transcriptSha256?: string; host?: string; transferredAt?: string; }; lifecycleUid: string; id: string; }; /** A seat's compact runtime identity. Model is provenance, not a debugging detail, so it belongs * beside the connector in the default row. `variant` is the requested override the manager * recorded: when no override was requested it stays absent rather than inventing an effective * provider default Cotal cannot observe. */ export declare function agentIdentity(r: Pick): string; /** * WHERE does the named seat live? A `stop` or `attach` can only be served by the manager actually * HOSTING the seat, and the class queue does not know which one that is — so without this the verb * is answered by whichever instance wins the race and fails on a seat that plainly exists. * * This is a POSITIVE lookup, not a retry after a miss, and that is forced by measurement: a manager * asked about a seat it does not host answers `not-found: no agent ""` — the SAME code and the * same message it gives for a name that exists nowhere. "Hosted elsewhere" and "does not exist" are * indistinguishable from a single manager's answer, so a caller that retried on a miss would scatter * for a typo and, worse, could only ever report the ambiguous message. Asking every instance is the * only construction that can tell the two apart — which is also what lets the error finally say * which case it is. * * Costs a second one-shot instrument. The scatter's freeze read belongs to the PRIVILEGED tier; * `stop`/`attach` mint ADMIN, which is denied that read deliberately ("the admin tier never * scatters"). Rather than widen admin for convenience, the lookup runs as its own privileged * instrument and the admin instrument is then minted pinned to the answer. */ export type SeatLocation = { kind: "pin"; instanceId: string; } | { kind: "unpinned"; } | { kind: "absent"; checked: number; } /** #1638 item 3: the search could not settle. At least one registered instance did not answer * FOR ITSELF, so the seat may be sitting on it; absence is not what was established. */ | { kind: "unknown"; answered: number; silent: string[]; refused: { instanceId: string; error: string; }[]; }; /** Exported for the console, which drives the same targeted verbs (`stop`/`attach`) from * inside a TUI and so needs the THROWING resolve: an unreachable mesh there is a notice on the * status line, never a `process.exit` that blanks the screen. The CLI commands keep the default. */ export declare function locateSeat(v: Pick, "space" | "server" | "creds">, name: string, opts?: { onRefusal?: "exit" | "throw"; }): Promise; /** * WHAT THE SCATTER ESTABLISHED about one seat name — the whole decision, as a function of the rows * alone, so it is gradable without a broker. * * ANSWERED FOR ITSELF means an instance returned its own roster. A slot that never answered and one * that answered with a REFUSAL are the same fact for this search: neither stated which seats it * hosts, so neither licenses a conclusion about a seat that might be sitting on it (#1638 item 3). * The refusal half is the reachable-but-errored row `scatterManager` reports, which the older * filter counted as a manager that had looked and found nothing. * * Absence is a claim about the WHOLE space, so it is concluded only when the whole space answered. */ export declare function locateSeatIn(instances: readonly ScatterInstanceReply[], name: string): SeatLocation; /** The console's wording for a seat the whole space proved absent. Main's richer `seatMissRefusal` * needs the `unknown` variant too; the console (and `attachSeat`'s returned verdict) only ever * hold a proved `absent`, so this stays the narrow shape their call sites guarantee. */ export declare function seatNotFoundMessage(loc: { checked: number; }, name: string, verb?: string): string; /** * What a `stop`/`attach`/`input` that did not find its seat TELLS the operator — and the difference * between the two things it can mean (#1638 item 3). * * ABSENT is a claim about the whole space and is only made when the whole space answered for * itself. A registration that gave no answer within the deadline is NOT told to "retry": a manager * whose host died never deregisters, so its row stays in the registry indefinitely and answers * nothing, and a retry against it loops forever. Say what is known (registered, silent), what it * may mean (a live slow host OR a dead registration), and the two real actions. * * UNKNOWN is the other case and it used to print as the first one. The seat may be sitting on the * instance that did not answer, so "no managed agent " was a definite negative drawn from an * incomplete search — and it names the instance COUNT, which is the shape a reader believes. * Measured on a live mesh: a seat that `ps` listed as running the whole time was reported absent, * and the same command with `--on` succeeded first time. A retry loop that reads the old sentence * as "already gone" stops looking for a seat that is still running. */ export declare function seatMissRefusal(name: string, verb: string, loc: Extract): string; /** The mesh column of one `ps` row. A verdict needs a fresh observer: when the manager reports its * own presence view as `stale` (its watch went silent past TTL) or `unpopulated` (its watch has not * replayed the bucket yet), `offline` and `absent` describe the manager's watch, not the seat. Print * "mesh unknown" with the reason instead of a liveness word an operator, or a watchdog, would act * on. A row from a manager that predates `meshView` carries no field and renders as before. * An offline verdict says how long it has stood when the row carries `offlineSince` (#1208), so a * seat that dropped a minute ago reads differently from one that dropped two days ago. */ export declare function meshCell(r: Pick, now?: number): Styled; /** {@link wideFields} as one line of facts. */ export declare function agentWideFacts(r: Pick): string[]; /** What one manager instance answered a `ps` census with. */ export interface ManagerAnswer { readonly instanceId: string; /** `answered`; `silent` (registered, no answer within the deadline); `refused` (it answered with an * error); `contract-mismatch` (it serves a different `ps` contract, so its rows were not read). */ readonly state: "answered" | "silent" | "refused" | "contract-mismatch"; /** What this command established about a silent instance's liveness. */ readonly liveness?: ScatterInstanceLiveness; /** A refusal's own sentence, with the endpoint's code when it carried one. */ readonly error?: string; readonly code?: string; } /** What `cotal ps` read: each seat (or, with `--slots`, each static slot) exactly as its manager * returned it, and what each manager instance asked answered. A manager that did not answer is * listed, never dropped, so a short list is not mistaken for a complete one. */ export interface PsResult { readonly kind: "seats" | "slots"; readonly items: readonly unknown[]; readonly managers: readonly ManagerAnswer[]; } export declare function ps(args: ParsedArgs): Promise; /** A named-agent detail uses the same authorized census as ps, never an invented process view. */ export declare function agentStatus(args: ParsedArgs): Promise; /** One census of the managed seats (or, for `slots`, the static slots): each answered manager * instance's rows as it returned them, every instance's answer, a warning for each one that did not * return its rows, and the partial notice when any did not. */ export interface SeatCensus { readonly target: { space: string; scope: string; managerInstanceId?: string | null; }; readonly items: unknown[]; readonly managers: ManagerAnswer[]; readonly warnings: OutputWarning[]; readonly rowsOf: Map; readonly partial?: { message: string; remedy: string; }; } /** Read the managed seats the way `ps` lists them: from one manager when `on` pins it or the caller * holds a user bearer, otherwise from every registered instance. Throws the classified failure when * the target cannot be resolved or no manager can be asked. */ export declare function readSeats(v: ConnectFlags, command: "ps" | "slots", on: string | undefined): Promise; /** Race a link round trip against a deadline, and answer `no` if the deadline wins. The timer is * deliberately NOT unref'd: it is the only thing keeping the process alive while we wait on a * socket that will never answer, and an unref'd one lets node empty its loop and abort the whole * command on a pending await instead of finishing the wait and printing why. It is cleared as soon * as either side settles, so a healthy link is never held open for the remainder of the deadline. */ export declare const withDeadline: (work: Promise, ms: number) => Promise; /** What a caller should DO about a manager refusal. `denied` will not change by asking again; * `gone` is the seat the manager no longer knows, so there is nothing left to attach to; anything * else is worth another attempt. */ export type AttachRefusal = "denied" | "gone" | "transient"; /** * Classify a refusal on the manager's structured error, never on its wording. The wording is * operator copy and changes; the code and namespaced detail are the contract. Getting this wrong in * either direction is a real failure: reading `permission-denied` as transient turns a refusal into * an infinite retry loop against a manager that has already said no, and reading `not-found` or an * `inspect` static-slot observation as transient does the same to a seat that no longer exists. * Other `failed-precondition` refusals remain transient, including the session ceiling. */ export declare function attachRefusal(code: string | undefined, details?: Array<{ kind: string; }>): AttachRefusal; /** * What a re-establishment TELLS the operator while it keeps trying, and what it keeps to itself. * Returns the line to print, or undefined for silence. * * Only the MANAGER's own refusal is relayed, and only when it changes. An operator watching * `reconnecting` for ten minutes cannot otherwise tell a sleeping laptop from a manager that is at * its session ceiling, and the ceiling is the one a person can act on. Repeating a steady refusal * on every attempt would bury it. * * A LOCAL failure to reach anything is deliberately silent: it is already what `connection lost, * reconnecting` says, and the copy on this path is written for someone who just typed a command * ("no mesh running at X - run `cotal up`"), which is the wrong thing to tell someone whose wifi * dropped. */ export declare function reconnectNotice(est: { fromManager?: true; message: string; }, alreadySaid: string): string | undefined; /** * The line an exit owes an operator about sessions this attach could not hand back, or nothing. * * Suppressed on `gone`, and that is not tidiness. That verdict exists only when the manager proves * the live seat is absent: either `not-found`, or the namespaced durable static-slot observation * after its process is gone. Freeing a seat ends every session bound to it (`freeSlot` into * `endForTarget`, on despawn, self-stop, reap and natural exit alike). The sessions this would name * have already been collected, so naming them would be inventing work for someone who is about to * close their terminal. */ export declare function heldSessionNotice(pending: number, verdict: AttachVerdict["kind"]): string | undefined; /** The mesh contract that decides how attach redeems a session grant. The mode is the REGISTERED * one (`MeshTarget.mode`), carried forward from the resolve. It is the only input to the decision: * `spaceAuth` says whether a SEALED mesh's seed is present, and is never consulted to decide which * kind of mesh this is. */ export type AttachSessionTarget = { space: string; server: string; root?: string; spaceAuth?: SpaceAuth; mode?: "auth" | "open" | "user"; auth: { bearer?: unknown; }; }; /** * HOW this mesh's session grant is redeemed, as a closed union with no optional credential. * * `bare` and `session-caller` are structurally distinct rather than "session-caller, but the creds * may be missing". That distinction is the whole fix for #1205. An optional `creds?: string` on the * redeem path invites exactly one question at every call site — "is the seed there?" — and answering * it with `!creds` is the defect: an OPEN mesh has no seed BY DESIGN, so absence means "bare", * while on a SEALED mesh the same absence means "refuse". One field cannot carry both meanings, so * the mode is named and the compiler makes every consumer read the name. */ export type RedeemLink = { mode: "bare"; tls: boolean; } | { mode: "session-caller"; tls: boolean; creds: string; } | { mode: "session-bearer"; tls: boolean; bearer: string; sentinelCreds: string; }; /** The ONE place a {@link RedeemLink} becomes NATS connect options. Both connections on the redeem * path (the session link and the abandoned-session hand-back) go through here, so neither can * invent a credential for an open mesh or drop one on a sealed mesh, and a third caller gets the * same two arms for free. */ export declare function redeemConnectOpts(link: RedeemLink): ReturnType; /** * Which redeem contract this target gets: a bare open-mesh connection, a seed-backed mint, or a * loud refusal. Graded by `smoke:attach-open-mode`, whose mutations flip each arm in turn. * * EXHAUSTIVE over the three recorded modes on purpose, with `user` named rather than reached by * fallthrough. A `user` entry holds no local seed by design and its two-step redemption is not * wired, so it must refuse even on the day a user-mode root happens to carry static material on * disk; letting it fall through to the seed test would silently mint on the wrong identity plane. * An UNRECORDED mode (a raw off-registry connection) is the conservative arm: it is not known to be * open, so it takes the sealed test and refuses without a seed. */ export declare function attachSessionMaterial(t: AttachSessionTarget): { kind: "bare"; } | { kind: "mint"; auth: SpaceAuth; } | { kind: "redeem"; } | { kind: "fatal"; message: string; }; /** How the attach finished, decided inside the loop and acted on outside it — so the terminal is * always given back before anything prints or exits. */ export type AttachVerdict = { kind: "ended"; reason: string; } | { kind: "gone"; } | { kind: "failed"; message: string; }; /** What an attach needs to know: the mesh coordinates the control commands take, plus the seat, * plus what an unresolvable mesh does on the first attempt (`exit`, the command's default, or * `throw`, which the console needs because an exit inside a TUI blanks the screen). */ export type AttachTarget = Pick, "space" | "server" | "creds"> & { name: string; onRefusal?: "exit" | "throw"; expectedTarget?: ManagerPin["expectedTarget"]; asSeat?: boolean; }; /** * The whole attach, as one call: seat locality, the establish-redeem-drive loop with its reconnect, * end-reason classification and abandoned-session hand-back, and the terminal given back before * the verdict is returned. `cotal attach` and the console's `a` / `:attach` both run THIS, so the * console can never drift into a lesser attach. `onRefusal` chooses what an unresolvable mesh or * an absent seat does: the command prints and exits; the console needs a returned verdict, because * an exit inside a TUI blanks the screen. The pin, when the caller already knows it (`--on`), is * honoured; otherwise the seat is located the way `stop` locates it. */ export declare function attachSeat(v: AttachTarget, opts: { reconnect: boolean; onRefusal: "exit" | "throw"; on?: string; }): Promise; export declare function attach(args: ParsedArgs): Promise; /** * `cotal input --name --text [--no-enter]`: deliver one line of text into a running * seat's terminal, as if a human had typed it. The command an external control surface needs that * `attach` cannot be: `attach` is a stream that holds a session and wants a pty on this side, and a * web request has neither. * * Routing is `attach`'s, unchanged: the seat-locality pin first (only the manager HOSTING the seat * can type into it), then the reach that mesh mode implies. Nothing is echoed back - the caller * reads the resulting turns from the event plane or the transcript, so this prints only what was * delivered. */ export declare function inputArguments(args: ParsedArgs): { name: string; text: string; }; export declare function input(args: ParsedArgs): Promise; export {}; //# sourceMappingURL=agents.d.ts.map