/** * RelaySessionManager — tracks the relay side of mesh session sharing. * * When a remote peer subscribes to one of our local PTY sessions, we create * a "relay session" that forwards output from the source session to that * peer's `MeshPTYTransport`. Each (sourceSessionId, viewerPeerId) pair has * its own relay so we can scope subscriptions and clean up per-peer on * disconnect. * * Ported from vibe-ctl's * packages/desktop/src/main/services/foundation/pty/remote-sessions/relay-session-manager.ts * * Design note (deviation from vibe-ctl): * vibe-ctl delegates to `createRelaySession` from * `@claude-code-on-the-go/shared`, which wraps a `ProxyPTYSession` with * event plumbing. Avocado doesn't ship a concrete `ProxyPTYSession` — * `BasePTYSession` is the only session primitive in `#types` and * the app supplies the concrete classes via `ProxySessionFactory`. The * relay side lives entirely inside the owner device and never becomes * a first-class entry in `PTYSessionManager`, so we inline a lightweight * `RelayPTYSession` here that: * - listens for `'output'`/`'resized'`/`'exit'` on the source session * - forwards each event to the viewer via `MeshPTYTransport` owner-side * sends (sendOutput, sendResized, sendSessionEnded) * - disposes when the source exits or the viewer disconnects * * This keeps the relay logic contained and avoids pulling a ProxyPTYSession * concrete class into the transport package. * * The `ITerminalStoreSync` dependency is currently reserved for future * focus/authority coordination — the constructor accepts it for API parity * with vibe-ctl, but the v0.1 relay itself is focus-agnostic (cooperative * focus, last-write-wins per plan D5). Store-based terminal mode handling * stays in RemoteSessionService / the consumer app. */ import { EventEmitter } from 'events'; import type { IPTYSession } from '#types'; import type { ITerminalStoreSync } from '#core'; import type { MeshPTYTransport } from './mesh-pty-transport.js'; /** * Forwards events from a local source session to a remote viewer. * * This is an internal helper class — it is not registered with * `PTYSessionManager` and is not exposed outside the package. It exists * purely to hold the forwarding listeners so they can be detached cleanly * on `dispose()`. */ export declare class RelayPTYSession extends EventEmitter { readonly id: string; readonly sourceSessionId: string; readonly viewerPeerId: string; private readonly source; private readonly transport; private disposed; private readonly onSourceOutput; private readonly onSourceResized; private readonly onSourceExit; private readonly onSourceDisposed; private readonly onTransportDisconnected; constructor(source: IPTYSession, transport: MeshPTYTransport, viewerPeerId: string); dispose(): void; get isDisposed(): boolean; } export interface RelaySessionManagerEvents { relayCreated: (sessionId: string, peerId: string, relay: RelayPTYSession) => void; relayDisposed: (sessionId: string, peerId: string) => void; } export interface IRelaySessionManager extends EventEmitter { createRelay(sourceSession: IPTYSession, transport: MeshPTYTransport, targetPeerId: string): RelayPTYSession; getRelay(sessionId: string, peerId: string): RelayPTYSession | null; hasRelay(sessionId: string, peerId: string): boolean; disposeRelay(sessionId: string, peerId: string): void; getRelaysForSession(sessionId: string): Map; cleanupForDevice(peerId: string): number; dispose(): void; on(event: K, listener: RelaySessionManagerEvents[K]): this; emit(event: K, ...args: Parameters): boolean; } export declare class RelaySessionManager extends EventEmitter implements IRelaySessionManager { private readonly relays; private readonly _terminalStoreSync; constructor(terminalStoreSync?: ITerminalStoreSync); /** Compose the composite relay key. */ private static key; createRelay(sourceSession: IPTYSession, transport: MeshPTYTransport, targetPeerId: string): RelayPTYSession; getRelay(sessionId: string, peerId: string): RelayPTYSession | null; hasRelay(sessionId: string, peerId: string): boolean; disposeRelay(sessionId: string, peerId: string): void; getRelaysForSession(sessionId: string): Map; cleanupForDevice(peerId: string): number; dispose(): void; } export declare function createRelaySessionManager(terminalStoreSync?: ITerminalStoreSync): IRelaySessionManager; //# sourceMappingURL=relay-session-manager.d.ts.map