import { SessionManager } from '../state/session-manager.js';
import type { Session, SessionResult } from '../state/types.js';
export class TimeoutError extends Error {
constructor(message: string) {
super(message);
this.name = 'TimeoutError';
}
}
export interface WatcherOptions {
timeoutMs?: number;
pollIntervalMs?: number;
}
export class CompletionWatcher {
private sessionId: string;
private sessionManager: SessionManager;
private timeoutMs?: number;
private pollIntervalMs: number;
constructor(
sessionId: string,
sessionManager: SessionManager,
options: WatcherOptions = {}
) {
this.sessionId = sessionId;
this.sessionManager = sessionManager;
this.timeoutMs = options.timeoutMs;
this.pollIntervalMs = options.pollIntervalMs ?? 500;
}
async waitForCompletion(): Promise<SessionResult> {
const startTime = Date.now();
while (true) {
const session = await this.sessionManager.get(this.sessionId);
if (!session) {
throw new Error(`Session ${this.sessionId} not found`);
}
// Check if session is complete (any terminal state)
if (session.status !== 'active') {
return this.sessionManager.getResult(session);
}
// Check timeout
if (this.timeoutMs !== undefined) {
const elapsed = Date.now() - startTime;
if (elapsed >= this.timeoutMs) {
await this.sessionManager.markTimeout(this.sessionId);
const timedOutSession = await this.sessionManager.get(this.sessionId);
throw new TimeoutError(
`Session ${this.sessionId} timed out after ${this.timeoutMs}ms`
);
}
}
// Wait before polling again
await this.sleep(this.pollIntervalMs);
}
}
private sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
}