/** * P58.8 (S4, REQ-58-10) — in-memory child event bus. * * Subscribes to child session events via the OpenCode SDK and pushes a * bounded ring buffer per session. Used by `delegation-status {action: * "progress"}` to surface the latest event without re-running the * counter-based `progressPct` calculation. * * Design constraints (per 58-PLAN-08-GAP-FIX.md:233-237): * - ≤ 100 LOC module * - Ring buffer per session, capped at 100 events (drop oldest on overflow) * - Singleton export `childEventStream` * - Subscribe/unsubscribe wrap in try/catch — silent fallback to * counter-based progress when the SDK doesn't expose * `client.session.subscribe` (per R2 mitigation in the plan). * * The shape of an event is intentionally loose: `{ eventType, sessionId, * emittedAt, payload }`. Callers (delegation-status progress action) read * `eventType` and `payload` to render a meaningful "what is the child * doing right now" answer. */ /** * One event observed from a child session's SDK event stream. * `payload` is intentionally `Record` — the SDK's * event payload shape varies by `eventType` and version; we do not * validate at the bus boundary. */ export interface ChildEvent { eventType: string; sessionId: string; emittedAt: number; payload: Record; } /** * Subscription handle returned by `subscribe`. Stored in the bus so * `unsubscribe` can detach the listener when the delegation terminal. * Kept intentionally loose — the SDK's subscribe signature varies; * we hold onto whatever it returns so we can call any standard * unsubscribe / close method. */ type SubscriptionHandle = { close?: () => void | Promise; unsubscribe?: () => void | Promise; }; interface Logger { debug: (msg: string, data?: unknown) => void; warn: (msg: string, data?: unknown) => void; error: (msg: string, data?: unknown) => void; } export declare class ChildEventStream { private readonly events; private readonly subscriptions; private log; /** * Inject a logger. Default is no-op. Plugin composition root wires * the harness-level logger. */ setLogger(log: Logger): void; /** * Subscribe to events for a child session. Calls the SDK's * `client.session.subscribe(sessionId, handler)` if available; * otherwise returns silently (the caller can rely on counter-based * progress). All errors are caught and logged at warn level. */ subscribe(sessionId: string, sdkClient: { session?: { subscribe?: (id: string, handler: (event: unknown) => void) => Promise | SubscriptionHandle; }; }): Promise; /** * Unsubscribe the listener for a child session. Idempotent. Errors * from the SDK's close/unsubscribe are caught and logged. */ unsubscribe(sessionId: string): Promise; /** * Read the most recent event for a child session, or `null` if no * events have been recorded (or no subscription ever ran). */ getLastEvent(sessionId: string): ChildEvent | null; /** * Return live counters derived from the bus: * - `actionCount`: total events seen * - `messageCount`: events with eventType in {message, message.part} * - `toolCallCount`: events with eventType in {tool.call, tool.execute} * * The counter-based progressPct (in delegation-status) is a separate * signal that uses these counters as a fallback when the bus is * unavailable. */ getCounters(sessionId: string): { actionCount: number; messageCount: number; toolCallCount: number; }; /** * Test seam — wipe all events and subscriptions. Not for production * callers; the bus is intentionally module-singleton. */ __resetForTesting(): void; private pushEvent; } /** * Module-singleton instance. Wire this into the dispatch lifecycle: * `childEventStream.subscribe(childSessionId, sdkClient)` after a * delegation is dispatched; `childEventStream.unsubscribe(...)` on * terminal. The progress action in `delegation-status` reads via * `getLastEvent` and `getCounters`. */ export declare const childEventStream: ChildEventStream; export {}; //# sourceMappingURL=child-event-stream.d.ts.map