/** * TypeScript errors near the cursor, as prompt context ("TS errors as context") and for verifying generated * training data. Shared by the training pipeline and the daemon so the format is identical in both. * * Rendered as a pseudo-file in the repo header: * <|file_sep|>{dir}/__errors__.txt * TS2304 Cannot find name 'getU'. | const user = getU */ export interface Diagnostic { /** 0-based line in the visible file. */ line: number code: number message: string category: 'error' | 'warning' } /** * Errors that are noise for completion: environment problems (unresolved modules or types when dependencies * aren't installed) rather than mistakes in the code being written. */ export const IGNORED_CODES = new Set([ 2307, // Cannot find module 7016, // Could not find a declaration file for module 2792, // Cannot find module. Did you mean to set moduleResolution… 7006, // Parameter implicitly has an 'any' type 7031, // Binding element implicitly has an 'any' type 2875, // JSX tag requires the module path … to exist 6133, // declared but never read (unused), noise while writing 6196, // declared but never used ]) export function relevantDiagnostics(diags: Diagnostic[], cursorLine: number, opts: { window?: number; max?: number } = {}): Diagnostic[] { const window = opts.window ?? 20 const max = opts.max ?? 8 return diags .filter(d => !IGNORED_CODES.has(d.code) && Math.abs(d.line - cursorLine) <= window) .sort((a, b) => Math.abs(a.line - cursorLine) - Math.abs(b.line - cursorLine) || a.line - b.line) .slice(0, max) } /** One line per diagnostic: code, message (first line), and the trimmed source line it points at. */ export function formatDiagnostics(diags: Diagnostic[], visible: string): string { const lines = visible.split('\n') return diags.map(d => { const message = d.message.split('\n')[0].slice(0, 160) const src = (lines[d.line] ?? '').trim().slice(0, 100) return `TS${d.code} ${message} | ${src}` }).join('\n') } /** Diagnostics present in `after` but not in `before`, matched by code + message (positions shift with edits). */ export function newDiagnostics(before: Diagnostic[], after: Diagnostic[]): Diagnostic[] { const counts = new Map() for (const d of before) counts.set(`${d.code}:${d.message}`, (counts.get(`${d.code}:${d.message}`) ?? 0) + 1) const out: Diagnostic[] = [] for (const d of after) { const key = `${d.code}:${d.message}` const n = counts.get(key) ?? 0 if (n > 0) counts.set(key, n - 1) else if (!IGNORED_CODES.has(d.code)) out.push(d) } return out }