target-errors.ts
1 /** 2 * Structured error types for the target resolution system. 3 * 4 * Every browser action (click, type, select, get) that targets a DOM element 5 * goes through the unified resolver. When resolution fails, one of these 6 * structured errors is thrown so that AI agents and adapter authors get 7 * actionable diagnostics instead of a generic "Element not found". 8 * 9 * Numeric-ref codes (from snapshot indices): 10 * - not_found: the ref no longer exists in the DOM 11 * - stale_ref: the ref still exists but points to a different element 12 * 13 * CSS-selector codes (from `--selector <css>` entrypoints): 14 * - invalid_selector: selector syntax rejected by querySelectorAll 15 * - selector_not_found: 0 matches 16 * - selector_ambiguous: >1 matches for a write op without --nth 17 * - selector_nth_out_of_range: --nth beyond matches_n 18 */ 19 20 export type TargetErrorCode = 21 | 'not_found' 22 | 'stale_ref' 23 | 'invalid_selector' 24 | 'selector_not_found' 25 | 'selector_ambiguous' 26 | 'selector_nth_out_of_range'; 27 28 export interface TargetErrorInfo { 29 code: TargetErrorCode; 30 message: string; 31 hint: string; 32 candidates?: string[]; 33 /** CSS-path match count, when the error was raised mid-resolution */ 34 matches_n?: number; 35 } 36 37 export class TargetError extends Error { 38 readonly code: TargetErrorCode; 39 readonly hint: string; 40 readonly candidates?: string[]; 41 readonly matches_n?: number; 42 43 constructor(info: TargetErrorInfo) { 44 super(info.message); 45 this.name = 'TargetError'; 46 this.code = info.code; 47 this.hint = info.hint; 48 this.candidates = info.candidates; 49 this.matches_n = info.matches_n; 50 } 51 52 /** Serialize for structured output to AI agents */ 53 toJSON(): TargetErrorInfo { 54 return { 55 code: this.code, 56 message: this.message, 57 hint: this.hint, 58 ...(this.candidates && { candidates: this.candidates }), 59 ...(this.matches_n !== undefined && { matches_n: this.matches_n }), 60 }; 61 } 62 }