mlld
Version:
mlld: llm scripting language
1 lines • 19.9 kB
Source Map (JSON)
{"version":3,"sources":["../core/utils/ansi-processor.ts","../interpreter/streaming/template-interpolator.ts"],"names":["ANSI_CODES","reset","bold","dim","italic","underline","blink","inverse","hidden","strikethrough","black","red","green","yellow","blue","magenta","cyan","white","bright_black","bright_red","bright_green","bright_yellow","bright_blue","bright_magenta","bright_cyan","bright_white","bg_black","bg_red","bg_green","bg_yellow","bg_blue","bg_magenta","bg_cyan","bg_white","bg_bright_black","bg_bright_red","bg_bright_green","bg_bright_yellow","bg_bright_blue","bg_bright_magenta","bg_bright_cyan","bg_bright_white","gray","grey","bg_gray","bg_grey","brightblack","brightred","brightgreen","brightyellow","brightblue","brightmagenta","brightcyan","brightwhite","bgblack","bgred","bggreen","bgyellow","bgblue","bgmagenta","bgcyan","bgwhite","CODE_PATTERN","ANSI_ESCAPE_PATTERN","shouldProcessAnsi","target","options","process","env","NO_COLOR","MLLD_NO_COLOR","enabled","forceTTY","MLLD_FORCE_COLOR","stdout","isTTY","stderr","expandAnsiCodes","text","replace","match","code","lowerCode","toLowerCase","stripAnsiMarkers","stripAnsiEscapes","processAnsi","getFormattedText","plain","ansi","getAvailableCodes","Object","keys","interpolateTemplate","template","eventData","format","missingValue","result","replaceVariables","processEscapes","variablePattern","_match","path","value","extractPath","returnUndefined","undefined","formatValue","JSON","stringify","String","Array","isArray","applyTemplates","templates","json","DEFAULT_TEMPLATES","thinking","message","toolUse","toolResult","error","metadata"],"mappings":";;;;AAmBA,IAAMA,UAAqC,GAAA;;EAEzCC,KAAO,EAAA,SAAA;;EAGPC,IAAM,EAAA,SAAA;EACNC,GAAK,EAAA,SAAA;EACLC,MAAQ,EAAA,SAAA;EACRC,SAAW,EAAA,SAAA;EACXC,KAAO,EAAA,SAAA;EACPC,OAAS,EAAA,SAAA;EACTC,MAAQ,EAAA,SAAA;EACRC,aAAe,EAAA,SAAA;;EAGfC,KAAO,EAAA,UAAA;EACPC,GAAK,EAAA,UAAA;EACLC,KAAO,EAAA,UAAA;EACPC,MAAQ,EAAA,UAAA;EACRC,IAAM,EAAA,UAAA;EACNC,OAAS,EAAA,UAAA;EACTC,IAAM,EAAA,UAAA;EACNC,KAAO,EAAA,UAAA;;EAGPC,YAAc,EAAA,UAAA;EACdC,UAAY,EAAA,UAAA;EACZC,YAAc,EAAA,UAAA;EACdC,aAAe,EAAA,UAAA;EACfC,WAAa,EAAA,UAAA;EACbC,cAAgB,EAAA,UAAA;EAChBC,WAAa,EAAA,UAAA;EACbC,YAAc,EAAA,UAAA;;EAGdC,QAAU,EAAA,UAAA;EACVC,MAAQ,EAAA,UAAA;EACRC,QAAU,EAAA,UAAA;EACVC,SAAW,EAAA,UAAA;EACXC,OAAS,EAAA,UAAA;EACTC,UAAY,EAAA,UAAA;EACZC,OAAS,EAAA,UAAA;EACTC,QAAU,EAAA,UAAA;;EAGVC,eAAiB,EAAA,WAAA;EACjBC,aAAe,EAAA,WAAA;EACfC,eAAiB,EAAA,WAAA;EACjBC,gBAAkB,EAAA,WAAA;EAClBC,cAAgB,EAAA,WAAA;EAChBC,iBAAmB,EAAA,WAAA;EACnBC,cAAgB,EAAA,WAAA;EAChBC,eAAiB,EAAA,WAAA;;EAGjBC,IAAM,EAAA,UAAA;EACNC,IAAM,EAAA,UAAA;EACNC,OAAS,EAAA,WAAA;EACTC,OAAS,EAAA,WAAA;;EAGTC,WAAa,EAAA,UAAA;EACbC,SAAW,EAAA,UAAA;EACXC,WAAa,EAAA,UAAA;EACbC,YAAc,EAAA,UAAA;EACdC,UAAY,EAAA,UAAA;EACZC,aAAe,EAAA,UAAA;EACfC,UAAY,EAAA,UAAA;EACZC,WAAa,EAAA,UAAA;EACbC,OAAS,EAAA,UAAA;EACTC,KAAO,EAAA,UAAA;EACPC,OAAS,EAAA,UAAA;EACTC,QAAU,EAAA,UAAA;EACVC,MAAQ,EAAA,UAAA;EACRC,SAAW,EAAA,UAAA;EACXC,MAAQ,EAAA,UAAA;EACRC,OAAS,EAAA;AACX,CAAA;AAGA,IAAMC,YAAe,GAAA,eAAA;AAGrB,IAAMC,mBAAsB,GAAA,iBAAA;AAUrB,SAASC,iBAAAA,CACdC,QACAC,OAA+B,EAAA;AAG/B,EAAA,IAAIC,QAAQC,GAAIC,CAAAA,QAAAA,IAAYF,OAAQC,CAAAA,GAAAA,CAAIE,kBAAkB,MAAQ,EAAA;AAChE,IAAO,OAAA,KAAA;AACT;AAGA,EAAIJ,IAAAA,OAAAA,EAASK,YAAY,KAAO,EAAA;AAC9B,IAAO,OAAA,KAAA;AACT;AACA,EAAA,IAAIL,OAASM,EAAAA,QAAAA,IAAYL,OAAQC,CAAAA,GAAAA,CAAIK,qBAAqB,MAAQ,EAAA;AAChE,IAAO,OAAA,IAAA;AACT;AAGA,EAAA,IAAIR,WAAW,MAAQ,EAAA;AACrB,IAAO,OAAA,KAAA;AACT;AAGA,EAAA,IAAIA,WAAW,KAAO,EAAA;AACpB,IAAO,OAAA,KAAA;AACT;AAGA,EAAA,IAAIA,WAAW,QAAU,EAAA;AACvB,IAAOE,OAAAA,OAAAA,CAAQO,OAAOC,KAAU,KAAA,IAAA;AAClC;AACA,EAAA,IAAIV,WAAW,QAAU,EAAA;AACvB,IAAOE,OAAAA,OAAAA,CAAQS,OAAOD,KAAU,KAAA,IAAA;AAClC;AAEA,EAAO,OAAA,KAAA;AACT;AApCgBX,MAAAA,CAAAA,iBAAAA,EAAAA,mBAAAA,CAAAA;AAyCT,SAASa,gBAAgBC,IAAY,EAAA;AAC1C,EAAA,OAAOA,IAAKC,CAAAA,OAAAA,CAAQjB,YAAc,EAAA,CAACkB,OAAOC,IAAAA,KAAAA;AACxC,IAAMC,MAAAA,SAAAA,GAAYD,KAAKE,WAAW,EAAA;AAClC,IAAOnF,OAAAA,UAAAA,CAAWkF,SAAAA,CAAcF,IAAAA,KAAAA;GAClC,CAAA;AACF;AALgBH,MAAAA,CAAAA,eAAAA,EAAAA,iBAAAA,CAAAA;AAUT,SAASO,iBAAiBN,IAAY,EAAA;AAC3C,EAAOA,OAAAA,IAAAA,CAAKC,OAAQjB,CAAAA,YAAAA,EAAc,EAAA,CAAA;AACpC;AAFgBsB,MAAAA,CAAAA,gBAAAA,EAAAA,kBAAAA,CAAAA;AAOT,SAASC,iBAAiBP,IAAY,EAAA;AAC3C,EAAOA,OAAAA,IAAAA,CAAKC,OAAQhB,CAAAA,mBAAAA,EAAqB,EAAA,CAAA;AAC3C;AAFgBsB,MAAAA,CAAAA,gBAAAA,EAAAA,kBAAAA,CAAAA;AAwBT,SAASC,WAAAA,CACdR,IACAb,EAAAA,MAAAA,EACAC,OAA+B,EAAA;AAE/B,EAAIF,IAAAA,iBAAAA,CAAkBC,MAAQC,EAAAA,OAAAA,CAAU,EAAA;AACtC,IAAA,OAAOW,gBAAgBC,IAAAA,CAAAA;AACzB;AACA,EAAA,OAAOM,iBAAiBN,IAAAA,CAAAA;AAC1B;AATgBQ,MAAAA,CAAAA,WAAAA,EAAAA,aAAAA,CAAAA;AAcT,SAASC,iBAAiBT,IAAY,EAAA;AAC3C,EAAO,OAAA;AACLU,IAAAA,KAAAA,EAAOJ,iBAAiBN,IAAAA,CAAAA;AACxBW,IAAAA,IAAAA,EAAMZ,gBAAgBC,IAAAA;AACxB,GAAA;AACF;AALgBS,MAAAA,CAAAA,gBAAAA,EAAAA,kBAAAA,CAAAA;AAUT,SAASG,iBAAAA,GAAAA;AACd,EAAOC,OAAAA,MAAAA,CAAOC,KAAK5F,UAAAA,CAAAA;AACrB;AAFgB0F,MAAAA,CAAAA,iBAAAA,EAAAA,mBAAAA,CAAAA;;;ACvLT,SAASG,mBACdC,CAAAA,QAAAA,EACAC,SACAC,EAAAA,MAAAA,GAAyB,QACzB9B,OAA4B,EAAA;AAE5B,EAAA,MAAM,EAAE+B,YAAAA,GAAe,EAAE,EAAA,GAAK/B,WAAW,EAAC;AAG1C,EAAA,IAAIgC,MAASC,GAAAA,gBAAAA,CAAiBL,QAAUC,EAAAA,SAAAA,EAAWC,QAAQC,YAAAA,CAAAA;AAI3D,EAAA,IAAID,WAAW,MAAQ,EAAA;AACrBE,IAAAA,MAAAA,GAASrB,gBAAgBqB,MAAAA,CAAAA;GAChBF,MAAAA,IAAAA,MAAAA,KAAW,MAAUA,IAAAA,MAAAA,KAAW,MAAQ,EAAA;AACjDE,IAAAA,MAAAA,GAASd,iBAAiBc,MAAAA,CAAAA;AAC5B;AAGAA,EAAAA,MAAAA,GAASE,eAAeF,MAAAA,CAAAA;AAExB,EAAOA,OAAAA,MAAAA;AACT;AAvBgBL,MAAAA,CAAAA,mBAAAA,EAAAA,qBAAAA,CAAAA;AA4BhB,SAASM,gBACPL,CAAAA,QAAAA,EACAC,SACAC,EAAAA,MAAAA,EACAC,YAAoB,EAAA;AAIpB,EAAA,MAAMI,eAAkB,GAAA,4EAAA;AAExB,EAAA,OAAOP,QAASf,CAAAA,OAAAA,CAAQsB,eAAiB,EAAA,CAACC,QAAQC,IAAAA,KAAAA;AAChD,IAAMC,MAAAA,KAAAA,GAAQC,WAAYV,CAAAA,SAAAA,EAAWQ,IAAM,EAAA;MAAEG,eAAiB,EAAA;KAAK,CAAA;AAEnE,IAAA,IAAIF,UAAUG,MAAW,EAAA;AACvB,MAAOV,OAAAA,YAAAA;AACT;AAEA,IAAOW,OAAAA,WAAAA,CAAYJ,OAAOR,MAAAA,CAAAA;GAC5B,CAAA;AACF;AAnBSG,MAAAA,CAAAA,gBAAAA,EAAAA,kBAAAA,CAAAA;AAwBT,SAASS,WAAAA,CAAYJ,OAAgBR,MAAsB,EAAA;AACzD,EAAA,IAAIQ,UAAU,IAAM,EAAA;AAClB,IAAOR,OAAAA,MAAAA,KAAW,SAAS,MAAS,GAAA,EAAA;AACtC;AAEA,EAAA,IAAIQ,UAAUG,MAAW,EAAA;AACvB,IAAOX,OAAAA,MAAAA,KAAW,SAAS,MAAS,GAAA,EAAA;AACtC;AAEA,EAAI,IAAA,OAAOQ,UAAU,QAAU,EAAA;AAC7B,IAAA,IAAIR,WAAW,MAAQ,EAAA;AAErB,MAAOa,OAAAA,IAAAA,CAAKC,UAAUN,KAAAA,CAAAA;AACxB;AAEA,IAAOA,OAAAA,KAAAA;AACT;AAEA,EAAA,IAAI,OAAOA,KAAAA,KAAU,QAAY,IAAA,OAAOA,UAAU,SAAW,EAAA;AAE3D,IAAA,OAAOO,OAAOP,KAAAA,CAAAA;AAChB;AAEA,EAAA,IAAIQ,MAAMC,OAAQT,CAAAA,KAAAA,CAAU,IAAA,OAAOA,UAAU,QAAU,EAAA;AAErD,IAAOK,OAAAA,IAAAA,CAAKC,UAAUN,KAAAA,CAAAA;AACxB;AAEA,EAAA,OAAOO,OAAOP,KAAAA,CAAAA;AAChB;AA7BSI,MAAAA,CAAAA,WAAAA,EAAAA,aAAAA,CAAAA;AAoCT,SAASR,eAAetB,IAAY,EAAA;AAClC,EAAA,OAAOA,KACJC,OAAQ,CAAA,KAAA,EAAO,GAAA,CACfA,CAAAA,OAAAA,CAAQ,OAAO,GAAA,CAAA;AACpB;AAJSqB,MAAAA,CAAAA,cAAAA,EAAAA,gBAAAA,CAAAA;AA0BF,SAASc,cAAAA,CACdnB,SACAoB,EAAAA,SAAAA,EACAjD,OAA4B,EAAA;AAE5B,EAAA,MAAMgC,MAA0B,GAAA;IAC9BV,KAAO,EAAA,EAAA;IACPC,IAAM,EAAA;AACR,GAAA;AAGA,EAAA,IAAI0B,UAAUrC,IAAM,EAAA;AAClBoB,IAAAA,MAAAA,CAAOV,QAAQK,mBAAoBsB,CAAAA,SAAAA,CAAUrC,IAAMiB,EAAAA,SAAAA,EAAW,QAAQ7B,OAAAA,CAAAA;AACxE;AAGA,EAAA,IAAIiD,UAAU1B,IAAM,EAAA;AAClBS,IAAAA,MAAAA,CAAOT,OAAOI,mBAAoBsB,CAAAA,SAAAA,CAAU1B,IAAMM,EAAAA,SAAAA,EAAW,QAAQ7B,OAAAA,CAAAA;AACvE,GAAA,MAAA,IAAWiD,UAAUrC,IAAM,EAAA;AACzBoB,IAAAA,MAAAA,CAAOT,OAAOI,mBAAoBsB,CAAAA,SAAAA,CAAUrC,IAAMiB,EAAAA,SAAAA,EAAW,QAAQ7B,OAAAA,CAAAA;AACvE;AAGA,EAAA,IAAIiD,UAAUC,IAAM,EAAA;AAClBlB,IAAAA,MAAAA,CAAOkB,OAAOvB,mBAAoBsB,CAAAA,SAAAA,CAAUC,IAAMrB,EAAAA,SAAAA,EAAW,QAAQ7B,OAAAA,CAAAA;AACvE;AAEA,EAAOgC,OAAAA,MAAAA;AACT;AA5BgBgB,MAAAA,CAAAA,cAAAA,EAAAA,gBAAAA,CAAAA;AA8DT,IAAMG,iBAAoB,GAAA;EAC/BC,QAAU,EAAA;IACRxC,IAAM,EAAA,WAAA;IACNW,IAAM,EAAA;AACR,GAAA;EACA8B,OAAS,EAAA;IACPzC,IAAM,EAAA,YAAA;IACNW,IAAM,EAAA;AACR,GAAA;EACA+B,OAAS,EAAA;IACP1C,IAAM,EAAA,wBAAA;IACNW,IAAM,EAAA;AACR,GAAA;EACAgC,UAAY,EAAA;IACV3C,IAAM,EAAA,8BAAA;IACNW,IAAM,EAAA;AACR,GAAA;EACAiC,KAAO,EAAA;IACL5C,IAAM,EAAA,qBAAA;IACNW,IAAM,EAAA;AACR,GAAA;EACAkC,QAAU,EAAA;IACR7C,IAAM,EAAA,qDAAA;IACNW,IAAM,EAAA;AACR;AACF","file":"chunk-NS36QLDY.mjs","sourcesContent":["/**\n * ANSI Color Processing\n *\n * Handles `%color%` syntax for terminal colors in mlld output.\n * Colors are processed at the effect handler level, not during interpolation.\n *\n * Supported codes:\n * - Colors: %red%, %green%, %blue%, %yellow%, %cyan%, %magenta%, %white%, %black%\n * - Bright colors: %bright_red%, %bright_green%, etc.\n * - Backgrounds: %bg_red%, %bg_green%, etc.\n * - Modifiers: %bold%, %dim%, %italic%, %underline%, %blink%, %inverse%, %hidden%, %strikethrough%\n * - Reset: %reset%\n *\n * Environment variables:\n * - MLLD_NO_COLOR=true: Strip all ANSI codes\n * - MLLD_FORCE_COLOR=true: Force ANSI codes even when not TTY\n * - NO_COLOR: Standard no-color env var\n */\n\nconst ANSI_CODES: Record<string, string> = {\n // Reset\n reset: '\\x1b[0m',\n\n // Modifiers\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n italic: '\\x1b[3m',\n underline: '\\x1b[4m',\n blink: '\\x1b[5m',\n inverse: '\\x1b[7m',\n hidden: '\\x1b[8m',\n strikethrough: '\\x1b[9m',\n\n // Regular colors (foreground)\n black: '\\x1b[30m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n\n // Bright colors (foreground)\n bright_black: '\\x1b[90m',\n bright_red: '\\x1b[91m',\n bright_green: '\\x1b[92m',\n bright_yellow: '\\x1b[93m',\n bright_blue: '\\x1b[94m',\n bright_magenta: '\\x1b[95m',\n bright_cyan: '\\x1b[96m',\n bright_white: '\\x1b[97m',\n\n // Background colors\n bg_black: '\\x1b[40m',\n bg_red: '\\x1b[41m',\n bg_green: '\\x1b[42m',\n bg_yellow: '\\x1b[43m',\n bg_blue: '\\x1b[44m',\n bg_magenta: '\\x1b[45m',\n bg_cyan: '\\x1b[46m',\n bg_white: '\\x1b[47m',\n\n // Bright background colors\n bg_bright_black: '\\x1b[100m',\n bg_bright_red: '\\x1b[101m',\n bg_bright_green: '\\x1b[102m',\n bg_bright_yellow: '\\x1b[103m',\n bg_bright_blue: '\\x1b[104m',\n bg_bright_magenta: '\\x1b[105m',\n bg_bright_cyan: '\\x1b[106m',\n bg_bright_white: '\\x1b[107m',\n\n // Aliases for convenience\n gray: '\\x1b[90m',\n grey: '\\x1b[90m',\n bg_gray: '\\x1b[100m',\n bg_grey: '\\x1b[100m',\n\n // Aliases without underscores\n brightblack: '\\x1b[90m',\n brightred: '\\x1b[91m',\n brightgreen: '\\x1b[92m',\n brightyellow: '\\x1b[93m',\n brightblue: '\\x1b[94m',\n brightmagenta: '\\x1b[95m',\n brightcyan: '\\x1b[96m',\n brightwhite: '\\x1b[97m',\n bgblack: '\\x1b[40m',\n bgred: '\\x1b[41m',\n bggreen: '\\x1b[42m',\n bgyellow: '\\x1b[43m',\n bgblue: '\\x1b[44m',\n bgmagenta: '\\x1b[45m',\n bgcyan: '\\x1b[46m',\n bgwhite: '\\x1b[47m'\n};\n\n// Pattern to match %code% sequences\nconst CODE_PATTERN = /%([a-z_]+)%/gi;\n\n// Pattern to match actual ANSI escape sequences\nconst ANSI_ESCAPE_PATTERN = /\\x1b\\[[0-9;]*m/g;\n\nexport interface AnsiProcessingOptions {\n enabled?: boolean;\n forceTTY?: boolean;\n}\n\n/**\n * Check if ANSI processing should be enabled for a target\n */\nexport function shouldProcessAnsi(\n target: 'stdout' | 'stderr' | 'file' | 'doc',\n options?: AnsiProcessingOptions\n): boolean {\n // Check environment variables\n if (process.env.NO_COLOR || process.env.MLLD_NO_COLOR === 'true') {\n return false;\n }\n\n // Force option overrides\n if (options?.enabled === false) {\n return false;\n }\n if (options?.forceTTY || process.env.MLLD_FORCE_COLOR === 'true') {\n return true;\n }\n\n // File output never gets ANSI\n if (target === 'file') {\n return false;\n }\n\n // Doc buffer doesn't get ANSI by default (preserved for later processing)\n if (target === 'doc') {\n return false;\n }\n\n // Check TTY status\n if (target === 'stdout') {\n return process.stdout.isTTY === true;\n }\n if (target === 'stderr') {\n return process.stderr.isTTY === true;\n }\n\n return false;\n}\n\n/**\n * Expand %color% codes to ANSI escape sequences\n */\nexport function expandAnsiCodes(text: string): string {\n return text.replace(CODE_PATTERN, (match, code) => {\n const lowerCode = code.toLowerCase();\n return ANSI_CODES[lowerCode] ?? match;\n });\n}\n\n/**\n * Strip %color% codes from text (removes the markers without replacing)\n */\nexport function stripAnsiMarkers(text: string): string {\n return text.replace(CODE_PATTERN, '');\n}\n\n/**\n * Strip actual ANSI escape sequences from text\n */\nexport function stripAnsiEscapes(text: string): string {\n return text.replace(ANSI_ESCAPE_PATTERN, '');\n}\n\n/**\n * Check if text contains %color% markers\n */\nexport function hasAnsiMarkers(text: string): boolean {\n return CODE_PATTERN.test(text);\n}\n\n/**\n * Check if text contains actual ANSI escape sequences\n */\nexport function hasAnsiEscapes(text: string): boolean {\n return ANSI_ESCAPE_PATTERN.test(text);\n}\n\n/**\n * Process text for a specific output target\n *\n * - For TTY stdout/stderr: Expands %color% to ANSI codes\n * - For non-TTY or file: Strips %color% markers\n */\nexport function processAnsi(\n text: string,\n target: 'stdout' | 'stderr' | 'file' | 'doc',\n options?: AnsiProcessingOptions\n): string {\n if (shouldProcessAnsi(target, options)) {\n return expandAnsiCodes(text);\n }\n return stripAnsiMarkers(text);\n}\n\n/**\n * Get both plain and formatted versions of text\n */\nexport function getFormattedText(text: string): { plain: string; ansi: string } {\n return {\n plain: stripAnsiMarkers(text),\n ansi: expandAnsiCodes(text)\n };\n}\n\n/**\n * List all available ANSI codes\n */\nexport function getAvailableCodes(): string[] {\n return Object.keys(ANSI_CODES);\n}\n","/**\n * Template Interpolator for Streaming Adapters\n *\n * Interpolates templates with event data and format-specific processing.\n *\n * Supported syntax:\n * - Variable references: `@evt.field`, `@evt.nested.field`\n * - Escape sequences: `@@` → `@`, `%%` → `%`\n * - ANSI color codes: `%red%`, `%bold%` (processed based on format)\n *\n * Output formats:\n * - `text`: Plain text with variables replaced\n * - `ansi`: Variables replaced + ANSI codes expanded\n * - `json`: Variables JSON-stringified appropriately\n */\n\nimport { expandAnsiCodes, stripAnsiMarkers } from '@core/utils/ansi-processor';\nimport { extractPath } from './jsonpath';\n\nexport type TemplateFormat = 'text' | 'ansi' | 'json';\n\nexport interface InterpolateOptions {\n missingValue?: string;\n escapeHtml?: boolean;\n}\n\n/**\n * Interpolate a template with event data.\n *\n * @param template - Template string with `@evt.*` placeholders\n * @param eventData - Data extracted from the event\n * @param format - Output format ('text', 'ansi', or 'json')\n * @param options - Additional options\n * @returns Interpolated string\n */\nexport function interpolateTemplate(\n template: string,\n eventData: Record<string, unknown>,\n format: TemplateFormat = 'text',\n options?: InterpolateOptions\n): string {\n const { missingValue = '' } = options ?? {};\n\n // Step 1: Replace @evt.* variables\n let result = replaceVariables(template, eventData, format, missingValue);\n\n // Step 2: Process ANSI codes based on format\n // (Do this BEFORE escape processing so %bold%%red% works correctly)\n if (format === 'ansi') {\n result = expandAnsiCodes(result);\n } else if (format === 'text' || format === 'json') {\n result = stripAnsiMarkers(result);\n }\n\n // Step 3: Process escape sequences (after ANSI so %% escapes work)\n result = processEscapes(result);\n\n return result;\n}\n\n/**\n * Replace @evt.* variables in a template.\n */\nfunction replaceVariables(\n template: string,\n eventData: Record<string, unknown>,\n format: TemplateFormat,\n missingValue: string\n): string {\n // Match @evt.path or @evt[index].path patterns\n // Uses negative lookbehind to skip escaped @@\n const variablePattern = /(?<!@)@evt\\.([a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*|\\[\\d+\\])*)/g;\n\n return template.replace(variablePattern, (_match, path: string) => {\n const value = extractPath(eventData, path, { returnUndefined: true });\n\n if (value === undefined) {\n return missingValue;\n }\n\n return formatValue(value, format);\n });\n}\n\n/**\n * Format a value for output based on format type.\n */\nfunction formatValue(value: unknown, format: TemplateFormat): string {\n if (value === null) {\n return format === 'json' ? 'null' : '';\n }\n\n if (value === undefined) {\n return format === 'json' ? 'null' : '';\n }\n\n if (typeof value === 'string') {\n if (format === 'json') {\n // JSON format: quote strings\n return JSON.stringify(value);\n }\n // text/ansi: use raw string\n return value;\n }\n\n if (typeof value === 'number' || typeof value === 'boolean') {\n // Numbers and booleans: no quoting needed\n return String(value);\n }\n\n if (Array.isArray(value) || typeof value === 'object') {\n // Objects and arrays: always stringify\n return JSON.stringify(value);\n }\n\n return String(value);\n}\n\n/**\n * Process escape sequences in a template.\n * - @@ → @\n * - %% → %\n */\nfunction processEscapes(text: string): string {\n return text\n .replace(/@@/g, '@')\n .replace(/%%/g, '%');\n}\n\n/**\n * Apply templates to event data for all output formats.\n *\n * Returns an object with plain, ansi, and optionally json formats.\n */\nexport interface FormattedOutput {\n plain: string;\n ansi: string;\n json?: string;\n}\n\nexport interface EventTemplates {\n text?: string;\n ansi?: string;\n json?: string;\n}\n\n/**\n * Apply templates to produce formatted output in multiple formats.\n */\nexport function applyTemplates(\n eventData: Record<string, unknown>,\n templates: EventTemplates,\n options?: InterpolateOptions\n): FormattedOutput {\n const result: FormattedOutput = {\n plain: '',\n ansi: ''\n };\n\n // Use text template for plain output\n if (templates.text) {\n result.plain = interpolateTemplate(templates.text, eventData, 'text', options);\n }\n\n // Use ansi template for colored output, fallback to text\n if (templates.ansi) {\n result.ansi = interpolateTemplate(templates.ansi, eventData, 'ansi', options);\n } else if (templates.text) {\n result.ansi = interpolateTemplate(templates.text, eventData, 'text', options);\n }\n\n // Use json template if specified\n if (templates.json) {\n result.json = interpolateTemplate(templates.json, eventData, 'json', options);\n }\n\n return result;\n}\n\n/**\n * Check if a string contains template variables.\n */\nexport function hasTemplateVariables(template: string): boolean {\n return /(?<!@)@evt\\.[a-zA-Z_]/.test(template);\n}\n\n/**\n * Extract variable paths from a template.\n */\nexport function extractVariablePaths(template: string): string[] {\n const variablePattern = /(?<!@)@evt\\.([a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*|\\[\\d+\\])*)/g;\n const paths: string[] = [];\n let match;\n\n while ((match = variablePattern.exec(template)) !== null) {\n paths.push(match[1]);\n }\n\n return paths;\n}\n\n/**\n * Create a simple template that outputs a single field.\n */\nexport function createFieldTemplate(fieldName: string): string {\n return `@evt.${fieldName}`;\n}\n\n/**\n * Create default templates for common event types.\n */\nexport const DEFAULT_TEMPLATES = {\n thinking: {\n text: '@evt.text',\n ansi: '%dim%@evt.text%reset%'\n },\n message: {\n text: '@evt.chunk',\n ansi: '@evt.chunk'\n },\n toolUse: {\n text: '[@evt.name] @evt.input',\n ansi: '%cyan%[@evt.name]%reset% @evt.input'\n },\n toolResult: {\n text: '[@evt.toolUseId] @evt.result',\n ansi: '%green%[@evt.toolUseId]%reset% @evt.result'\n },\n error: {\n text: 'Error: @evt.message',\n ansi: '%red%Error:%reset% @evt.message'\n },\n metadata: {\n text: 'Tokens: @evt.inputTokens in / @evt.outputTokens out',\n ansi: '%dim%Tokens: @evt.inputTokens in / @evt.outputTokens out%reset%'\n }\n};\n"]}