/** * hooteams team client (`--team `). * * Connects to a running hooteams server, registers every role as a * kind="role" agent in the task store, and maps the server's TeamEvent SSE * stream onto task-store patches so the task panel's existing "teams" view * shows live role state. On top of that mirror the connection exposes * steering (POST /steer) and an event subscription used by the attach * side-panel — both share the single /events stream; no second SSE * connection is ever opened. * * The connection is best-effort by design — a connect failure or a later * drop logs a warning and never blocks (or crashes) the main agent. At most * one SSE connection (to /events) is open at any time. */ import { taskStore } from "./task-store.js"; /** Shape of GET /status: coarse per-role status keyed by role name. */ export type TeamStatusSnapshot = Record; /** One frame of GET /events: a hoocode AgentEvent tagged with its producer. */ export interface TeamViewEvent { type: string; role: string; agentId?: string; ts?: number; toolName?: string; args?: unknown; isError?: boolean; /** Streaming assistant-message delta carried by message_update events. */ assistantMessageEvent?: { type?: string; delta?: string; }; message?: { role?: string; errorMessage?: string; usage?: { input?: number; output?: number; cost?: { total?: number; }; }; }; /** Task lifecycle fields carried by task_* events from the orchestrator. */ taskId?: string; /** Approval gate carried by task_paused. */ question?: string; options?: string[]; /** Answer carried by task_resumed. */ chosenOption?: string; /** "done" | "error" on task_finished. */ status?: string; /** Run id carried by dag_complete / dag_failed. */ runId?: string; } /** One unanswered approval gate from GET /tasks/pending. */ export interface TeamPendingApproval { taskId: string; question: string; options: string[]; } /** * Maps team status snapshots and TeamEvents onto task-store patches. * * Each role owns one roster entry (id `team:`) and at most one task whose * title tracks the role's latest activity. Tasks exist only while a role is * actually doing something (active/running, or failed so the error is visible); * idle roles keep their roster entry but no task — the panel's teams lens * renders them as placeholder groups, so a quiet team reads as an idle roster * instead of pinning the pane at "working". Entries are re-created on demand * because taskStore.reset() wipes finished tasks between user turns. */ export declare class TeamViewMapper { private readonly store; private readonly taskIds; constructor(store?: typeof taskStore); /** Register roles from a GET /status snapshot. */ applyStatus(snapshot: TeamStatusSnapshot): void; /** Map one TeamEvent from GET /events onto the store. */ applyEvent(event: TeamViewEvent): void; private agentId; /** * Make sure the role's roster entry exists, plus its task when the state * warrants one (reset() may have dropped both). Idle/done states never * create a task — only patch one that live activity already opened. */ private ensureRole; private patchRole; } export interface TeamViewOptions { /** Warning sink; defaults to console.error. */ warn?: (message: string) => void; /** Store override for tests. */ store?: typeof taskStore; /** Delay between reconnect attempts in ms (default 5000). */ retryDelayMs?: number; } export interface TeamViewConnection { /** Close the SSE connection and stop reconnecting. */ stop(): void; /** POST /steer { role, message }. Rejects on network or HTTP error. */ steer(role: string, message: string): Promise; /** * Answer a paused task: POST /tasks/:taskId/resume { option, feedback? }. * Rejects with "answered elsewhere" on 409 (first answer wins across * surfaces) and with HTTP/network errors otherwise. */ resume(taskId: string, option: string, feedback?: string): Promise; /** * GET /tasks/pending — gates that opened before we attached. Resolves to * [] when the server has no active run (404) so callers need no special * casing. */ pendingApprovals(): Promise; /** * Subscribe to every TeamEvent delivered by the shared /events stream. * Returns an unsubscribe function. Listeners receive events for all roles; * per-role filtering is the subscriber's job (the attach panel filters). */ subscribe(listener: (event: TeamViewEvent) => void): () => void; /** Number of live event subscribers. Exposed for leak tests. */ subscriberCount(): number; } /** * Start the read-only team view against a hooteams server base URL. * * Returns immediately; all network work happens in the background and any * failure is reported through `warn` without ever throwing. */ export declare function connectTeamView(url: string, options?: TeamViewOptions): TeamViewConnection; //# sourceMappingURL=team-view.d.ts.map