export const EVAL_PRAGMA_PREFIXES = ["// @eval:", "# @eval:"] as const; const SUPPORTED_FIELDS = ["timeout", "on_timeout", "title"] as const; export interface ParsedEvalSource { readonly code: string; readonly on_timeout?: "detach" | "error"; readonly timeout?: number; readonly title?: string; } /** * Parse a first-line `@eval` pragma out of cell code. The pragma mirrors the * `// @exec:` pragma from Codex: a JSON object on the first line that carries * cell options. Explicit tool parameters win over pragma fields (see * `parseEvalRequest`), and the pragma line never runs as code. * * Parser contract: * - Only a pragma on the FIRST line is recognized; a pragma-looking line * later in the cell is ordinary code. * - The pragma value must be a JSON object with only the supported fields. * - The pragma must be followed by code on subsequent lines. */ export function parseEvalSource(input: string): ParsedEvalSource { const newlineIndex = input.indexOf("\n"); const firstLine = newlineIndex === -1 ? input : input.slice(0, newlineIndex); const rest = newlineIndex === -1 ? "" : input.slice(newlineIndex + 1); const trimmed = firstLine.trimStart(); const prefix = EVAL_PRAGMA_PREFIXES.find((candidate) => trimmed.startsWith(candidate) ); if (prefix === undefined) { return { code: input }; } if (rest.length === 0) { throw new TypeError( "eval pragma must be followed by cell code on subsequent lines" ); } const valueText = trimmed.slice(prefix.length); const parsed = parsePragmaValue(valueText); return { code: rest, ...parsed }; } function parsePragmaValue(valueText: string): { timeout?: number; on_timeout?: "detach" | "error"; title?: string; } { let value: unknown; try { value = JSON.parse(valueText); } catch (error) { const detail = error instanceof Error ? error.message : String(error); throw new TypeError( `eval pragma must be a JSON object with supported fields "timeout", "on_timeout", and "title": ${detail}`, { cause: error } ); } if (typeof value !== "object" || value === null || Array.isArray(value)) { throw new TypeError( `eval pragma must be a JSON object with supported fields "timeout", "on_timeout", and "title"` ); } const record = value as Record; const parsed: { timeout?: number; on_timeout?: "detach" | "error"; title?: string; } = {}; for (const [key, fieldValue] of Object.entries(record)) { if (!SUPPORTED_FIELDS.includes(key as (typeof SUPPORTED_FIELDS)[number])) { throw new TypeError( `eval pragma only supports "timeout", "on_timeout", and "title"; got "${key}"` ); } if (key === "timeout") { if (typeof fieldValue !== "number" || fieldValue < 1) { throw new TypeError( `eval pragma field "timeout" must be a number of at least 1 second` ); } parsed.timeout = fieldValue; } else if (key === "on_timeout") { if (fieldValue !== "detach" && fieldValue !== "error") { throw new TypeError( `eval pragma field "on_timeout" must be "detach" or "error"` ); } parsed.on_timeout = fieldValue; } else if (key === "title") { if (typeof fieldValue !== "string") { throw new TypeError(`eval pragma field "title" must be a string`); } parsed.title = fieldValue; } } return parsed; }