| 468 | } |
| 469 | |
| 470 | function toWaitTarget(parsed: WaitParsed, session: SessionState | undefined) { |
| 471 | if (parsed.kind === 'sleep') return { kind: 'sleep' as const, durationMs: parsed.durationMs }; |
| 472 | if (parsed.kind === 'selector') { |
| 473 | return { |
| 474 | kind: 'selector' as const, |
| 475 | selector: parsed.selectorExpression, |
| 476 | timeoutMs: parsed.timeoutMs, |
| 477 | }; |
| 478 | } |
| 479 | if (parsed.kind === 'ref') { |
| 480 | if (!session?.snapshot) { |
| 481 | throw new AppError('INVALID_ARGS', 'Ref wait requires an existing snapshot in session.'); |
| 482 | } |
| 483 | return { kind: 'ref' as const, ref: parsed.rawRef, timeoutMs: parsed.timeoutMs }; |
| 484 | } |
| 485 | if (!parsed.text) throw new AppError('INVALID_ARGS', 'wait requires text'); |
| 486 | return { kind: 'text' as const, text: parsed.text, timeoutMs: parsed.timeoutMs }; |
| 487 | } |
| 488 | |
| 489 | async function toDaemonResponse( |
| 490 | task: () => Promise<Record<string, unknown>>, |