// highlight.js's type defs carry `/// `. SSETransport, // mcp/client, ssh, dumpPrompts use DOM types (TextDecodeOptions, RequestInfo) // that only typecheck because the hljs import below pulls lib.dom in. // tsconfig has lib: ["ESNext"] only — this ref preserves the status quo. /// import { extname } from 'path' // Static import — dynamic import('highlight.js') fails in Bun --compile mode // because module resolution points to the internal bunfs binary path. import hljs from 'highlight.js' export type CliHighlight = { highlight: typeof import('cli-highlight').highlight supportsLanguage: typeof import('cli-highlight').supportsLanguage } // One promise shared by Fallback.tsx, markdown.ts, events.ts, getLanguageName. let cliHighlightPromise: Promise | undefined let loadedGetLanguage: ((name: string) => { name: string } | undefined) | undefined async function loadCliHighlight(): Promise { try { const cliHighlight = await import('cli-highlight') // highlight.js CJS interop: `export =` wraps in .default under ESM const hljsMod = hljs as { getLanguage?: typeof loadedGetLanguage; default?: typeof hljs } loadedGetLanguage = hljsMod.getLanguage ?? hljsMod.default?.getLanguage return { highlight: cliHighlight.highlight, supportsLanguage: cliHighlight.supportsLanguage, } } catch { return null } } export function getCliHighlightPromise(): Promise { cliHighlightPromise ??= loadCliHighlight() return cliHighlightPromise } /** * eg. "foo/bar.ts" → "TypeScript". Awaits the shared cli-highlight load, * then reads highlight.js's language registry. All callers are telemetry * (OTel counter attributes, permission-dialog unary events) — none block * on this, they fire-and-forget or the consumer already handles Promise. */ export async function getLanguageName(file_path: string): Promise { await getCliHighlightPromise() const ext = extname(file_path).slice(1) if (!ext) return 'unknown' return loadedGetLanguage?.(ext)?.name ?? 'unknown' }