@mariozechner/pi-coding-agent 0.39.0 → 0.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/modes/interactive/components/assistant-message.d.ts +2 -0
  3. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  4. package/dist/modes/interactive/components/assistant-message.js +8 -0
  5. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  6. package/dist/modes/interactive/components/bash-execution.d.ts +1 -0
  7. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  8. package/dist/modes/interactive/components/bash-execution.js +4 -0
  9. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  10. package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -0
  11. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  12. package/dist/modes/interactive/components/branch-summary-message.js +4 -0
  13. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  14. package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -0
  15. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  16. package/dist/modes/interactive/components/compaction-summary-message.js +4 -0
  17. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  18. package/dist/modes/interactive/components/custom-message.d.ts +1 -0
  19. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  20. package/dist/modes/interactive/components/custom-message.js +4 -0
  21. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  22. package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  23. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  24. package/dist/modes/interactive/components/tool-execution.js +4 -0
  25. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  26. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  27. package/dist/modes/interactive/theme/theme.js +6 -0
  28. package/dist/modes/interactive/theme/theme.js.map +1 -1
  29. package/docs/tui.md +102 -0
  30. package/examples/extensions/mac-system-theme.ts +25 -5
  31. package/examples/extensions/with-deps/package-lock.json +2 -2
  32. package/examples/extensions/with-deps/package.json +1 -1
  33. package/package.json +4 -4
@@ -168,6 +168,10 @@ export class ToolExecutionComponent extends Container {
168
168
  this.showImages = show;
169
169
  this.updateDisplay();
170
170
  }
171
+ invalidate() {
172
+ super.invalidate();
173
+ this.updateDisplay();
174
+ }
171
175
  updateDisplay() {
172
176
  // Set background based on state
173
177
  const bgFn = this.isPartial
@@ -1 +1 @@
1
- {"version":3,"file":"tool-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport {\n\tBox,\n\tContainer,\n\tgetCapabilities,\n\tgetImageDimensions,\n\tImage,\n\timageFallback,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@mariozechner/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\nimport type { ToolDefinition } from \"../../../core/extensions/types.js\";\nimport { computeEditDiff, type EditDiffError, type EditDiffResult } from \"../../../core/tools/edit-diff.js\";\nimport { allTools } from \"../../../core/tools/index.js\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from \"../../../core/tools/truncate.js\";\nimport { convertToPng } from \"../../../utils/image-convert.js\";\nimport { sanitizeBinaryOutput } from \"../../../utils/shell.js\";\nimport { getLanguageFromPath, highlightCode, theme } from \"../theme/theme.js\";\nimport { renderDiff } from \"./diff.js\";\nimport { truncateToVisualLines } from \"./visual-truncate.js\";\n\n// Preview line limit for bash when not expanded\nconst BASH_PREVIEW_LINES = 5;\n\n/**\n * Convert absolute path to tilde notation if it's in home directory\n */\nfunction shortenPath(path: string): string {\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\n/**\n * Replace tabs with spaces for consistent rendering\n */\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean; // default: true (only used if terminal supports images)\n}\n\n/**\n * Component that renders a tool call with its result (updateable)\n */\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box; // Used for custom tools and bash visual truncation\n\tprivate contentText: Text; // For built-in tools (with its own padding/bg)\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolDefinition;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\t// Cached edit diff preview (computed when args arrive, before tool executes)\n\tprivate editDiffPreview?: EditDiffResult | EditDiffError;\n\tprivate editDiffArgsKey?: string; // Track which args the preview is for\n\t// Cached converted images for Kitty protocol (which requires PNG), keyed by index\n\tprivate convertedImages: Map<number, { data: string; mimeType: string }> = new Map();\n\n\tconstructor(\n\t\ttoolName: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolDefinition | undefined,\n\t\tui: TUI,\n\t\tcwd: string = process.cwd(),\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.args = args;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Always create both - contentBox for custom tools/bash, contentText for other built-ins\n\t\tthis.contentBox = new Box(1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\n\t\t// Use contentBox for bash (visual truncation) or custom tools with custom renderers\n\t\t// Use contentText for built-in tools (including overrides without custom renderers)\n\t\tif (toolName === \"bash\" || (toolDefinition && !this.shouldUseBuiltInRenderer())) {\n\t\t\tthis.addChild(this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentText);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\t/**\n\t * Check if we should use built-in rendering for this tool.\n\t * Returns true if the tool name is a built-in AND either there's no toolDefinition\n\t * or the toolDefinition doesn't provide custom renderers.\n\t */\n\tprivate shouldUseBuiltInRenderer(): boolean {\n\t\tconst isBuiltInName = this.toolName in allTools;\n\t\tconst hasCustomRenderers = this.toolDefinition?.renderCall || this.toolDefinition?.renderResult;\n\t\treturn isBuiltInName && !hasCustomRenderers;\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\t/**\n\t * Signal that args are complete (tool is about to execute).\n\t * This triggers diff computation for edit tool.\n\t */\n\tsetArgsComplete(): void {\n\t\tthis.maybeComputeEditDiff();\n\t}\n\n\t/**\n\t * Compute edit diff preview when we have complete args.\n\t * This runs async and updates display when done.\n\t */\n\tprivate maybeComputeEditDiff(): void {\n\t\tif (this.toolName !== \"edit\") return;\n\n\t\tconst path = this.args?.path;\n\t\tconst oldText = this.args?.oldText;\n\t\tconst newText = this.args?.newText;\n\n\t\t// Need all three params to compute diff\n\t\tif (!path || oldText === undefined || newText === undefined) return;\n\n\t\t// Create a key to track which args this computation is for\n\t\tconst argsKey = JSON.stringify({ path, oldText, newText });\n\n\t\t// Skip if we already computed for these exact args\n\t\tif (this.editDiffArgsKey === argsKey) return;\n\n\t\tthis.editDiffArgsKey = argsKey;\n\n\t\t// Compute diff async\n\t\tcomputeEditDiff(path, oldText, newText, this.cwd).then((result) => {\n\t\t\t// Only update if args haven't changed since we started\n\t\t\tif (this.editDiffArgsKey === argsKey) {\n\t\t\t\tthis.editDiffPreview = result;\n\t\t\t\tthis.updateDisplay();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t}\n\t\t});\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t\t// Convert non-PNG images to PNG for Kitty protocol (async)\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\t/**\n\t * Convert non-PNG images to PNG for Kitty graphics protocol.\n\t * Kitty requires PNG format (f=100), so JPEG/GIF/WebP won't display.\n\t */\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\t// Only needed for Kitty protocol\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\t// Skip if already PNG or already converted\n\t\t\tif (img.mimeType === \"image/png\") continue;\n\t\t\tif (this.convertedImages.has(i)) continue;\n\n\t\t\t// Convert async\n\t\t\tconst index = i;\n\t\t\tconvertToPng(img.data, img.mimeType).then((converted) => {\n\t\t\t\tif (converted) {\n\t\t\t\t\tthis.convertedImages.set(index, converted);\n\t\t\t\t\tthis.updateDisplay();\n\t\t\t\t\tthis.ui.requestRender();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\t// Set background based on state\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\t// Use built-in rendering for built-in tools (or overrides without custom renderers)\n\t\tif (this.shouldUseBuiltInRenderer()) {\n\t\t\tif (this.toolName === \"bash\") {\n\t\t\t\t// Bash uses Box with visual line truncation\n\t\t\t\tthis.contentBox.setBgFn(bgFn);\n\t\t\t\tthis.contentBox.clear();\n\t\t\t\tthis.renderBashContent();\n\t\t\t} else {\n\t\t\t\t// Other built-in tools: use Text directly with caching\n\t\t\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\t}\n\t\t} else if (this.toolDefinition) {\n\t\t\t// Custom tools use Box for flexible component rendering\n\t\t\tthis.contentBox.setBgFn(bgFn);\n\t\t\tthis.contentBox.clear();\n\n\t\t\t// Render call component\n\t\t\tif (this.toolDefinition.renderCall) {\n\t\t\t\ttry {\n\t\t\t\t\tconst callComponent = this.toolDefinition.renderCall(this.args, theme);\n\t\t\t\t\tif (callComponent) {\n\t\t\t\t\t\tthis.contentBox.addChild(callComponent);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall back to default on error\n\t\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No custom renderCall, show tool name\n\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0));\n\t\t\t}\n\n\t\t\t// Render result component if we have a result\n\t\t\tif (this.result && this.toolDefinition.renderResult) {\n\t\t\t\ttry {\n\t\t\t\t\tconst resultComponent = this.toolDefinition.renderResult(\n\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\ttheme,\n\t\t\t\t\t);\n\t\t\t\t\tif (resultComponent) {\n\t\t\t\t\t\tthis.contentBox.addChild(resultComponent);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall back to showing raw output on error\n\t\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\t\tif (output) {\n\t\t\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolOutput\", output), 0, 0));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (this.result) {\n\t\t\t\t// Has result but no custom renderResult\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tif (output) {\n\t\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolOutput\", output), 0, 0));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Handle images (same for both custom and built-in)\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\t\t\tconst caps = getCapabilities();\n\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\t// Use converted PNG for Kitty protocol if available\n\t\t\t\t\tconst converted = this.convertedImages.get(i);\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\n\t\t\t\t\t// For Kitty, skip non-PNG images that haven't been converted yet\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: 60 },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Render bash content using visual line truncation (like bash-execution.ts)\n\t */\n\tprivate renderBashContent(): void {\n\t\tconst command = this.args?.command || \"\";\n\n\t\t// Header\n\t\tthis.contentBox.addChild(\n\t\t\tnew Text(theme.fg(\"toolTitle\", theme.bold(`$ ${command || theme.fg(\"toolOutput\", \"...\")}`)), 0, 0),\n\t\t);\n\n\t\tif (this.result) {\n\t\t\tconst output = this.getTextOutput().trim();\n\n\t\t\tif (output) {\n\t\t\t\t// Style each line for the output\n\t\t\t\tconst styledOutput = output\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t\t\t.join(\"\\n\");\n\n\t\t\t\tif (this.expanded) {\n\t\t\t\t\t// Show all lines when expanded\n\t\t\t\t\tthis.contentBox.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t\t\t} else {\n\t\t\t\t\t// Use visual line truncation when collapsed with width-aware caching\n\t\t\t\t\tconst textContent = `\\n${styledOutput}`;\n\t\t\t\t\tlet cachedWidth: number | undefined;\n\t\t\t\t\tlet cachedLines: string[] | undefined;\n\t\t\t\t\tlet cachedSkipped: number | undefined;\n\n\t\t\t\t\tthis.contentBox.addChild({\n\t\t\t\t\t\trender: (width: number) => {\n\t\t\t\t\t\t\tif (cachedLines === undefined || cachedWidth !== width) {\n\t\t\t\t\t\t\t\tconst result = truncateToVisualLines(textContent, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\t\t\tcachedLines = result.visualLines;\n\t\t\t\t\t\t\t\tcachedSkipped = result.skippedCount;\n\t\t\t\t\t\t\t\tcachedWidth = width;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn cachedSkipped && cachedSkipped > 0\n\t\t\t\t\t\t\t\t? [\"\", theme.fg(\"toolOutput\", `... (${cachedSkipped} earlier lines)`), ...cachedLines]\n\t\t\t\t\t\t\t\t: cachedLines;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinvalidate: () => {\n\t\t\t\t\t\t\tcachedWidth = undefined;\n\t\t\t\t\t\t\tcachedLines = undefined;\n\t\t\t\t\t\t\tcachedSkipped = undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Truncation warnings\n\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\tconst fullOutputPath = this.result.details?.fullOutputPath;\n\t\t\tif (truncation?.truncated || fullOutputPath) {\n\t\t\t\tconst warnings: string[] = [];\n\t\t\t\tif (fullOutputPath) {\n\t\t\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t\t\t}\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.contentBox.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\tif (!this.result) return \"\";\n\n\t\tconst textBlocks = this.result.content?.filter((c: any) => c.type === \"text\") || [];\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tlet output = textBlocks\n\t\t\t.map((c: any) => {\n\t\t\t\t// Use sanitizeBinaryOutput to handle binary data that crashes string-width\n\t\t\t\treturn sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\");\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\n\t\tconst caps = getCapabilities();\n\t\tif (imageBlocks.length > 0 && (!caps.images || !this.showImages)) {\n\t\t\tconst imageIndicators = imageBlocks\n\t\t\t\t.map((img: any) => {\n\t\t\t\t\tconst dims = img.data ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\t\treturn imageFallback(img.mimeType, dims);\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = \"\";\n\n\t\tif (this.toolName === \"read\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst offset = this.args?.offset;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n\t\t\t}\n\n\t\t\ttext = `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}`;\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tconst rawPath = this.args?.file_path || this.args?.path || \"\";\n\t\t\t\tconst lang = getLanguageFromPath(rawPath);\n\t\t\t\tconst lines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext +=\n\t\t\t\t\t\"\\n\\n\" +\n\t\t\t\t\tdisplayLines\n\t\t\t\t\t\t.map((line: string) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line))))\n\t\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"write\") {\n\t\t\tconst rawPath = this.args?.file_path || this.args?.path || \"\";\n\t\t\tconst path = shortenPath(rawPath);\n\t\t\tconst fileContent = this.args?.content || \"\";\n\t\t\tconst lang = getLanguageFromPath(rawPath);\n\t\t\tconst lines = fileContent\n\t\t\t\t? lang\n\t\t\t\t\t? highlightCode(replaceTabs(fileContent), lang)\n\t\t\t\t\t: fileContent.split(\"\\n\")\n\t\t\t\t: [];\n\t\t\tconst totalLines = lines.length;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"write\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\n\t\t\tif (fileContent) {\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext +=\n\t\t\t\t\t\"\\n\\n\" +\n\t\t\t\t\tdisplayLines\n\t\t\t\t\t\t.map((line: string) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line))))\n\t\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines, ${totalLines} total)`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"edit\") {\n\t\t\tconst rawPath = this.args?.file_path || this.args?.path || \"\";\n\t\t\tconst path = shortenPath(rawPath);\n\n\t\t\t// Build path display, appending :line if we have diff info\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tconst firstChangedLine =\n\t\t\t\t(this.editDiffPreview && \"firstChangedLine\" in this.editDiffPreview\n\t\t\t\t\t? this.editDiffPreview.firstChangedLine\n\t\t\t\t\t: undefined) ||\n\t\t\t\t(this.result && !this.result.isError ? this.result.details?.firstChangedLine : undefined);\n\t\t\tif (firstChangedLine) {\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${firstChangedLine}`);\n\t\t\t}\n\n\t\t\ttext = `${theme.fg(\"toolTitle\", theme.bold(\"edit\"))} ${pathDisplay}`;\n\n\t\t\tif (this.result?.isError) {\n\t\t\t\t// Show error from result\n\t\t\t\tconst errorText = this.getTextOutput();\n\t\t\t\tif (errorText) {\n\t\t\t\t\ttext += `\\n\\n${theme.fg(\"error\", errorText)}`;\n\t\t\t\t}\n\t\t\t} else if (this.result?.details?.diff) {\n\t\t\t\t// Tool executed successfully - use the diff from result\n\t\t\t\t// This takes priority over editDiffPreview which may have a stale error\n\t\t\t\t// due to race condition (async preview computed after file was modified)\n\t\t\t\ttext += `\\n\\n${renderDiff(this.result.details.diff, { filePath: rawPath })}`;\n\t\t\t} else if (this.editDiffPreview) {\n\t\t\t\t// Use cached diff preview (before tool executes)\n\t\t\t\tif (\"error\" in this.editDiffPreview) {\n\t\t\t\t\ttext += `\\n\\n${theme.fg(\"error\", this.editDiffPreview.error)}`;\n\t\t\t\t} else if (this.editDiffPreview.diff) {\n\t\t\t\t\ttext += `\\n\\n${renderDiff(this.editDiffPreview.diff, { filePath: rawPath })}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"ls\") {\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${theme.fg(\"accent\", path)}`;\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += `\\n\\n${displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst entryLimit = this.result.details?.entryLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (entryLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (entryLimit) {\n\t\t\t\t\t\twarnings.push(`${entryLimit} entries limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"find\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", pattern) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += `\\n\\n${displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst resultLimit = this.result.details?.resultLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (resultLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (resultLimit) {\n\t\t\t\t\t\twarnings.push(`${resultLimit} results limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"grep\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst glob = this.args?.glob;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", `/${pattern}/`) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (glob) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (${glob})`);\n\t\t\t}\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 15;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += `\\n\\n${displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst matchLimit = this.result.details?.matchLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst linesTruncated = this.result.details?.linesTruncated;\n\t\t\t\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (matchLimit) {\n\t\t\t\t\t\twarnings.push(`${matchLimit} matches limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\twarnings.push(\"some lines truncated\");\n\t\t\t\t\t}\n\t\t\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tool (shouldn't reach here for custom tools)\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\ttext += `\\n\\n${content}`;\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += `\\n${output}`;\n\t\t\t}\n\t\t}\n\n\t\treturn text;\n\t}\n}\n"]}
1
+ {"version":3,"file":"tool-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/tool-execution.ts"],"names":[],"mappings":"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","sourcesContent":["import * as os from \"node:os\";\nimport {\n\tBox,\n\tContainer,\n\tgetCapabilities,\n\tgetImageDimensions,\n\tImage,\n\timageFallback,\n\tSpacer,\n\tText,\n\ttype TUI,\n} from \"@mariozechner/pi-tui\";\nimport stripAnsi from \"strip-ansi\";\nimport type { ToolDefinition } from \"../../../core/extensions/types.js\";\nimport { computeEditDiff, type EditDiffError, type EditDiffResult } from \"../../../core/tools/edit-diff.js\";\nimport { allTools } from \"../../../core/tools/index.js\";\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from \"../../../core/tools/truncate.js\";\nimport { convertToPng } from \"../../../utils/image-convert.js\";\nimport { sanitizeBinaryOutput } from \"../../../utils/shell.js\";\nimport { getLanguageFromPath, highlightCode, theme } from \"../theme/theme.js\";\nimport { renderDiff } from \"./diff.js\";\nimport { truncateToVisualLines } from \"./visual-truncate.js\";\n\n// Preview line limit for bash when not expanded\nconst BASH_PREVIEW_LINES = 5;\n\n/**\n * Convert absolute path to tilde notation if it's in home directory\n */\nfunction shortenPath(path: string): string {\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\treturn `~${path.slice(home.length)}`;\n\t}\n\treturn path;\n}\n\n/**\n * Replace tabs with spaces for consistent rendering\n */\nfunction replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport interface ToolExecutionOptions {\n\tshowImages?: boolean; // default: true (only used if terminal supports images)\n}\n\n/**\n * Component that renders a tool call with its result (updateable)\n */\nexport class ToolExecutionComponent extends Container {\n\tprivate contentBox: Box; // Used for custom tools and bash visual truncation\n\tprivate contentText: Text; // For built-in tools (with its own padding/bg)\n\tprivate imageComponents: Image[] = [];\n\tprivate imageSpacers: Spacer[] = [];\n\tprivate toolName: string;\n\tprivate args: any;\n\tprivate expanded = false;\n\tprivate showImages: boolean;\n\tprivate isPartial = true;\n\tprivate toolDefinition?: ToolDefinition;\n\tprivate ui: TUI;\n\tprivate cwd: string;\n\tprivate result?: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tisError: boolean;\n\t\tdetails?: any;\n\t};\n\t// Cached edit diff preview (computed when args arrive, before tool executes)\n\tprivate editDiffPreview?: EditDiffResult | EditDiffError;\n\tprivate editDiffArgsKey?: string; // Track which args the preview is for\n\t// Cached converted images for Kitty protocol (which requires PNG), keyed by index\n\tprivate convertedImages: Map<number, { data: string; mimeType: string }> = new Map();\n\n\tconstructor(\n\t\ttoolName: string,\n\t\targs: any,\n\t\toptions: ToolExecutionOptions = {},\n\t\ttoolDefinition: ToolDefinition | undefined,\n\t\tui: TUI,\n\t\tcwd: string = process.cwd(),\n\t) {\n\t\tsuper();\n\t\tthis.toolName = toolName;\n\t\tthis.args = args;\n\t\tthis.showImages = options.showImages ?? true;\n\t\tthis.toolDefinition = toolDefinition;\n\t\tthis.ui = ui;\n\t\tthis.cwd = cwd;\n\n\t\tthis.addChild(new Spacer(1));\n\n\t\t// Always create both - contentBox for custom tools/bash, contentText for other built-ins\n\t\tthis.contentBox = new Box(1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\t\tthis.contentText = new Text(\"\", 1, 1, (text: string) => theme.bg(\"toolPendingBg\", text));\n\n\t\t// Use contentBox for bash (visual truncation) or custom tools with custom renderers\n\t\t// Use contentText for built-in tools (including overrides without custom renderers)\n\t\tif (toolName === \"bash\" || (toolDefinition && !this.shouldUseBuiltInRenderer())) {\n\t\t\tthis.addChild(this.contentBox);\n\t\t} else {\n\t\t\tthis.addChild(this.contentText);\n\t\t}\n\n\t\tthis.updateDisplay();\n\t}\n\n\t/**\n\t * Check if we should use built-in rendering for this tool.\n\t * Returns true if the tool name is a built-in AND either there's no toolDefinition\n\t * or the toolDefinition doesn't provide custom renderers.\n\t */\n\tprivate shouldUseBuiltInRenderer(): boolean {\n\t\tconst isBuiltInName = this.toolName in allTools;\n\t\tconst hasCustomRenderers = this.toolDefinition?.renderCall || this.toolDefinition?.renderResult;\n\t\treturn isBuiltInName && !hasCustomRenderers;\n\t}\n\n\tupdateArgs(args: any): void {\n\t\tthis.args = args;\n\t\tthis.updateDisplay();\n\t}\n\n\t/**\n\t * Signal that args are complete (tool is about to execute).\n\t * This triggers diff computation for edit tool.\n\t */\n\tsetArgsComplete(): void {\n\t\tthis.maybeComputeEditDiff();\n\t}\n\n\t/**\n\t * Compute edit diff preview when we have complete args.\n\t * This runs async and updates display when done.\n\t */\n\tprivate maybeComputeEditDiff(): void {\n\t\tif (this.toolName !== \"edit\") return;\n\n\t\tconst path = this.args?.path;\n\t\tconst oldText = this.args?.oldText;\n\t\tconst newText = this.args?.newText;\n\n\t\t// Need all three params to compute diff\n\t\tif (!path || oldText === undefined || newText === undefined) return;\n\n\t\t// Create a key to track which args this computation is for\n\t\tconst argsKey = JSON.stringify({ path, oldText, newText });\n\n\t\t// Skip if we already computed for these exact args\n\t\tif (this.editDiffArgsKey === argsKey) return;\n\n\t\tthis.editDiffArgsKey = argsKey;\n\n\t\t// Compute diff async\n\t\tcomputeEditDiff(path, oldText, newText, this.cwd).then((result) => {\n\t\t\t// Only update if args haven't changed since we started\n\t\t\tif (this.editDiffArgsKey === argsKey) {\n\t\t\t\tthis.editDiffPreview = result;\n\t\t\t\tthis.updateDisplay();\n\t\t\t\tthis.ui.requestRender();\n\t\t\t}\n\t\t});\n\t}\n\n\tupdateResult(\n\t\tresult: {\n\t\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\t\tdetails?: any;\n\t\t\tisError: boolean;\n\t\t},\n\t\tisPartial = false,\n\t): void {\n\t\tthis.result = result;\n\t\tthis.isPartial = isPartial;\n\t\tthis.updateDisplay();\n\t\t// Convert non-PNG images to PNG for Kitty protocol (async)\n\t\tthis.maybeConvertImagesForKitty();\n\t}\n\n\t/**\n\t * Convert non-PNG images to PNG for Kitty graphics protocol.\n\t * Kitty requires PNG format (f=100), so JPEG/GIF/WebP won't display.\n\t */\n\tprivate maybeConvertImagesForKitty(): void {\n\t\tconst caps = getCapabilities();\n\t\t// Only needed for Kitty protocol\n\t\tif (caps.images !== \"kitty\") return;\n\t\tif (!this.result) return;\n\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\tconst img = imageBlocks[i];\n\t\t\tif (!img.data || !img.mimeType) continue;\n\t\t\t// Skip if already PNG or already converted\n\t\t\tif (img.mimeType === \"image/png\") continue;\n\t\t\tif (this.convertedImages.has(i)) continue;\n\n\t\t\t// Convert async\n\t\t\tconst index = i;\n\t\t\tconvertToPng(img.data, img.mimeType).then((converted) => {\n\t\t\t\tif (converted) {\n\t\t\t\t\tthis.convertedImages.set(index, converted);\n\t\t\t\t\tthis.updateDisplay();\n\t\t\t\t\tthis.ui.requestRender();\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetShowImages(show: boolean): void {\n\t\tthis.showImages = show;\n\t\tthis.updateDisplay();\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\t// Set background based on state\n\t\tconst bgFn = this.isPartial\n\t\t\t? (text: string) => theme.bg(\"toolPendingBg\", text)\n\t\t\t: this.result?.isError\n\t\t\t\t? (text: string) => theme.bg(\"toolErrorBg\", text)\n\t\t\t\t: (text: string) => theme.bg(\"toolSuccessBg\", text);\n\n\t\t// Use built-in rendering for built-in tools (or overrides without custom renderers)\n\t\tif (this.shouldUseBuiltInRenderer()) {\n\t\t\tif (this.toolName === \"bash\") {\n\t\t\t\t// Bash uses Box with visual line truncation\n\t\t\t\tthis.contentBox.setBgFn(bgFn);\n\t\t\t\tthis.contentBox.clear();\n\t\t\t\tthis.renderBashContent();\n\t\t\t} else {\n\t\t\t\t// Other built-in tools: use Text directly with caching\n\t\t\t\tthis.contentText.setCustomBgFn(bgFn);\n\t\t\t\tthis.contentText.setText(this.formatToolExecution());\n\t\t\t}\n\t\t} else if (this.toolDefinition) {\n\t\t\t// Custom tools use Box for flexible component rendering\n\t\t\tthis.contentBox.setBgFn(bgFn);\n\t\t\tthis.contentBox.clear();\n\n\t\t\t// Render call component\n\t\t\tif (this.toolDefinition.renderCall) {\n\t\t\t\ttry {\n\t\t\t\t\tconst callComponent = this.toolDefinition.renderCall(this.args, theme);\n\t\t\t\t\tif (callComponent) {\n\t\t\t\t\t\tthis.contentBox.addChild(callComponent);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall back to default on error\n\t\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0));\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No custom renderCall, show tool name\n\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolTitle\", theme.bold(this.toolName)), 0, 0));\n\t\t\t}\n\n\t\t\t// Render result component if we have a result\n\t\t\tif (this.result && this.toolDefinition.renderResult) {\n\t\t\t\ttry {\n\t\t\t\t\tconst resultComponent = this.toolDefinition.renderResult(\n\t\t\t\t\t\t{ content: this.result.content as any, details: this.result.details },\n\t\t\t\t\t\t{ expanded: this.expanded, isPartial: this.isPartial },\n\t\t\t\t\t\ttheme,\n\t\t\t\t\t);\n\t\t\t\t\tif (resultComponent) {\n\t\t\t\t\t\tthis.contentBox.addChild(resultComponent);\n\t\t\t\t\t}\n\t\t\t\t} catch {\n\t\t\t\t\t// Fall back to showing raw output on error\n\t\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\t\tif (output) {\n\t\t\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolOutput\", output), 0, 0));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (this.result) {\n\t\t\t\t// Has result but no custom renderResult\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tif (output) {\n\t\t\t\t\tthis.contentBox.addChild(new Text(theme.fg(\"toolOutput\", output), 0, 0));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Handle images (same for both custom and built-in)\n\t\tfor (const img of this.imageComponents) {\n\t\t\tthis.removeChild(img);\n\t\t}\n\t\tthis.imageComponents = [];\n\t\tfor (const spacer of this.imageSpacers) {\n\t\t\tthis.removeChild(spacer);\n\t\t}\n\t\tthis.imageSpacers = [];\n\n\t\tif (this.result) {\n\t\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\t\t\tconst caps = getCapabilities();\n\n\t\t\tfor (let i = 0; i < imageBlocks.length; i++) {\n\t\t\t\tconst img = imageBlocks[i];\n\t\t\t\tif (caps.images && this.showImages && img.data && img.mimeType) {\n\t\t\t\t\t// Use converted PNG for Kitty protocol if available\n\t\t\t\t\tconst converted = this.convertedImages.get(i);\n\t\t\t\t\tconst imageData = converted?.data ?? img.data;\n\t\t\t\t\tconst imageMimeType = converted?.mimeType ?? img.mimeType;\n\n\t\t\t\t\t// For Kitty, skip non-PNG images that haven't been converted yet\n\t\t\t\t\tif (caps.images === \"kitty\" && imageMimeType !== \"image/png\") {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst spacer = new Spacer(1);\n\t\t\t\t\tthis.addChild(spacer);\n\t\t\t\t\tthis.imageSpacers.push(spacer);\n\t\t\t\t\tconst imageComponent = new Image(\n\t\t\t\t\t\timageData,\n\t\t\t\t\t\timageMimeType,\n\t\t\t\t\t\t{ fallbackColor: (s: string) => theme.fg(\"toolOutput\", s) },\n\t\t\t\t\t\t{ maxWidthCells: 60 },\n\t\t\t\t\t);\n\t\t\t\t\tthis.imageComponents.push(imageComponent);\n\t\t\t\t\tthis.addChild(imageComponent);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Render bash content using visual line truncation (like bash-execution.ts)\n\t */\n\tprivate renderBashContent(): void {\n\t\tconst command = this.args?.command || \"\";\n\n\t\t// Header\n\t\tthis.contentBox.addChild(\n\t\t\tnew Text(theme.fg(\"toolTitle\", theme.bold(`$ ${command || theme.fg(\"toolOutput\", \"...\")}`)), 0, 0),\n\t\t);\n\n\t\tif (this.result) {\n\t\t\tconst output = this.getTextOutput().trim();\n\n\t\t\tif (output) {\n\t\t\t\t// Style each line for the output\n\t\t\t\tconst styledOutput = output\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.map((line) => theme.fg(\"toolOutput\", line))\n\t\t\t\t\t.join(\"\\n\");\n\n\t\t\t\tif (this.expanded) {\n\t\t\t\t\t// Show all lines when expanded\n\t\t\t\t\tthis.contentBox.addChild(new Text(`\\n${styledOutput}`, 0, 0));\n\t\t\t\t} else {\n\t\t\t\t\t// Use visual line truncation when collapsed with width-aware caching\n\t\t\t\t\tconst textContent = `\\n${styledOutput}`;\n\t\t\t\t\tlet cachedWidth: number | undefined;\n\t\t\t\t\tlet cachedLines: string[] | undefined;\n\t\t\t\t\tlet cachedSkipped: number | undefined;\n\n\t\t\t\t\tthis.contentBox.addChild({\n\t\t\t\t\t\trender: (width: number) => {\n\t\t\t\t\t\t\tif (cachedLines === undefined || cachedWidth !== width) {\n\t\t\t\t\t\t\t\tconst result = truncateToVisualLines(textContent, BASH_PREVIEW_LINES, width);\n\t\t\t\t\t\t\t\tcachedLines = result.visualLines;\n\t\t\t\t\t\t\t\tcachedSkipped = result.skippedCount;\n\t\t\t\t\t\t\t\tcachedWidth = width;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn cachedSkipped && cachedSkipped > 0\n\t\t\t\t\t\t\t\t? [\"\", theme.fg(\"toolOutput\", `... (${cachedSkipped} earlier lines)`), ...cachedLines]\n\t\t\t\t\t\t\t\t: cachedLines;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tinvalidate: () => {\n\t\t\t\t\t\t\tcachedWidth = undefined;\n\t\t\t\t\t\t\tcachedLines = undefined;\n\t\t\t\t\t\t\tcachedSkipped = undefined;\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Truncation warnings\n\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\tconst fullOutputPath = this.result.details?.fullOutputPath;\n\t\t\tif (truncation?.truncated || fullOutputPath) {\n\t\t\t\tconst warnings: string[] = [];\n\t\t\t\tif (fullOutputPath) {\n\t\t\t\t\twarnings.push(`Full output: ${fullOutputPath}`);\n\t\t\t\t}\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\twarnings.push(`Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\twarnings.push(\n\t\t\t\t\t\t\t`Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis.contentBox.addChild(new Text(`\\n${theme.fg(\"warning\", `[${warnings.join(\". \")}]`)}`, 0, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate getTextOutput(): string {\n\t\tif (!this.result) return \"\";\n\n\t\tconst textBlocks = this.result.content?.filter((c: any) => c.type === \"text\") || [];\n\t\tconst imageBlocks = this.result.content?.filter((c: any) => c.type === \"image\") || [];\n\n\t\tlet output = textBlocks\n\t\t\t.map((c: any) => {\n\t\t\t\t// Use sanitizeBinaryOutput to handle binary data that crashes string-width\n\t\t\t\treturn sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\");\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\n\t\tconst caps = getCapabilities();\n\t\tif (imageBlocks.length > 0 && (!caps.images || !this.showImages)) {\n\t\t\tconst imageIndicators = imageBlocks\n\t\t\t\t.map((img: any) => {\n\t\t\t\t\tconst dims = img.data ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\t\treturn imageFallback(img.mimeType, dims);\n\t\t\t\t})\n\t\t\t\t.join(\"\\n\");\n\t\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t\t}\n\n\t\treturn output;\n\t}\n\n\tprivate formatToolExecution(): string {\n\t\tlet text = \"\";\n\n\t\tif (this.toolName === \"read\") {\n\t\t\tconst path = shortenPath(this.args?.file_path || this.args?.path || \"\");\n\t\t\tconst offset = this.args?.offset;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tif (offset !== undefined || limit !== undefined) {\n\t\t\t\tconst startLine = offset ?? 1;\n\t\t\t\tconst endLine = limit !== undefined ? startLine + limit - 1 : \"\";\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${startLine}${endLine ? `-${endLine}` : \"\"}`);\n\t\t\t}\n\n\t\t\ttext = `${theme.fg(\"toolTitle\", theme.bold(\"read\"))} ${pathDisplay}`;\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput();\n\t\t\t\tconst rawPath = this.args?.file_path || this.args?.path || \"\";\n\t\t\t\tconst lang = getLanguageFromPath(rawPath);\n\t\t\t\tconst lines = lang ? highlightCode(replaceTabs(output), lang) : output.split(\"\\n\");\n\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext +=\n\t\t\t\t\t\"\\n\\n\" +\n\t\t\t\t\tdisplayLines\n\t\t\t\t\t\t.map((line: string) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line))))\n\t\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t}\n\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[First line exceeds ${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else if (truncation.truncatedBy === \"lines\") {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: showing ${truncation.outputLines} of ${truncation.totalLines} lines (${truncation.maxLines ?? DEFAULT_MAX_LINES} line limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttext +=\n\t\t\t\t\t\t\t\"\\n\" +\n\t\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\t`[Truncated: ${truncation.outputLines} lines shown (${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit)]`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"write\") {\n\t\t\tconst rawPath = this.args?.file_path || this.args?.path || \"\";\n\t\t\tconst path = shortenPath(rawPath);\n\t\t\tconst fileContent = this.args?.content || \"\";\n\t\t\tconst lang = getLanguageFromPath(rawPath);\n\t\t\tconst lines = fileContent\n\t\t\t\t? lang\n\t\t\t\t\t? highlightCode(replaceTabs(fileContent), lang)\n\t\t\t\t\t: fileContent.split(\"\\n\")\n\t\t\t\t: [];\n\t\t\tconst totalLines = lines.length;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"write\")) +\n\t\t\t\t\" \" +\n\t\t\t\t(path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\"));\n\n\t\t\tif (fileContent) {\n\t\t\t\tconst maxLines = this.expanded ? lines.length : 10;\n\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\ttext +=\n\t\t\t\t\t\"\\n\\n\" +\n\t\t\t\t\tdisplayLines\n\t\t\t\t\t\t.map((line: string) => (lang ? replaceTabs(line) : theme.fg(\"toolOutput\", replaceTabs(line))))\n\t\t\t\t\t\t.join(\"\\n\");\n\t\t\t\tif (remaining > 0) {\n\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines, ${totalLines} total)`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"edit\") {\n\t\t\tconst rawPath = this.args?.file_path || this.args?.path || \"\";\n\t\t\tconst path = shortenPath(rawPath);\n\n\t\t\t// Build path display, appending :line if we have diff info\n\t\t\tlet pathDisplay = path ? theme.fg(\"accent\", path) : theme.fg(\"toolOutput\", \"...\");\n\t\t\tconst firstChangedLine =\n\t\t\t\t(this.editDiffPreview && \"firstChangedLine\" in this.editDiffPreview\n\t\t\t\t\t? this.editDiffPreview.firstChangedLine\n\t\t\t\t\t: undefined) ||\n\t\t\t\t(this.result && !this.result.isError ? this.result.details?.firstChangedLine : undefined);\n\t\t\tif (firstChangedLine) {\n\t\t\t\tpathDisplay += theme.fg(\"warning\", `:${firstChangedLine}`);\n\t\t\t}\n\n\t\t\ttext = `${theme.fg(\"toolTitle\", theme.bold(\"edit\"))} ${pathDisplay}`;\n\n\t\t\tif (this.result?.isError) {\n\t\t\t\t// Show error from result\n\t\t\t\tconst errorText = this.getTextOutput();\n\t\t\t\tif (errorText) {\n\t\t\t\t\ttext += `\\n\\n${theme.fg(\"error\", errorText)}`;\n\t\t\t\t}\n\t\t\t} else if (this.result?.details?.diff) {\n\t\t\t\t// Tool executed successfully - use the diff from result\n\t\t\t\t// This takes priority over editDiffPreview which may have a stale error\n\t\t\t\t// due to race condition (async preview computed after file was modified)\n\t\t\t\ttext += `\\n\\n${renderDiff(this.result.details.diff, { filePath: rawPath })}`;\n\t\t\t} else if (this.editDiffPreview) {\n\t\t\t\t// Use cached diff preview (before tool executes)\n\t\t\t\tif (\"error\" in this.editDiffPreview) {\n\t\t\t\t\ttext += `\\n\\n${theme.fg(\"error\", this.editDiffPreview.error)}`;\n\t\t\t\t} else if (this.editDiffPreview.diff) {\n\t\t\t\t\ttext += `\\n\\n${renderDiff(this.editDiffPreview.diff, { filePath: rawPath })}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"ls\") {\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext = `${theme.fg(\"toolTitle\", theme.bold(\"ls\"))} ${theme.fg(\"accent\", path)}`;\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += `\\n\\n${displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst entryLimit = this.result.details?.entryLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (entryLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (entryLimit) {\n\t\t\t\t\t\twarnings.push(`${entryLimit} entries limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"find\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"find\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", pattern) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (limit ${limit})`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 20;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += `\\n\\n${displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst resultLimit = this.result.details?.resultLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tif (resultLimit || truncation?.truncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (resultLimit) {\n\t\t\t\t\t\twarnings.push(`${resultLimit} results limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else if (this.toolName === \"grep\") {\n\t\t\tconst pattern = this.args?.pattern || \"\";\n\t\t\tconst path = shortenPath(this.args?.path || \".\");\n\t\t\tconst glob = this.args?.glob;\n\t\t\tconst limit = this.args?.limit;\n\n\t\t\ttext =\n\t\t\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\t\t\" \" +\n\t\t\t\ttheme.fg(\"accent\", `/${pattern}/`) +\n\t\t\t\ttheme.fg(\"toolOutput\", ` in ${path}`);\n\t\t\tif (glob) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` (${glob})`);\n\t\t\t}\n\t\t\tif (limit !== undefined) {\n\t\t\t\ttext += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\t\t\t}\n\n\t\t\tif (this.result) {\n\t\t\t\tconst output = this.getTextOutput().trim();\n\t\t\t\tif (output) {\n\t\t\t\t\tconst lines = output.split(\"\\n\");\n\t\t\t\t\tconst maxLines = this.expanded ? lines.length : 15;\n\t\t\t\t\tconst displayLines = lines.slice(0, maxLines);\n\t\t\t\t\tconst remaining = lines.length - maxLines;\n\n\t\t\t\t\ttext += `\\n\\n${displayLines.map((line: string) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\t\t\t\tif (remaining > 0) {\n\t\t\t\t\t\ttext += theme.fg(\"toolOutput\", `\\n... (${remaining} more lines)`);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst matchLimit = this.result.details?.matchLimitReached;\n\t\t\t\tconst truncation = this.result.details?.truncation;\n\t\t\t\tconst linesTruncated = this.result.details?.linesTruncated;\n\t\t\t\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\t\t\t\tconst warnings: string[] = [];\n\t\t\t\t\tif (matchLimit) {\n\t\t\t\t\t\twarnings.push(`${matchLimit} matches limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (truncation?.truncated) {\n\t\t\t\t\t\twarnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\t\t\t\t}\n\t\t\t\t\tif (linesTruncated) {\n\t\t\t\t\t\twarnings.push(\"some lines truncated\");\n\t\t\t\t\t}\n\t\t\t\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t// Generic tool (shouldn't reach here for custom tools)\n\t\t\ttext = theme.fg(\"toolTitle\", theme.bold(this.toolName));\n\n\t\t\tconst content = JSON.stringify(this.args, null, 2);\n\t\t\ttext += `\\n\\n${content}`;\n\t\t\tconst output = this.getTextOutput();\n\t\t\tif (output) {\n\t\t\t\ttext += `\\n${output}`;\n\t\t\t}\n\t\t}\n\n\t\treturn text;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/theme.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { EditorTheme, MarkdownTheme, SelectListTheme } from \"@mariozechner/pi-tui\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { TypeCompiler } from \"@sinclair/typebox/compiler\";\nimport chalk from \"chalk\";\nimport { highlight, supportsLanguage } from \"cli-highlight\";\nimport { getCustomThemesDir, getThemesDir } from \"../../../config.js\";\n\n// ============================================================================\n// Types & Schema\n// ============================================================================\n\nconst ColorValueSchema = Type.Union([\n\tType.String(), // hex \"#ff0000\", var ref \"primary\", or empty \"\"\n\tType.Integer({ minimum: 0, maximum: 255 }), // 256-color index\n]);\n\ntype ColorValue = Static<typeof ColorValueSchema>;\n\nconst ThemeJsonSchema = Type.Object({\n\t$schema: Type.Optional(Type.String()),\n\tname: Type.String(),\n\tvars: Type.Optional(Type.Record(Type.String(), ColorValueSchema)),\n\tcolors: Type.Object({\n\t\t// Core UI (10 colors)\n\t\taccent: ColorValueSchema,\n\t\tborder: ColorValueSchema,\n\t\tborderAccent: ColorValueSchema,\n\t\tborderMuted: ColorValueSchema,\n\t\tsuccess: ColorValueSchema,\n\t\terror: ColorValueSchema,\n\t\twarning: ColorValueSchema,\n\t\tmuted: ColorValueSchema,\n\t\tdim: ColorValueSchema,\n\t\ttext: ColorValueSchema,\n\t\tthinkingText: ColorValueSchema,\n\t\t// Backgrounds & Content Text (11 colors)\n\t\tselectedBg: ColorValueSchema,\n\t\tuserMessageBg: ColorValueSchema,\n\t\tuserMessageText: ColorValueSchema,\n\t\tcustomMessageBg: ColorValueSchema,\n\t\tcustomMessageText: ColorValueSchema,\n\t\tcustomMessageLabel: ColorValueSchema,\n\t\ttoolPendingBg: ColorValueSchema,\n\t\ttoolSuccessBg: ColorValueSchema,\n\t\ttoolErrorBg: ColorValueSchema,\n\t\ttoolTitle: ColorValueSchema,\n\t\ttoolOutput: ColorValueSchema,\n\t\t// Markdown (10 colors)\n\t\tmdHeading: ColorValueSchema,\n\t\tmdLink: ColorValueSchema,\n\t\tmdLinkUrl: ColorValueSchema,\n\t\tmdCode: ColorValueSchema,\n\t\tmdCodeBlock: ColorValueSchema,\n\t\tmdCodeBlockBorder: ColorValueSchema,\n\t\tmdQuote: ColorValueSchema,\n\t\tmdQuoteBorder: ColorValueSchema,\n\t\tmdHr: ColorValueSchema,\n\t\tmdListBullet: ColorValueSchema,\n\t\t// Tool Diffs (3 colors)\n\t\ttoolDiffAdded: ColorValueSchema,\n\t\ttoolDiffRemoved: ColorValueSchema,\n\t\ttoolDiffContext: ColorValueSchema,\n\t\t// Syntax Highlighting (9 colors)\n\t\tsyntaxComment: ColorValueSchema,\n\t\tsyntaxKeyword: ColorValueSchema,\n\t\tsyntaxFunction: ColorValueSchema,\n\t\tsyntaxVariable: ColorValueSchema,\n\t\tsyntaxString: ColorValueSchema,\n\t\tsyntaxNumber: ColorValueSchema,\n\t\tsyntaxType: ColorValueSchema,\n\t\tsyntaxOperator: ColorValueSchema,\n\t\tsyntaxPunctuation: ColorValueSchema,\n\t\t// Thinking Level Borders (6 colors)\n\t\tthinkingOff: ColorValueSchema,\n\t\tthinkingMinimal: ColorValueSchema,\n\t\tthinkingLow: ColorValueSchema,\n\t\tthinkingMedium: ColorValueSchema,\n\t\tthinkingHigh: ColorValueSchema,\n\t\tthinkingXhigh: ColorValueSchema,\n\t\t// Bash Mode (1 color)\n\t\tbashMode: ColorValueSchema,\n\t}),\n\texport: Type.Optional(\n\t\tType.Object({\n\t\t\tpageBg: Type.Optional(ColorValueSchema),\n\t\t\tcardBg: Type.Optional(ColorValueSchema),\n\t\t\tinfoBg: Type.Optional(ColorValueSchema),\n\t\t}),\n\t),\n});\n\ntype ThemeJson = Static<typeof ThemeJsonSchema>;\n\nconst validateThemeJson = TypeCompiler.Compile(ThemeJsonSchema);\n\nexport type ThemeColor =\n\t| \"accent\"\n\t| \"border\"\n\t| \"borderAccent\"\n\t| \"borderMuted\"\n\t| \"success\"\n\t| \"error\"\n\t| \"warning\"\n\t| \"muted\"\n\t| \"dim\"\n\t| \"text\"\n\t| \"thinkingText\"\n\t| \"userMessageText\"\n\t| \"customMessageText\"\n\t| \"customMessageLabel\"\n\t| \"toolTitle\"\n\t| \"toolOutput\"\n\t| \"mdHeading\"\n\t| \"mdLink\"\n\t| \"mdLinkUrl\"\n\t| \"mdCode\"\n\t| \"mdCodeBlock\"\n\t| \"mdCodeBlockBorder\"\n\t| \"mdQuote\"\n\t| \"mdQuoteBorder\"\n\t| \"mdHr\"\n\t| \"mdListBullet\"\n\t| \"toolDiffAdded\"\n\t| \"toolDiffRemoved\"\n\t| \"toolDiffContext\"\n\t| \"syntaxComment\"\n\t| \"syntaxKeyword\"\n\t| \"syntaxFunction\"\n\t| \"syntaxVariable\"\n\t| \"syntaxString\"\n\t| \"syntaxNumber\"\n\t| \"syntaxType\"\n\t| \"syntaxOperator\"\n\t| \"syntaxPunctuation\"\n\t| \"thinkingOff\"\n\t| \"thinkingMinimal\"\n\t| \"thinkingLow\"\n\t| \"thinkingMedium\"\n\t| \"thinkingHigh\"\n\t| \"thinkingXhigh\"\n\t| \"bashMode\";\n\nexport type ThemeBg =\n\t| \"selectedBg\"\n\t| \"userMessageBg\"\n\t| \"customMessageBg\"\n\t| \"toolPendingBg\"\n\t| \"toolSuccessBg\"\n\t| \"toolErrorBg\";\n\ntype ColorMode = \"truecolor\" | \"256color\";\n\n// ============================================================================\n// Color Utilities\n// ============================================================================\n\nfunction detectColorMode(): ColorMode {\n\tconst colorterm = process.env.COLORTERM;\n\tif (colorterm === \"truecolor\" || colorterm === \"24bit\") {\n\t\treturn \"truecolor\";\n\t}\n\t// Windows Terminal supports truecolor\n\tif (process.env.WT_SESSION) {\n\t\treturn \"truecolor\";\n\t}\n\tconst term = process.env.TERM || \"\";\n\t// Only fall back to 256color for truly limited terminals\n\tif (term === \"dumb\" || term === \"\" || term === \"linux\") {\n\t\treturn \"256color\";\n\t}\n\t// Assume truecolor for everything else - virtually all modern terminals support it\n\treturn \"truecolor\";\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n\tconst cleaned = hex.replace(\"#\", \"\");\n\tif (cleaned.length !== 6) {\n\t\tthrow new Error(`Invalid hex color: ${hex}`);\n\t}\n\tconst r = parseInt(cleaned.substring(0, 2), 16);\n\tconst g = parseInt(cleaned.substring(2, 4), 16);\n\tconst b = parseInt(cleaned.substring(4, 6), 16);\n\tif (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {\n\t\tthrow new Error(`Invalid hex color: ${hex}`);\n\t}\n\treturn { r, g, b };\n}\n\n// The 6x6x6 color cube channel values (indices 0-5)\nconst CUBE_VALUES = [0, 95, 135, 175, 215, 255];\n\n// Grayscale ramp values (indices 232-255, 24 grays from 8 to 238)\nconst GRAY_VALUES = Array.from({ length: 24 }, (_, i) => 8 + i * 10);\n\nfunction findClosestCubeIndex(value: number): number {\n\tlet minDist = Infinity;\n\tlet minIdx = 0;\n\tfor (let i = 0; i < CUBE_VALUES.length; i++) {\n\t\tconst dist = Math.abs(value - CUBE_VALUES[i]);\n\t\tif (dist < minDist) {\n\t\t\tminDist = dist;\n\t\t\tminIdx = i;\n\t\t}\n\t}\n\treturn minIdx;\n}\n\nfunction findClosestGrayIndex(gray: number): number {\n\tlet minDist = Infinity;\n\tlet minIdx = 0;\n\tfor (let i = 0; i < GRAY_VALUES.length; i++) {\n\t\tconst dist = Math.abs(gray - GRAY_VALUES[i]);\n\t\tif (dist < minDist) {\n\t\t\tminDist = dist;\n\t\t\tminIdx = i;\n\t\t}\n\t}\n\treturn minIdx;\n}\n\nfunction colorDistance(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number): number {\n\t// Weighted Euclidean distance (human eye is more sensitive to green)\n\tconst dr = r1 - r2;\n\tconst dg = g1 - g2;\n\tconst db = b1 - b2;\n\treturn dr * dr * 0.299 + dg * dg * 0.587 + db * db * 0.114;\n}\n\nfunction rgbTo256(r: number, g: number, b: number): number {\n\t// Find closest color in the 6x6x6 cube\n\tconst rIdx = findClosestCubeIndex(r);\n\tconst gIdx = findClosestCubeIndex(g);\n\tconst bIdx = findClosestCubeIndex(b);\n\tconst cubeR = CUBE_VALUES[rIdx];\n\tconst cubeG = CUBE_VALUES[gIdx];\n\tconst cubeB = CUBE_VALUES[bIdx];\n\tconst cubeIndex = 16 + 36 * rIdx + 6 * gIdx + bIdx;\n\tconst cubeDist = colorDistance(r, g, b, cubeR, cubeG, cubeB);\n\n\t// Find closest grayscale\n\tconst gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);\n\tconst grayIdx = findClosestGrayIndex(gray);\n\tconst grayValue = GRAY_VALUES[grayIdx];\n\tconst grayIndex = 232 + grayIdx;\n\tconst grayDist = colorDistance(r, g, b, grayValue, grayValue, grayValue);\n\n\t// Check if color has noticeable saturation (hue matters)\n\t// If max-min spread is significant, prefer cube to preserve tint\n\tconst maxC = Math.max(r, g, b);\n\tconst minC = Math.min(r, g, b);\n\tconst spread = maxC - minC;\n\n\t// Only consider grayscale if color is nearly neutral (spread < 10)\n\t// AND grayscale is actually closer\n\tif (spread < 10 && grayDist < cubeDist) {\n\t\treturn grayIndex;\n\t}\n\n\treturn cubeIndex;\n}\n\nfunction hexTo256(hex: string): number {\n\tconst { r, g, b } = hexToRgb(hex);\n\treturn rgbTo256(r, g, b);\n}\n\nfunction fgAnsi(color: string | number, mode: ColorMode): string {\n\tif (color === \"\") return \"\\x1b[39m\";\n\tif (typeof color === \"number\") return `\\x1b[38;5;${color}m`;\n\tif (color.startsWith(\"#\")) {\n\t\tif (mode === \"truecolor\") {\n\t\t\tconst { r, g, b } = hexToRgb(color);\n\t\t\treturn `\\x1b[38;2;${r};${g};${b}m`;\n\t\t} else {\n\t\t\tconst index = hexTo256(color);\n\t\t\treturn `\\x1b[38;5;${index}m`;\n\t\t}\n\t}\n\tthrow new Error(`Invalid color value: ${color}`);\n}\n\nfunction bgAnsi(color: string | number, mode: ColorMode): string {\n\tif (color === \"\") return \"\\x1b[49m\";\n\tif (typeof color === \"number\") return `\\x1b[48;5;${color}m`;\n\tif (color.startsWith(\"#\")) {\n\t\tif (mode === \"truecolor\") {\n\t\t\tconst { r, g, b } = hexToRgb(color);\n\t\t\treturn `\\x1b[48;2;${r};${g};${b}m`;\n\t\t} else {\n\t\t\tconst index = hexTo256(color);\n\t\t\treturn `\\x1b[48;5;${index}m`;\n\t\t}\n\t}\n\tthrow new Error(`Invalid color value: ${color}`);\n}\n\nfunction resolveVarRefs(\n\tvalue: ColorValue,\n\tvars: Record<string, ColorValue>,\n\tvisited = new Set<string>(),\n): string | number {\n\tif (typeof value === \"number\" || value === \"\" || value.startsWith(\"#\")) {\n\t\treturn value;\n\t}\n\tif (visited.has(value)) {\n\t\tthrow new Error(`Circular variable reference detected: ${value}`);\n\t}\n\tif (!(value in vars)) {\n\t\tthrow new Error(`Variable reference not found: ${value}`);\n\t}\n\tvisited.add(value);\n\treturn resolveVarRefs(vars[value], vars, visited);\n}\n\nfunction resolveThemeColors<T extends Record<string, ColorValue>>(\n\tcolors: T,\n\tvars: Record<string, ColorValue> = {},\n): Record<keyof T, string | number> {\n\tconst resolved: Record<string, string | number> = {};\n\tfor (const [key, value] of Object.entries(colors)) {\n\t\tresolved[key] = resolveVarRefs(value, vars);\n\t}\n\treturn resolved as Record<keyof T, string | number>;\n}\n\n// ============================================================================\n// Theme Class\n// ============================================================================\n\nexport class Theme {\n\tprivate fgColors: Map<ThemeColor, string>;\n\tprivate bgColors: Map<ThemeBg, string>;\n\tprivate mode: ColorMode;\n\n\tconstructor(\n\t\tfgColors: Record<ThemeColor, string | number>,\n\t\tbgColors: Record<ThemeBg, string | number>,\n\t\tmode: ColorMode,\n\t) {\n\t\tthis.mode = mode;\n\t\tthis.fgColors = new Map();\n\t\tfor (const [key, value] of Object.entries(fgColors) as [ThemeColor, string | number][]) {\n\t\t\tthis.fgColors.set(key, fgAnsi(value, mode));\n\t\t}\n\t\tthis.bgColors = new Map();\n\t\tfor (const [key, value] of Object.entries(bgColors) as [ThemeBg, string | number][]) {\n\t\t\tthis.bgColors.set(key, bgAnsi(value, mode));\n\t\t}\n\t}\n\n\tfg(color: ThemeColor, text: string): string {\n\t\tconst ansi = this.fgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme color: ${color}`);\n\t\treturn `${ansi}${text}\\x1b[39m`; // Reset only foreground color\n\t}\n\n\tbg(color: ThemeBg, text: string): string {\n\t\tconst ansi = this.bgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme background color: ${color}`);\n\t\treturn `${ansi}${text}\\x1b[49m`; // Reset only background color\n\t}\n\n\tbold(text: string): string {\n\t\treturn chalk.bold(text);\n\t}\n\n\titalic(text: string): string {\n\t\treturn chalk.italic(text);\n\t}\n\n\tunderline(text: string): string {\n\t\treturn chalk.underline(text);\n\t}\n\n\tinverse(text: string): string {\n\t\treturn chalk.inverse(text);\n\t}\n\n\tstrikethrough(text: string): string {\n\t\treturn chalk.strikethrough(text);\n\t}\n\n\tgetFgAnsi(color: ThemeColor): string {\n\t\tconst ansi = this.fgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme color: ${color}`);\n\t\treturn ansi;\n\t}\n\n\tgetBgAnsi(color: ThemeBg): string {\n\t\tconst ansi = this.bgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme background color: ${color}`);\n\t\treturn ansi;\n\t}\n\n\tgetColorMode(): ColorMode {\n\t\treturn this.mode;\n\t}\n\n\tgetThinkingBorderColor(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"): (str: string) => string {\n\t\t// Map thinking levels to dedicated theme colors\n\t\tswitch (level) {\n\t\t\tcase \"off\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingOff\", str);\n\t\t\tcase \"minimal\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingMinimal\", str);\n\t\t\tcase \"low\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingLow\", str);\n\t\t\tcase \"medium\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingMedium\", str);\n\t\t\tcase \"high\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingHigh\", str);\n\t\t\tcase \"xhigh\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingXhigh\", str);\n\t\t\tdefault:\n\t\t\t\treturn (str: string) => this.fg(\"thinkingOff\", str);\n\t\t}\n\t}\n\n\tgetBashModeBorderColor(): (str: string) => string {\n\t\treturn (str: string) => this.fg(\"bashMode\", str);\n\t}\n}\n\n// ============================================================================\n// Theme Loading\n// ============================================================================\n\nlet BUILTIN_THEMES: Record<string, ThemeJson> | undefined;\n\nfunction getBuiltinThemes(): Record<string, ThemeJson> {\n\tif (!BUILTIN_THEMES) {\n\t\tconst themesDir = getThemesDir();\n\t\tconst darkPath = path.join(themesDir, \"dark.json\");\n\t\tconst lightPath = path.join(themesDir, \"light.json\");\n\t\tBUILTIN_THEMES = {\n\t\t\tdark: JSON.parse(fs.readFileSync(darkPath, \"utf-8\")) as ThemeJson,\n\t\t\tlight: JSON.parse(fs.readFileSync(lightPath, \"utf-8\")) as ThemeJson,\n\t\t};\n\t}\n\treturn BUILTIN_THEMES;\n}\n\nexport function getAvailableThemes(): string[] {\n\tconst themes = new Set<string>(Object.keys(getBuiltinThemes()));\n\tconst customThemesDir = getCustomThemesDir();\n\tif (fs.existsSync(customThemesDir)) {\n\t\tconst files = fs.readdirSync(customThemesDir);\n\t\tfor (const file of files) {\n\t\t\tif (file.endsWith(\".json\")) {\n\t\t\t\tthemes.add(file.slice(0, -5));\n\t\t\t}\n\t\t}\n\t}\n\treturn Array.from(themes).sort();\n}\n\nexport interface ThemeInfo {\n\tname: string;\n\tpath: string | undefined;\n}\n\nexport function getAvailableThemesWithPaths(): ThemeInfo[] {\n\tconst themesDir = getThemesDir();\n\tconst customThemesDir = getCustomThemesDir();\n\tconst result: ThemeInfo[] = [];\n\n\t// Built-in themes\n\tfor (const name of Object.keys(getBuiltinThemes())) {\n\t\tresult.push({ name, path: path.join(themesDir, `${name}.json`) });\n\t}\n\n\t// Custom themes\n\tif (fs.existsSync(customThemesDir)) {\n\t\tfor (const file of fs.readdirSync(customThemesDir)) {\n\t\t\tif (file.endsWith(\".json\")) {\n\t\t\t\tconst name = file.slice(0, -5);\n\t\t\t\tif (!result.some((t) => t.name === name)) {\n\t\t\t\t\tresult.push({ name, path: path.join(customThemesDir, file) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction loadThemeJson(name: string): ThemeJson {\n\tconst builtinThemes = getBuiltinThemes();\n\tif (name in builtinThemes) {\n\t\treturn builtinThemes[name];\n\t}\n\tconst customThemesDir = getCustomThemesDir();\n\tconst themePath = path.join(customThemesDir, `${name}.json`);\n\tif (!fs.existsSync(themePath)) {\n\t\tthrow new Error(`Theme not found: ${name}`);\n\t}\n\tconst content = fs.readFileSync(themePath, \"utf-8\");\n\tlet json: unknown;\n\ttry {\n\t\tjson = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new Error(`Failed to parse theme ${name}: ${error}`);\n\t}\n\tif (!validateThemeJson.Check(json)) {\n\t\tconst errors = Array.from(validateThemeJson.Errors(json));\n\t\tconst missingColors: string[] = [];\n\t\tconst otherErrors: string[] = [];\n\n\t\tfor (const e of errors) {\n\t\t\t// Check for missing required color properties\n\t\t\tconst match = e.path.match(/^\\/colors\\/(\\w+)$/);\n\t\t\tif (match && e.message.includes(\"Required\")) {\n\t\t\t\tmissingColors.push(match[1]);\n\t\t\t} else {\n\t\t\t\totherErrors.push(` - ${e.path}: ${e.message}`);\n\t\t\t}\n\t\t}\n\n\t\tlet errorMessage = `Invalid theme \"${name}\":\\n`;\n\t\tif (missingColors.length > 0) {\n\t\t\terrorMessage += `\\nMissing required color tokens:\\n`;\n\t\t\terrorMessage += missingColors.map((c) => ` - ${c}`).join(\"\\n\");\n\t\t\terrorMessage += `\\n\\nPlease add these colors to your theme's \"colors\" object.`;\n\t\t\terrorMessage += `\\nSee the built-in themes (dark.json, light.json) for reference values.`;\n\t\t}\n\t\tif (otherErrors.length > 0) {\n\t\t\terrorMessage += `\\n\\nOther errors:\\n${otherErrors.join(\"\\n\")}`;\n\t\t}\n\n\t\tthrow new Error(errorMessage);\n\t}\n\treturn json as ThemeJson;\n}\n\nfunction createTheme(themeJson: ThemeJson, mode?: ColorMode): Theme {\n\tconst colorMode = mode ?? detectColorMode();\n\tconst resolvedColors = resolveThemeColors(themeJson.colors, themeJson.vars);\n\tconst fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;\n\tconst bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;\n\tconst bgColorKeys: Set<string> = new Set([\n\t\t\"selectedBg\",\n\t\t\"userMessageBg\",\n\t\t\"customMessageBg\",\n\t\t\"toolPendingBg\",\n\t\t\"toolSuccessBg\",\n\t\t\"toolErrorBg\",\n\t]);\n\tfor (const [key, value] of Object.entries(resolvedColors)) {\n\t\tif (bgColorKeys.has(key)) {\n\t\t\tbgColors[key as ThemeBg] = value;\n\t\t} else {\n\t\t\tfgColors[key as ThemeColor] = value;\n\t\t}\n\t}\n\treturn new Theme(fgColors, bgColors, colorMode);\n}\n\nfunction loadTheme(name: string, mode?: ColorMode): Theme {\n\tconst themeJson = loadThemeJson(name);\n\treturn createTheme(themeJson, mode);\n}\n\nexport function getThemeByName(name: string): Theme | undefined {\n\ttry {\n\t\treturn loadTheme(name);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction detectTerminalBackground(): \"dark\" | \"light\" {\n\tconst colorfgbg = process.env.COLORFGBG || \"\";\n\tif (colorfgbg) {\n\t\tconst parts = colorfgbg.split(\";\");\n\t\tif (parts.length >= 2) {\n\t\t\tconst bg = parseInt(parts[1], 10);\n\t\t\tif (!Number.isNaN(bg)) {\n\t\t\t\tconst result = bg < 8 ? \"dark\" : \"light\";\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\treturn \"dark\";\n}\n\nfunction getDefaultTheme(): string {\n\treturn detectTerminalBackground();\n}\n\n// ============================================================================\n// Global Theme Instance\n// ============================================================================\n\nexport let theme: Theme;\nlet currentThemeName: string | undefined;\nlet themeWatcher: fs.FSWatcher | undefined;\nlet onThemeChangeCallback: (() => void) | undefined;\n\nexport function initTheme(themeName?: string, enableWatcher: boolean = false): void {\n\tconst name = themeName ?? getDefaultTheme();\n\tcurrentThemeName = name;\n\ttry {\n\t\ttheme = loadTheme(name);\n\t\tif (enableWatcher) {\n\t\t\tstartThemeWatcher();\n\t\t}\n\t} catch (_error) {\n\t\t// Theme is invalid - fall back to dark theme silently\n\t\tcurrentThemeName = \"dark\";\n\t\ttheme = loadTheme(\"dark\");\n\t\t// Don't start watcher for fallback theme\n\t}\n}\n\nexport function setTheme(name: string, enableWatcher: boolean = false): { success: boolean; error?: string } {\n\tcurrentThemeName = name;\n\ttry {\n\t\ttheme = loadTheme(name);\n\t\tif (enableWatcher) {\n\t\t\tstartThemeWatcher();\n\t\t}\n\t\treturn { success: true };\n\t} catch (error) {\n\t\t// Theme is invalid - fall back to dark theme\n\t\tcurrentThemeName = \"dark\";\n\t\ttheme = loadTheme(\"dark\");\n\t\t// Don't start watcher for fallback theme\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t}\n}\n\nexport function setThemeInstance(themeInstance: Theme): void {\n\ttheme = themeInstance;\n\tcurrentThemeName = \"<in-memory>\";\n\tstopThemeWatcher(); // Can't watch a direct instance\n}\n\nexport function onThemeChange(callback: () => void): void {\n\tonThemeChangeCallback = callback;\n}\n\nfunction startThemeWatcher(): void {\n\t// Stop existing watcher if any\n\tif (themeWatcher) {\n\t\tthemeWatcher.close();\n\t\tthemeWatcher = undefined;\n\t}\n\n\t// Only watch if it's a custom theme (not built-in)\n\tif (!currentThemeName || currentThemeName === \"dark\" || currentThemeName === \"light\") {\n\t\treturn;\n\t}\n\n\tconst customThemesDir = getCustomThemesDir();\n\tconst themeFile = path.join(customThemesDir, `${currentThemeName}.json`);\n\n\t// Only watch if the file exists\n\tif (!fs.existsSync(themeFile)) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tthemeWatcher = fs.watch(themeFile, (eventType) => {\n\t\t\tif (eventType === \"change\") {\n\t\t\t\t// Debounce rapid changes\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Reload the theme\n\t\t\t\t\t\ttheme = loadTheme(currentThemeName!);\n\t\t\t\t\t\t// Notify callback (to invalidate UI)\n\t\t\t\t\t\tif (onThemeChangeCallback) {\n\t\t\t\t\t\t\tonThemeChangeCallback();\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (_error) {\n\t\t\t\t\t\t// Ignore errors (file might be in invalid state while being edited)\n\t\t\t\t\t}\n\t\t\t\t}, 100);\n\t\t\t} else if (eventType === \"rename\") {\n\t\t\t\t// File was deleted or renamed - fall back to default theme\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!fs.existsSync(themeFile)) {\n\t\t\t\t\t\tcurrentThemeName = \"dark\";\n\t\t\t\t\t\ttheme = loadTheme(\"dark\");\n\t\t\t\t\t\tif (themeWatcher) {\n\t\t\t\t\t\t\tthemeWatcher.close();\n\t\t\t\t\t\t\tthemeWatcher = undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (onThemeChangeCallback) {\n\t\t\t\t\t\t\tonThemeChangeCallback();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, 100);\n\t\t\t}\n\t\t});\n\t} catch (_error) {\n\t\t// Ignore errors starting watcher\n\t}\n}\n\nexport function stopThemeWatcher(): void {\n\tif (themeWatcher) {\n\t\tthemeWatcher.close();\n\t\tthemeWatcher = undefined;\n\t}\n}\n\n// ============================================================================\n// HTML Export Helpers\n// ============================================================================\n\n/**\n * Convert a 256-color index to hex string.\n * Indices 0-15: basic colors (approximate)\n * Indices 16-231: 6x6x6 color cube\n * Indices 232-255: grayscale ramp\n */\nfunction ansi256ToHex(index: number): string {\n\t// Basic colors (0-15) - approximate common terminal values\n\tconst basicColors = [\n\t\t\"#000000\",\n\t\t\"#800000\",\n\t\t\"#008000\",\n\t\t\"#808000\",\n\t\t\"#000080\",\n\t\t\"#800080\",\n\t\t\"#008080\",\n\t\t\"#c0c0c0\",\n\t\t\"#808080\",\n\t\t\"#ff0000\",\n\t\t\"#00ff00\",\n\t\t\"#ffff00\",\n\t\t\"#0000ff\",\n\t\t\"#ff00ff\",\n\t\t\"#00ffff\",\n\t\t\"#ffffff\",\n\t];\n\tif (index < 16) {\n\t\treturn basicColors[index];\n\t}\n\n\t// Color cube (16-231): 6x6x6 = 216 colors\n\tif (index < 232) {\n\t\tconst cubeIndex = index - 16;\n\t\tconst r = Math.floor(cubeIndex / 36);\n\t\tconst g = Math.floor((cubeIndex % 36) / 6);\n\t\tconst b = cubeIndex % 6;\n\t\tconst toHex = (n: number) => (n === 0 ? 0 : 55 + n * 40).toString(16).padStart(2, \"0\");\n\t\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n\t}\n\n\t// Grayscale (232-255): 24 shades\n\tconst gray = 8 + (index - 232) * 10;\n\tconst grayHex = gray.toString(16).padStart(2, \"0\");\n\treturn `#${grayHex}${grayHex}${grayHex}`;\n}\n\n/**\n * Get resolved theme colors as CSS-compatible hex strings.\n * Used by HTML export to generate CSS custom properties.\n */\nexport function getResolvedThemeColors(themeName?: string): Record<string, string> {\n\tconst name = themeName ?? getDefaultTheme();\n\tconst isLight = name === \"light\";\n\tconst themeJson = loadThemeJson(name);\n\tconst resolved = resolveThemeColors(themeJson.colors, themeJson.vars);\n\n\t// Default text color for empty values (terminal uses default fg color)\n\tconst defaultText = isLight ? \"#000000\" : \"#e5e5e7\";\n\n\tconst cssColors: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(resolved)) {\n\t\tif (typeof value === \"number\") {\n\t\t\tcssColors[key] = ansi256ToHex(value);\n\t\t} else if (value === \"\") {\n\t\t\t// Empty means default terminal color - use sensible fallback for HTML\n\t\t\tcssColors[key] = defaultText;\n\t\t} else {\n\t\t\tcssColors[key] = value;\n\t\t}\n\t}\n\treturn cssColors;\n}\n\n/**\n * Check if a theme is a \"light\" theme (for CSS that needs light/dark variants).\n */\nexport function isLightTheme(themeName?: string): boolean {\n\t// Currently just check the name - could be extended to analyze colors\n\treturn themeName === \"light\";\n}\n\n/**\n * Get explicit export colors from theme JSON, if specified.\n * Returns undefined for each color that isn't explicitly set.\n */\nexport function getThemeExportColors(themeName?: string): {\n\tpageBg?: string;\n\tcardBg?: string;\n\tinfoBg?: string;\n} {\n\tconst name = themeName ?? getDefaultTheme();\n\ttry {\n\t\tconst themeJson = loadThemeJson(name);\n\t\tconst exportSection = themeJson.export;\n\t\tif (!exportSection) return {};\n\n\t\tconst vars = themeJson.vars ?? {};\n\t\tconst resolve = (value: string | number | undefined): string | undefined => {\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (typeof value === \"number\") return ansi256ToHex(value);\n\t\t\tif (value.startsWith(\"$\")) {\n\t\t\t\tconst resolved = vars[value];\n\t\t\t\tif (resolved === undefined) return undefined;\n\t\t\t\tif (typeof resolved === \"number\") return ansi256ToHex(resolved);\n\t\t\t\treturn resolved;\n\t\t\t}\n\t\t\treturn value;\n\t\t};\n\n\t\treturn {\n\t\t\tpageBg: resolve(exportSection.pageBg),\n\t\t\tcardBg: resolve(exportSection.cardBg),\n\t\t\tinfoBg: resolve(exportSection.infoBg),\n\t\t};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n// ============================================================================\n// TUI Helpers\n// ============================================================================\n\ntype CliHighlightTheme = Record<string, (s: string) => string>;\n\nlet cachedHighlightThemeFor: Theme | undefined;\nlet cachedCliHighlightTheme: CliHighlightTheme | undefined;\n\nfunction buildCliHighlightTheme(t: Theme): CliHighlightTheme {\n\treturn {\n\t\tkeyword: (s: string) => t.fg(\"syntaxKeyword\", s),\n\t\tbuilt_in: (s: string) => t.fg(\"syntaxType\", s),\n\t\tliteral: (s: string) => t.fg(\"syntaxNumber\", s),\n\t\tnumber: (s: string) => t.fg(\"syntaxNumber\", s),\n\t\tstring: (s: string) => t.fg(\"syntaxString\", s),\n\t\tcomment: (s: string) => t.fg(\"syntaxComment\", s),\n\t\tfunction: (s: string) => t.fg(\"syntaxFunction\", s),\n\t\ttitle: (s: string) => t.fg(\"syntaxFunction\", s),\n\t\tclass: (s: string) => t.fg(\"syntaxType\", s),\n\t\ttype: (s: string) => t.fg(\"syntaxType\", s),\n\t\tattr: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\tvariable: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\tparams: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\toperator: (s: string) => t.fg(\"syntaxOperator\", s),\n\t\tpunctuation: (s: string) => t.fg(\"syntaxPunctuation\", s),\n\t};\n}\n\nfunction getCliHighlightTheme(t: Theme): CliHighlightTheme {\n\tif (cachedHighlightThemeFor !== t || !cachedCliHighlightTheme) {\n\t\tcachedHighlightThemeFor = t;\n\t\tcachedCliHighlightTheme = buildCliHighlightTheme(t);\n\t}\n\treturn cachedCliHighlightTheme;\n}\n\n/**\n * Highlight code with syntax coloring based on file extension or language.\n * Returns array of highlighted lines.\n */\nexport function highlightCode(code: string, lang?: string): string[] {\n\t// Validate language before highlighting to avoid stderr spam from cli-highlight\n\tconst validLang = lang && supportsLanguage(lang) ? lang : undefined;\n\tconst opts = {\n\t\tlanguage: validLang,\n\t\tignoreIllegals: true,\n\t\ttheme: getCliHighlightTheme(theme),\n\t};\n\ttry {\n\t\treturn highlight(code, opts).split(\"\\n\");\n\t} catch {\n\t\treturn code.split(\"\\n\");\n\t}\n}\n\n/**\n * Get language identifier from file path extension.\n */\nexport function getLanguageFromPath(filePath: string): string | undefined {\n\tconst ext = filePath.split(\".\").pop()?.toLowerCase();\n\tif (!ext) return undefined;\n\n\tconst extToLang: Record<string, string> = {\n\t\tts: \"typescript\",\n\t\ttsx: \"typescript\",\n\t\tjs: \"javascript\",\n\t\tjsx: \"javascript\",\n\t\tmjs: \"javascript\",\n\t\tcjs: \"javascript\",\n\t\tpy: \"python\",\n\t\trb: \"ruby\",\n\t\trs: \"rust\",\n\t\tgo: \"go\",\n\t\tjava: \"java\",\n\t\tkt: \"kotlin\",\n\t\tswift: \"swift\",\n\t\tc: \"c\",\n\t\th: \"c\",\n\t\tcpp: \"cpp\",\n\t\tcc: \"cpp\",\n\t\tcxx: \"cpp\",\n\t\thpp: \"cpp\",\n\t\tcs: \"csharp\",\n\t\tphp: \"php\",\n\t\tsh: \"bash\",\n\t\tbash: \"bash\",\n\t\tzsh: \"bash\",\n\t\tfish: \"fish\",\n\t\tps1: \"powershell\",\n\t\tsql: \"sql\",\n\t\thtml: \"html\",\n\t\thtm: \"html\",\n\t\tcss: \"css\",\n\t\tscss: \"scss\",\n\t\tsass: \"sass\",\n\t\tless: \"less\",\n\t\tjson: \"json\",\n\t\tyaml: \"yaml\",\n\t\tyml: \"yaml\",\n\t\ttoml: \"toml\",\n\t\txml: \"xml\",\n\t\tmd: \"markdown\",\n\t\tmarkdown: \"markdown\",\n\t\tdockerfile: \"dockerfile\",\n\t\tmakefile: \"makefile\",\n\t\tcmake: \"cmake\",\n\t\tlua: \"lua\",\n\t\tperl: \"perl\",\n\t\tr: \"r\",\n\t\tscala: \"scala\",\n\t\tclj: \"clojure\",\n\t\tex: \"elixir\",\n\t\texs: \"elixir\",\n\t\terl: \"erlang\",\n\t\ths: \"haskell\",\n\t\tml: \"ocaml\",\n\t\tvim: \"vim\",\n\t\tgraphql: \"graphql\",\n\t\tproto: \"protobuf\",\n\t\ttf: \"hcl\",\n\t\thcl: \"hcl\",\n\t};\n\n\treturn extToLang[ext];\n}\n\nexport function getMarkdownTheme(): MarkdownTheme {\n\treturn {\n\t\theading: (text: string) => theme.fg(\"mdHeading\", text),\n\t\tlink: (text: string) => theme.fg(\"mdLink\", text),\n\t\tlinkUrl: (text: string) => theme.fg(\"mdLinkUrl\", text),\n\t\tcode: (text: string) => theme.fg(\"mdCode\", text),\n\t\tcodeBlock: (text: string) => theme.fg(\"mdCodeBlock\", text),\n\t\tcodeBlockBorder: (text: string) => theme.fg(\"mdCodeBlockBorder\", text),\n\t\tquote: (text: string) => theme.fg(\"mdQuote\", text),\n\t\tquoteBorder: (text: string) => theme.fg(\"mdQuoteBorder\", text),\n\t\thr: (text: string) => theme.fg(\"mdHr\", text),\n\t\tlistBullet: (text: string) => theme.fg(\"mdListBullet\", text),\n\t\tbold: (text: string) => theme.bold(text),\n\t\titalic: (text: string) => theme.italic(text),\n\t\tunderline: (text: string) => theme.underline(text),\n\t\tstrikethrough: (text: string) => chalk.strikethrough(text),\n\t\thighlightCode: (code: string, lang?: string): string[] => {\n\t\t\t// Validate language before highlighting to avoid stderr spam from cli-highlight\n\t\t\tconst validLang = lang && supportsLanguage(lang) ? lang : undefined;\n\t\t\tconst opts = {\n\t\t\t\tlanguage: validLang,\n\t\t\t\tignoreIllegals: true,\n\t\t\t\ttheme: getCliHighlightTheme(theme),\n\t\t\t};\n\t\t\ttry {\n\t\t\t\treturn highlight(code, opts).split(\"\\n\");\n\t\t\t} catch {\n\t\t\t\treturn code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function getSelectListTheme(): SelectListTheme {\n\treturn {\n\t\tselectedPrefix: (text: string) => theme.fg(\"accent\", text),\n\t\tselectedText: (text: string) => theme.fg(\"accent\", text),\n\t\tdescription: (text: string) => theme.fg(\"muted\", text),\n\t\tscrollInfo: (text: string) => theme.fg(\"muted\", text),\n\t\tnoMatch: (text: string) => theme.fg(\"muted\", text),\n\t};\n}\n\nexport function getEditorTheme(): EditorTheme {\n\treturn {\n\t\tborderColor: (text: string) => theme.fg(\"borderMuted\", text),\n\t\tselectList: getSelectListTheme(),\n\t};\n}\n\nexport function getSettingsListTheme(): import(\"@mariozechner/pi-tui\").SettingsListTheme {\n\treturn {\n\t\tlabel: (text: string, selected: boolean) => (selected ? theme.fg(\"accent\", text) : text),\n\t\tvalue: (text: string, selected: boolean) => (selected ? theme.fg(\"accent\", text) : theme.fg(\"muted\", text)),\n\t\tdescription: (text: string) => theme.fg(\"dim\", text),\n\t\tcursor: theme.fg(\"accent\", \"→ \"),\n\t\thint: (text: string) => theme.fg(\"dim\", text),\n\t};\n}\n"]}
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/theme/theme.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { EditorTheme, MarkdownTheme, SelectListTheme } from \"@mariozechner/pi-tui\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { TypeCompiler } from \"@sinclair/typebox/compiler\";\nimport chalk from \"chalk\";\nimport { highlight, supportsLanguage } from \"cli-highlight\";\nimport { getCustomThemesDir, getThemesDir } from \"../../../config.js\";\n\n// ============================================================================\n// Types & Schema\n// ============================================================================\n\nconst ColorValueSchema = Type.Union([\n\tType.String(), // hex \"#ff0000\", var ref \"primary\", or empty \"\"\n\tType.Integer({ minimum: 0, maximum: 255 }), // 256-color index\n]);\n\ntype ColorValue = Static<typeof ColorValueSchema>;\n\nconst ThemeJsonSchema = Type.Object({\n\t$schema: Type.Optional(Type.String()),\n\tname: Type.String(),\n\tvars: Type.Optional(Type.Record(Type.String(), ColorValueSchema)),\n\tcolors: Type.Object({\n\t\t// Core UI (10 colors)\n\t\taccent: ColorValueSchema,\n\t\tborder: ColorValueSchema,\n\t\tborderAccent: ColorValueSchema,\n\t\tborderMuted: ColorValueSchema,\n\t\tsuccess: ColorValueSchema,\n\t\terror: ColorValueSchema,\n\t\twarning: ColorValueSchema,\n\t\tmuted: ColorValueSchema,\n\t\tdim: ColorValueSchema,\n\t\ttext: ColorValueSchema,\n\t\tthinkingText: ColorValueSchema,\n\t\t// Backgrounds & Content Text (11 colors)\n\t\tselectedBg: ColorValueSchema,\n\t\tuserMessageBg: ColorValueSchema,\n\t\tuserMessageText: ColorValueSchema,\n\t\tcustomMessageBg: ColorValueSchema,\n\t\tcustomMessageText: ColorValueSchema,\n\t\tcustomMessageLabel: ColorValueSchema,\n\t\ttoolPendingBg: ColorValueSchema,\n\t\ttoolSuccessBg: ColorValueSchema,\n\t\ttoolErrorBg: ColorValueSchema,\n\t\ttoolTitle: ColorValueSchema,\n\t\ttoolOutput: ColorValueSchema,\n\t\t// Markdown (10 colors)\n\t\tmdHeading: ColorValueSchema,\n\t\tmdLink: ColorValueSchema,\n\t\tmdLinkUrl: ColorValueSchema,\n\t\tmdCode: ColorValueSchema,\n\t\tmdCodeBlock: ColorValueSchema,\n\t\tmdCodeBlockBorder: ColorValueSchema,\n\t\tmdQuote: ColorValueSchema,\n\t\tmdQuoteBorder: ColorValueSchema,\n\t\tmdHr: ColorValueSchema,\n\t\tmdListBullet: ColorValueSchema,\n\t\t// Tool Diffs (3 colors)\n\t\ttoolDiffAdded: ColorValueSchema,\n\t\ttoolDiffRemoved: ColorValueSchema,\n\t\ttoolDiffContext: ColorValueSchema,\n\t\t// Syntax Highlighting (9 colors)\n\t\tsyntaxComment: ColorValueSchema,\n\t\tsyntaxKeyword: ColorValueSchema,\n\t\tsyntaxFunction: ColorValueSchema,\n\t\tsyntaxVariable: ColorValueSchema,\n\t\tsyntaxString: ColorValueSchema,\n\t\tsyntaxNumber: ColorValueSchema,\n\t\tsyntaxType: ColorValueSchema,\n\t\tsyntaxOperator: ColorValueSchema,\n\t\tsyntaxPunctuation: ColorValueSchema,\n\t\t// Thinking Level Borders (6 colors)\n\t\tthinkingOff: ColorValueSchema,\n\t\tthinkingMinimal: ColorValueSchema,\n\t\tthinkingLow: ColorValueSchema,\n\t\tthinkingMedium: ColorValueSchema,\n\t\tthinkingHigh: ColorValueSchema,\n\t\tthinkingXhigh: ColorValueSchema,\n\t\t// Bash Mode (1 color)\n\t\tbashMode: ColorValueSchema,\n\t}),\n\texport: Type.Optional(\n\t\tType.Object({\n\t\t\tpageBg: Type.Optional(ColorValueSchema),\n\t\t\tcardBg: Type.Optional(ColorValueSchema),\n\t\t\tinfoBg: Type.Optional(ColorValueSchema),\n\t\t}),\n\t),\n});\n\ntype ThemeJson = Static<typeof ThemeJsonSchema>;\n\nconst validateThemeJson = TypeCompiler.Compile(ThemeJsonSchema);\n\nexport type ThemeColor =\n\t| \"accent\"\n\t| \"border\"\n\t| \"borderAccent\"\n\t| \"borderMuted\"\n\t| \"success\"\n\t| \"error\"\n\t| \"warning\"\n\t| \"muted\"\n\t| \"dim\"\n\t| \"text\"\n\t| \"thinkingText\"\n\t| \"userMessageText\"\n\t| \"customMessageText\"\n\t| \"customMessageLabel\"\n\t| \"toolTitle\"\n\t| \"toolOutput\"\n\t| \"mdHeading\"\n\t| \"mdLink\"\n\t| \"mdLinkUrl\"\n\t| \"mdCode\"\n\t| \"mdCodeBlock\"\n\t| \"mdCodeBlockBorder\"\n\t| \"mdQuote\"\n\t| \"mdQuoteBorder\"\n\t| \"mdHr\"\n\t| \"mdListBullet\"\n\t| \"toolDiffAdded\"\n\t| \"toolDiffRemoved\"\n\t| \"toolDiffContext\"\n\t| \"syntaxComment\"\n\t| \"syntaxKeyword\"\n\t| \"syntaxFunction\"\n\t| \"syntaxVariable\"\n\t| \"syntaxString\"\n\t| \"syntaxNumber\"\n\t| \"syntaxType\"\n\t| \"syntaxOperator\"\n\t| \"syntaxPunctuation\"\n\t| \"thinkingOff\"\n\t| \"thinkingMinimal\"\n\t| \"thinkingLow\"\n\t| \"thinkingMedium\"\n\t| \"thinkingHigh\"\n\t| \"thinkingXhigh\"\n\t| \"bashMode\";\n\nexport type ThemeBg =\n\t| \"selectedBg\"\n\t| \"userMessageBg\"\n\t| \"customMessageBg\"\n\t| \"toolPendingBg\"\n\t| \"toolSuccessBg\"\n\t| \"toolErrorBg\";\n\ntype ColorMode = \"truecolor\" | \"256color\";\n\n// ============================================================================\n// Color Utilities\n// ============================================================================\n\nfunction detectColorMode(): ColorMode {\n\tconst colorterm = process.env.COLORTERM;\n\tif (colorterm === \"truecolor\" || colorterm === \"24bit\") {\n\t\treturn \"truecolor\";\n\t}\n\t// Windows Terminal supports truecolor\n\tif (process.env.WT_SESSION) {\n\t\treturn \"truecolor\";\n\t}\n\tconst term = process.env.TERM || \"\";\n\t// Only fall back to 256color for truly limited terminals\n\tif (term === \"dumb\" || term === \"\" || term === \"linux\") {\n\t\treturn \"256color\";\n\t}\n\t// Assume truecolor for everything else - virtually all modern terminals support it\n\treturn \"truecolor\";\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n\tconst cleaned = hex.replace(\"#\", \"\");\n\tif (cleaned.length !== 6) {\n\t\tthrow new Error(`Invalid hex color: ${hex}`);\n\t}\n\tconst r = parseInt(cleaned.substring(0, 2), 16);\n\tconst g = parseInt(cleaned.substring(2, 4), 16);\n\tconst b = parseInt(cleaned.substring(4, 6), 16);\n\tif (Number.isNaN(r) || Number.isNaN(g) || Number.isNaN(b)) {\n\t\tthrow new Error(`Invalid hex color: ${hex}`);\n\t}\n\treturn { r, g, b };\n}\n\n// The 6x6x6 color cube channel values (indices 0-5)\nconst CUBE_VALUES = [0, 95, 135, 175, 215, 255];\n\n// Grayscale ramp values (indices 232-255, 24 grays from 8 to 238)\nconst GRAY_VALUES = Array.from({ length: 24 }, (_, i) => 8 + i * 10);\n\nfunction findClosestCubeIndex(value: number): number {\n\tlet minDist = Infinity;\n\tlet minIdx = 0;\n\tfor (let i = 0; i < CUBE_VALUES.length; i++) {\n\t\tconst dist = Math.abs(value - CUBE_VALUES[i]);\n\t\tif (dist < minDist) {\n\t\t\tminDist = dist;\n\t\t\tminIdx = i;\n\t\t}\n\t}\n\treturn minIdx;\n}\n\nfunction findClosestGrayIndex(gray: number): number {\n\tlet minDist = Infinity;\n\tlet minIdx = 0;\n\tfor (let i = 0; i < GRAY_VALUES.length; i++) {\n\t\tconst dist = Math.abs(gray - GRAY_VALUES[i]);\n\t\tif (dist < minDist) {\n\t\t\tminDist = dist;\n\t\t\tminIdx = i;\n\t\t}\n\t}\n\treturn minIdx;\n}\n\nfunction colorDistance(r1: number, g1: number, b1: number, r2: number, g2: number, b2: number): number {\n\t// Weighted Euclidean distance (human eye is more sensitive to green)\n\tconst dr = r1 - r2;\n\tconst dg = g1 - g2;\n\tconst db = b1 - b2;\n\treturn dr * dr * 0.299 + dg * dg * 0.587 + db * db * 0.114;\n}\n\nfunction rgbTo256(r: number, g: number, b: number): number {\n\t// Find closest color in the 6x6x6 cube\n\tconst rIdx = findClosestCubeIndex(r);\n\tconst gIdx = findClosestCubeIndex(g);\n\tconst bIdx = findClosestCubeIndex(b);\n\tconst cubeR = CUBE_VALUES[rIdx];\n\tconst cubeG = CUBE_VALUES[gIdx];\n\tconst cubeB = CUBE_VALUES[bIdx];\n\tconst cubeIndex = 16 + 36 * rIdx + 6 * gIdx + bIdx;\n\tconst cubeDist = colorDistance(r, g, b, cubeR, cubeG, cubeB);\n\n\t// Find closest grayscale\n\tconst gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);\n\tconst grayIdx = findClosestGrayIndex(gray);\n\tconst grayValue = GRAY_VALUES[grayIdx];\n\tconst grayIndex = 232 + grayIdx;\n\tconst grayDist = colorDistance(r, g, b, grayValue, grayValue, grayValue);\n\n\t// Check if color has noticeable saturation (hue matters)\n\t// If max-min spread is significant, prefer cube to preserve tint\n\tconst maxC = Math.max(r, g, b);\n\tconst minC = Math.min(r, g, b);\n\tconst spread = maxC - minC;\n\n\t// Only consider grayscale if color is nearly neutral (spread < 10)\n\t// AND grayscale is actually closer\n\tif (spread < 10 && grayDist < cubeDist) {\n\t\treturn grayIndex;\n\t}\n\n\treturn cubeIndex;\n}\n\nfunction hexTo256(hex: string): number {\n\tconst { r, g, b } = hexToRgb(hex);\n\treturn rgbTo256(r, g, b);\n}\n\nfunction fgAnsi(color: string | number, mode: ColorMode): string {\n\tif (color === \"\") return \"\\x1b[39m\";\n\tif (typeof color === \"number\") return `\\x1b[38;5;${color}m`;\n\tif (color.startsWith(\"#\")) {\n\t\tif (mode === \"truecolor\") {\n\t\t\tconst { r, g, b } = hexToRgb(color);\n\t\t\treturn `\\x1b[38;2;${r};${g};${b}m`;\n\t\t} else {\n\t\t\tconst index = hexTo256(color);\n\t\t\treturn `\\x1b[38;5;${index}m`;\n\t\t}\n\t}\n\tthrow new Error(`Invalid color value: ${color}`);\n}\n\nfunction bgAnsi(color: string | number, mode: ColorMode): string {\n\tif (color === \"\") return \"\\x1b[49m\";\n\tif (typeof color === \"number\") return `\\x1b[48;5;${color}m`;\n\tif (color.startsWith(\"#\")) {\n\t\tif (mode === \"truecolor\") {\n\t\t\tconst { r, g, b } = hexToRgb(color);\n\t\t\treturn `\\x1b[48;2;${r};${g};${b}m`;\n\t\t} else {\n\t\t\tconst index = hexTo256(color);\n\t\t\treturn `\\x1b[48;5;${index}m`;\n\t\t}\n\t}\n\tthrow new Error(`Invalid color value: ${color}`);\n}\n\nfunction resolveVarRefs(\n\tvalue: ColorValue,\n\tvars: Record<string, ColorValue>,\n\tvisited = new Set<string>(),\n): string | number {\n\tif (typeof value === \"number\" || value === \"\" || value.startsWith(\"#\")) {\n\t\treturn value;\n\t}\n\tif (visited.has(value)) {\n\t\tthrow new Error(`Circular variable reference detected: ${value}`);\n\t}\n\tif (!(value in vars)) {\n\t\tthrow new Error(`Variable reference not found: ${value}`);\n\t}\n\tvisited.add(value);\n\treturn resolveVarRefs(vars[value], vars, visited);\n}\n\nfunction resolveThemeColors<T extends Record<string, ColorValue>>(\n\tcolors: T,\n\tvars: Record<string, ColorValue> = {},\n): Record<keyof T, string | number> {\n\tconst resolved: Record<string, string | number> = {};\n\tfor (const [key, value] of Object.entries(colors)) {\n\t\tresolved[key] = resolveVarRefs(value, vars);\n\t}\n\treturn resolved as Record<keyof T, string | number>;\n}\n\n// ============================================================================\n// Theme Class\n// ============================================================================\n\nexport class Theme {\n\tprivate fgColors: Map<ThemeColor, string>;\n\tprivate bgColors: Map<ThemeBg, string>;\n\tprivate mode: ColorMode;\n\n\tconstructor(\n\t\tfgColors: Record<ThemeColor, string | number>,\n\t\tbgColors: Record<ThemeBg, string | number>,\n\t\tmode: ColorMode,\n\t) {\n\t\tthis.mode = mode;\n\t\tthis.fgColors = new Map();\n\t\tfor (const [key, value] of Object.entries(fgColors) as [ThemeColor, string | number][]) {\n\t\t\tthis.fgColors.set(key, fgAnsi(value, mode));\n\t\t}\n\t\tthis.bgColors = new Map();\n\t\tfor (const [key, value] of Object.entries(bgColors) as [ThemeBg, string | number][]) {\n\t\t\tthis.bgColors.set(key, bgAnsi(value, mode));\n\t\t}\n\t}\n\n\tfg(color: ThemeColor, text: string): string {\n\t\tconst ansi = this.fgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme color: ${color}`);\n\t\treturn `${ansi}${text}\\x1b[39m`; // Reset only foreground color\n\t}\n\n\tbg(color: ThemeBg, text: string): string {\n\t\tconst ansi = this.bgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme background color: ${color}`);\n\t\treturn `${ansi}${text}\\x1b[49m`; // Reset only background color\n\t}\n\n\tbold(text: string): string {\n\t\treturn chalk.bold(text);\n\t}\n\n\titalic(text: string): string {\n\t\treturn chalk.italic(text);\n\t}\n\n\tunderline(text: string): string {\n\t\treturn chalk.underline(text);\n\t}\n\n\tinverse(text: string): string {\n\t\treturn chalk.inverse(text);\n\t}\n\n\tstrikethrough(text: string): string {\n\t\treturn chalk.strikethrough(text);\n\t}\n\n\tgetFgAnsi(color: ThemeColor): string {\n\t\tconst ansi = this.fgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme color: ${color}`);\n\t\treturn ansi;\n\t}\n\n\tgetBgAnsi(color: ThemeBg): string {\n\t\tconst ansi = this.bgColors.get(color);\n\t\tif (!ansi) throw new Error(`Unknown theme background color: ${color}`);\n\t\treturn ansi;\n\t}\n\n\tgetColorMode(): ColorMode {\n\t\treturn this.mode;\n\t}\n\n\tgetThinkingBorderColor(level: \"off\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\"): (str: string) => string {\n\t\t// Map thinking levels to dedicated theme colors\n\t\tswitch (level) {\n\t\t\tcase \"off\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingOff\", str);\n\t\t\tcase \"minimal\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingMinimal\", str);\n\t\t\tcase \"low\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingLow\", str);\n\t\t\tcase \"medium\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingMedium\", str);\n\t\t\tcase \"high\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingHigh\", str);\n\t\t\tcase \"xhigh\":\n\t\t\t\treturn (str: string) => this.fg(\"thinkingXhigh\", str);\n\t\t\tdefault:\n\t\t\t\treturn (str: string) => this.fg(\"thinkingOff\", str);\n\t\t}\n\t}\n\n\tgetBashModeBorderColor(): (str: string) => string {\n\t\treturn (str: string) => this.fg(\"bashMode\", str);\n\t}\n}\n\n// ============================================================================\n// Theme Loading\n// ============================================================================\n\nlet BUILTIN_THEMES: Record<string, ThemeJson> | undefined;\n\nfunction getBuiltinThemes(): Record<string, ThemeJson> {\n\tif (!BUILTIN_THEMES) {\n\t\tconst themesDir = getThemesDir();\n\t\tconst darkPath = path.join(themesDir, \"dark.json\");\n\t\tconst lightPath = path.join(themesDir, \"light.json\");\n\t\tBUILTIN_THEMES = {\n\t\t\tdark: JSON.parse(fs.readFileSync(darkPath, \"utf-8\")) as ThemeJson,\n\t\t\tlight: JSON.parse(fs.readFileSync(lightPath, \"utf-8\")) as ThemeJson,\n\t\t};\n\t}\n\treturn BUILTIN_THEMES;\n}\n\nexport function getAvailableThemes(): string[] {\n\tconst themes = new Set<string>(Object.keys(getBuiltinThemes()));\n\tconst customThemesDir = getCustomThemesDir();\n\tif (fs.existsSync(customThemesDir)) {\n\t\tconst files = fs.readdirSync(customThemesDir);\n\t\tfor (const file of files) {\n\t\t\tif (file.endsWith(\".json\")) {\n\t\t\t\tthemes.add(file.slice(0, -5));\n\t\t\t}\n\t\t}\n\t}\n\treturn Array.from(themes).sort();\n}\n\nexport interface ThemeInfo {\n\tname: string;\n\tpath: string | undefined;\n}\n\nexport function getAvailableThemesWithPaths(): ThemeInfo[] {\n\tconst themesDir = getThemesDir();\n\tconst customThemesDir = getCustomThemesDir();\n\tconst result: ThemeInfo[] = [];\n\n\t// Built-in themes\n\tfor (const name of Object.keys(getBuiltinThemes())) {\n\t\tresult.push({ name, path: path.join(themesDir, `${name}.json`) });\n\t}\n\n\t// Custom themes\n\tif (fs.existsSync(customThemesDir)) {\n\t\tfor (const file of fs.readdirSync(customThemesDir)) {\n\t\t\tif (file.endsWith(\".json\")) {\n\t\t\t\tconst name = file.slice(0, -5);\n\t\t\t\tif (!result.some((t) => t.name === name)) {\n\t\t\t\t\tresult.push({ name, path: path.join(customThemesDir, file) });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn result.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction loadThemeJson(name: string): ThemeJson {\n\tconst builtinThemes = getBuiltinThemes();\n\tif (name in builtinThemes) {\n\t\treturn builtinThemes[name];\n\t}\n\tconst customThemesDir = getCustomThemesDir();\n\tconst themePath = path.join(customThemesDir, `${name}.json`);\n\tif (!fs.existsSync(themePath)) {\n\t\tthrow new Error(`Theme not found: ${name}`);\n\t}\n\tconst content = fs.readFileSync(themePath, \"utf-8\");\n\tlet json: unknown;\n\ttry {\n\t\tjson = JSON.parse(content);\n\t} catch (error) {\n\t\tthrow new Error(`Failed to parse theme ${name}: ${error}`);\n\t}\n\tif (!validateThemeJson.Check(json)) {\n\t\tconst errors = Array.from(validateThemeJson.Errors(json));\n\t\tconst missingColors: string[] = [];\n\t\tconst otherErrors: string[] = [];\n\n\t\tfor (const e of errors) {\n\t\t\t// Check for missing required color properties\n\t\t\tconst match = e.path.match(/^\\/colors\\/(\\w+)$/);\n\t\t\tif (match && e.message.includes(\"Required\")) {\n\t\t\t\tmissingColors.push(match[1]);\n\t\t\t} else {\n\t\t\t\totherErrors.push(` - ${e.path}: ${e.message}`);\n\t\t\t}\n\t\t}\n\n\t\tlet errorMessage = `Invalid theme \"${name}\":\\n`;\n\t\tif (missingColors.length > 0) {\n\t\t\terrorMessage += `\\nMissing required color tokens:\\n`;\n\t\t\terrorMessage += missingColors.map((c) => ` - ${c}`).join(\"\\n\");\n\t\t\terrorMessage += `\\n\\nPlease add these colors to your theme's \"colors\" object.`;\n\t\t\terrorMessage += `\\nSee the built-in themes (dark.json, light.json) for reference values.`;\n\t\t}\n\t\tif (otherErrors.length > 0) {\n\t\t\terrorMessage += `\\n\\nOther errors:\\n${otherErrors.join(\"\\n\")}`;\n\t\t}\n\n\t\tthrow new Error(errorMessage);\n\t}\n\treturn json as ThemeJson;\n}\n\nfunction createTheme(themeJson: ThemeJson, mode?: ColorMode): Theme {\n\tconst colorMode = mode ?? detectColorMode();\n\tconst resolvedColors = resolveThemeColors(themeJson.colors, themeJson.vars);\n\tconst fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;\n\tconst bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;\n\tconst bgColorKeys: Set<string> = new Set([\n\t\t\"selectedBg\",\n\t\t\"userMessageBg\",\n\t\t\"customMessageBg\",\n\t\t\"toolPendingBg\",\n\t\t\"toolSuccessBg\",\n\t\t\"toolErrorBg\",\n\t]);\n\tfor (const [key, value] of Object.entries(resolvedColors)) {\n\t\tif (bgColorKeys.has(key)) {\n\t\t\tbgColors[key as ThemeBg] = value;\n\t\t} else {\n\t\t\tfgColors[key as ThemeColor] = value;\n\t\t}\n\t}\n\treturn new Theme(fgColors, bgColors, colorMode);\n}\n\nfunction loadTheme(name: string, mode?: ColorMode): Theme {\n\tconst themeJson = loadThemeJson(name);\n\treturn createTheme(themeJson, mode);\n}\n\nexport function getThemeByName(name: string): Theme | undefined {\n\ttry {\n\t\treturn loadTheme(name);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction detectTerminalBackground(): \"dark\" | \"light\" {\n\tconst colorfgbg = process.env.COLORFGBG || \"\";\n\tif (colorfgbg) {\n\t\tconst parts = colorfgbg.split(\";\");\n\t\tif (parts.length >= 2) {\n\t\t\tconst bg = parseInt(parts[1], 10);\n\t\t\tif (!Number.isNaN(bg)) {\n\t\t\t\tconst result = bg < 8 ? \"dark\" : \"light\";\n\t\t\t\treturn result;\n\t\t\t}\n\t\t}\n\t}\n\treturn \"dark\";\n}\n\nfunction getDefaultTheme(): string {\n\treturn detectTerminalBackground();\n}\n\n// ============================================================================\n// Global Theme Instance\n// ============================================================================\n\nexport let theme: Theme;\nlet currentThemeName: string | undefined;\nlet themeWatcher: fs.FSWatcher | undefined;\nlet onThemeChangeCallback: (() => void) | undefined;\n\nexport function initTheme(themeName?: string, enableWatcher: boolean = false): void {\n\tconst name = themeName ?? getDefaultTheme();\n\tcurrentThemeName = name;\n\ttry {\n\t\ttheme = loadTheme(name);\n\t\tif (enableWatcher) {\n\t\t\tstartThemeWatcher();\n\t\t}\n\t} catch (_error) {\n\t\t// Theme is invalid - fall back to dark theme silently\n\t\tcurrentThemeName = \"dark\";\n\t\ttheme = loadTheme(\"dark\");\n\t\t// Don't start watcher for fallback theme\n\t}\n}\n\nexport function setTheme(name: string, enableWatcher: boolean = false): { success: boolean; error?: string } {\n\tcurrentThemeName = name;\n\ttry {\n\t\ttheme = loadTheme(name);\n\t\tif (enableWatcher) {\n\t\t\tstartThemeWatcher();\n\t\t}\n\t\tif (onThemeChangeCallback) {\n\t\t\tonThemeChangeCallback();\n\t\t}\n\t\treturn { success: true };\n\t} catch (error) {\n\t\t// Theme is invalid - fall back to dark theme\n\t\tcurrentThemeName = \"dark\";\n\t\ttheme = loadTheme(\"dark\");\n\t\t// Don't start watcher for fallback theme\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t};\n\t}\n}\n\nexport function setThemeInstance(themeInstance: Theme): void {\n\ttheme = themeInstance;\n\tcurrentThemeName = \"<in-memory>\";\n\tstopThemeWatcher(); // Can't watch a direct instance\n\tif (onThemeChangeCallback) {\n\t\tonThemeChangeCallback();\n\t}\n}\n\nexport function onThemeChange(callback: () => void): void {\n\tonThemeChangeCallback = callback;\n}\n\nfunction startThemeWatcher(): void {\n\t// Stop existing watcher if any\n\tif (themeWatcher) {\n\t\tthemeWatcher.close();\n\t\tthemeWatcher = undefined;\n\t}\n\n\t// Only watch if it's a custom theme (not built-in)\n\tif (!currentThemeName || currentThemeName === \"dark\" || currentThemeName === \"light\") {\n\t\treturn;\n\t}\n\n\tconst customThemesDir = getCustomThemesDir();\n\tconst themeFile = path.join(customThemesDir, `${currentThemeName}.json`);\n\n\t// Only watch if the file exists\n\tif (!fs.existsSync(themeFile)) {\n\t\treturn;\n\t}\n\n\ttry {\n\t\tthemeWatcher = fs.watch(themeFile, (eventType) => {\n\t\t\tif (eventType === \"change\") {\n\t\t\t\t// Debounce rapid changes\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Reload the theme\n\t\t\t\t\t\ttheme = loadTheme(currentThemeName!);\n\t\t\t\t\t\t// Notify callback (to invalidate UI)\n\t\t\t\t\t\tif (onThemeChangeCallback) {\n\t\t\t\t\t\t\tonThemeChangeCallback();\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (_error) {\n\t\t\t\t\t\t// Ignore errors (file might be in invalid state while being edited)\n\t\t\t\t\t}\n\t\t\t\t}, 100);\n\t\t\t} else if (eventType === \"rename\") {\n\t\t\t\t// File was deleted or renamed - fall back to default theme\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!fs.existsSync(themeFile)) {\n\t\t\t\t\t\tcurrentThemeName = \"dark\";\n\t\t\t\t\t\ttheme = loadTheme(\"dark\");\n\t\t\t\t\t\tif (themeWatcher) {\n\t\t\t\t\t\t\tthemeWatcher.close();\n\t\t\t\t\t\t\tthemeWatcher = undefined;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (onThemeChangeCallback) {\n\t\t\t\t\t\t\tonThemeChangeCallback();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}, 100);\n\t\t\t}\n\t\t});\n\t} catch (_error) {\n\t\t// Ignore errors starting watcher\n\t}\n}\n\nexport function stopThemeWatcher(): void {\n\tif (themeWatcher) {\n\t\tthemeWatcher.close();\n\t\tthemeWatcher = undefined;\n\t}\n}\n\n// ============================================================================\n// HTML Export Helpers\n// ============================================================================\n\n/**\n * Convert a 256-color index to hex string.\n * Indices 0-15: basic colors (approximate)\n * Indices 16-231: 6x6x6 color cube\n * Indices 232-255: grayscale ramp\n */\nfunction ansi256ToHex(index: number): string {\n\t// Basic colors (0-15) - approximate common terminal values\n\tconst basicColors = [\n\t\t\"#000000\",\n\t\t\"#800000\",\n\t\t\"#008000\",\n\t\t\"#808000\",\n\t\t\"#000080\",\n\t\t\"#800080\",\n\t\t\"#008080\",\n\t\t\"#c0c0c0\",\n\t\t\"#808080\",\n\t\t\"#ff0000\",\n\t\t\"#00ff00\",\n\t\t\"#ffff00\",\n\t\t\"#0000ff\",\n\t\t\"#ff00ff\",\n\t\t\"#00ffff\",\n\t\t\"#ffffff\",\n\t];\n\tif (index < 16) {\n\t\treturn basicColors[index];\n\t}\n\n\t// Color cube (16-231): 6x6x6 = 216 colors\n\tif (index < 232) {\n\t\tconst cubeIndex = index - 16;\n\t\tconst r = Math.floor(cubeIndex / 36);\n\t\tconst g = Math.floor((cubeIndex % 36) / 6);\n\t\tconst b = cubeIndex % 6;\n\t\tconst toHex = (n: number) => (n === 0 ? 0 : 55 + n * 40).toString(16).padStart(2, \"0\");\n\t\treturn `#${toHex(r)}${toHex(g)}${toHex(b)}`;\n\t}\n\n\t// Grayscale (232-255): 24 shades\n\tconst gray = 8 + (index - 232) * 10;\n\tconst grayHex = gray.toString(16).padStart(2, \"0\");\n\treturn `#${grayHex}${grayHex}${grayHex}`;\n}\n\n/**\n * Get resolved theme colors as CSS-compatible hex strings.\n * Used by HTML export to generate CSS custom properties.\n */\nexport function getResolvedThemeColors(themeName?: string): Record<string, string> {\n\tconst name = themeName ?? getDefaultTheme();\n\tconst isLight = name === \"light\";\n\tconst themeJson = loadThemeJson(name);\n\tconst resolved = resolveThemeColors(themeJson.colors, themeJson.vars);\n\n\t// Default text color for empty values (terminal uses default fg color)\n\tconst defaultText = isLight ? \"#000000\" : \"#e5e5e7\";\n\n\tconst cssColors: Record<string, string> = {};\n\tfor (const [key, value] of Object.entries(resolved)) {\n\t\tif (typeof value === \"number\") {\n\t\t\tcssColors[key] = ansi256ToHex(value);\n\t\t} else if (value === \"\") {\n\t\t\t// Empty means default terminal color - use sensible fallback for HTML\n\t\t\tcssColors[key] = defaultText;\n\t\t} else {\n\t\t\tcssColors[key] = value;\n\t\t}\n\t}\n\treturn cssColors;\n}\n\n/**\n * Check if a theme is a \"light\" theme (for CSS that needs light/dark variants).\n */\nexport function isLightTheme(themeName?: string): boolean {\n\t// Currently just check the name - could be extended to analyze colors\n\treturn themeName === \"light\";\n}\n\n/**\n * Get explicit export colors from theme JSON, if specified.\n * Returns undefined for each color that isn't explicitly set.\n */\nexport function getThemeExportColors(themeName?: string): {\n\tpageBg?: string;\n\tcardBg?: string;\n\tinfoBg?: string;\n} {\n\tconst name = themeName ?? getDefaultTheme();\n\ttry {\n\t\tconst themeJson = loadThemeJson(name);\n\t\tconst exportSection = themeJson.export;\n\t\tif (!exportSection) return {};\n\n\t\tconst vars = themeJson.vars ?? {};\n\t\tconst resolve = (value: string | number | undefined): string | undefined => {\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (typeof value === \"number\") return ansi256ToHex(value);\n\t\t\tif (value.startsWith(\"$\")) {\n\t\t\t\tconst resolved = vars[value];\n\t\t\t\tif (resolved === undefined) return undefined;\n\t\t\t\tif (typeof resolved === \"number\") return ansi256ToHex(resolved);\n\t\t\t\treturn resolved;\n\t\t\t}\n\t\t\treturn value;\n\t\t};\n\n\t\treturn {\n\t\t\tpageBg: resolve(exportSection.pageBg),\n\t\t\tcardBg: resolve(exportSection.cardBg),\n\t\t\tinfoBg: resolve(exportSection.infoBg),\n\t\t};\n\t} catch {\n\t\treturn {};\n\t}\n}\n\n// ============================================================================\n// TUI Helpers\n// ============================================================================\n\ntype CliHighlightTheme = Record<string, (s: string) => string>;\n\nlet cachedHighlightThemeFor: Theme | undefined;\nlet cachedCliHighlightTheme: CliHighlightTheme | undefined;\n\nfunction buildCliHighlightTheme(t: Theme): CliHighlightTheme {\n\treturn {\n\t\tkeyword: (s: string) => t.fg(\"syntaxKeyword\", s),\n\t\tbuilt_in: (s: string) => t.fg(\"syntaxType\", s),\n\t\tliteral: (s: string) => t.fg(\"syntaxNumber\", s),\n\t\tnumber: (s: string) => t.fg(\"syntaxNumber\", s),\n\t\tstring: (s: string) => t.fg(\"syntaxString\", s),\n\t\tcomment: (s: string) => t.fg(\"syntaxComment\", s),\n\t\tfunction: (s: string) => t.fg(\"syntaxFunction\", s),\n\t\ttitle: (s: string) => t.fg(\"syntaxFunction\", s),\n\t\tclass: (s: string) => t.fg(\"syntaxType\", s),\n\t\ttype: (s: string) => t.fg(\"syntaxType\", s),\n\t\tattr: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\tvariable: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\tparams: (s: string) => t.fg(\"syntaxVariable\", s),\n\t\toperator: (s: string) => t.fg(\"syntaxOperator\", s),\n\t\tpunctuation: (s: string) => t.fg(\"syntaxPunctuation\", s),\n\t};\n}\n\nfunction getCliHighlightTheme(t: Theme): CliHighlightTheme {\n\tif (cachedHighlightThemeFor !== t || !cachedCliHighlightTheme) {\n\t\tcachedHighlightThemeFor = t;\n\t\tcachedCliHighlightTheme = buildCliHighlightTheme(t);\n\t}\n\treturn cachedCliHighlightTheme;\n}\n\n/**\n * Highlight code with syntax coloring based on file extension or language.\n * Returns array of highlighted lines.\n */\nexport function highlightCode(code: string, lang?: string): string[] {\n\t// Validate language before highlighting to avoid stderr spam from cli-highlight\n\tconst validLang = lang && supportsLanguage(lang) ? lang : undefined;\n\tconst opts = {\n\t\tlanguage: validLang,\n\t\tignoreIllegals: true,\n\t\ttheme: getCliHighlightTheme(theme),\n\t};\n\ttry {\n\t\treturn highlight(code, opts).split(\"\\n\");\n\t} catch {\n\t\treturn code.split(\"\\n\");\n\t}\n}\n\n/**\n * Get language identifier from file path extension.\n */\nexport function getLanguageFromPath(filePath: string): string | undefined {\n\tconst ext = filePath.split(\".\").pop()?.toLowerCase();\n\tif (!ext) return undefined;\n\n\tconst extToLang: Record<string, string> = {\n\t\tts: \"typescript\",\n\t\ttsx: \"typescript\",\n\t\tjs: \"javascript\",\n\t\tjsx: \"javascript\",\n\t\tmjs: \"javascript\",\n\t\tcjs: \"javascript\",\n\t\tpy: \"python\",\n\t\trb: \"ruby\",\n\t\trs: \"rust\",\n\t\tgo: \"go\",\n\t\tjava: \"java\",\n\t\tkt: \"kotlin\",\n\t\tswift: \"swift\",\n\t\tc: \"c\",\n\t\th: \"c\",\n\t\tcpp: \"cpp\",\n\t\tcc: \"cpp\",\n\t\tcxx: \"cpp\",\n\t\thpp: \"cpp\",\n\t\tcs: \"csharp\",\n\t\tphp: \"php\",\n\t\tsh: \"bash\",\n\t\tbash: \"bash\",\n\t\tzsh: \"bash\",\n\t\tfish: \"fish\",\n\t\tps1: \"powershell\",\n\t\tsql: \"sql\",\n\t\thtml: \"html\",\n\t\thtm: \"html\",\n\t\tcss: \"css\",\n\t\tscss: \"scss\",\n\t\tsass: \"sass\",\n\t\tless: \"less\",\n\t\tjson: \"json\",\n\t\tyaml: \"yaml\",\n\t\tyml: \"yaml\",\n\t\ttoml: \"toml\",\n\t\txml: \"xml\",\n\t\tmd: \"markdown\",\n\t\tmarkdown: \"markdown\",\n\t\tdockerfile: \"dockerfile\",\n\t\tmakefile: \"makefile\",\n\t\tcmake: \"cmake\",\n\t\tlua: \"lua\",\n\t\tperl: \"perl\",\n\t\tr: \"r\",\n\t\tscala: \"scala\",\n\t\tclj: \"clojure\",\n\t\tex: \"elixir\",\n\t\texs: \"elixir\",\n\t\terl: \"erlang\",\n\t\ths: \"haskell\",\n\t\tml: \"ocaml\",\n\t\tvim: \"vim\",\n\t\tgraphql: \"graphql\",\n\t\tproto: \"protobuf\",\n\t\ttf: \"hcl\",\n\t\thcl: \"hcl\",\n\t};\n\n\treturn extToLang[ext];\n}\n\nexport function getMarkdownTheme(): MarkdownTheme {\n\treturn {\n\t\theading: (text: string) => theme.fg(\"mdHeading\", text),\n\t\tlink: (text: string) => theme.fg(\"mdLink\", text),\n\t\tlinkUrl: (text: string) => theme.fg(\"mdLinkUrl\", text),\n\t\tcode: (text: string) => theme.fg(\"mdCode\", text),\n\t\tcodeBlock: (text: string) => theme.fg(\"mdCodeBlock\", text),\n\t\tcodeBlockBorder: (text: string) => theme.fg(\"mdCodeBlockBorder\", text),\n\t\tquote: (text: string) => theme.fg(\"mdQuote\", text),\n\t\tquoteBorder: (text: string) => theme.fg(\"mdQuoteBorder\", text),\n\t\thr: (text: string) => theme.fg(\"mdHr\", text),\n\t\tlistBullet: (text: string) => theme.fg(\"mdListBullet\", text),\n\t\tbold: (text: string) => theme.bold(text),\n\t\titalic: (text: string) => theme.italic(text),\n\t\tunderline: (text: string) => theme.underline(text),\n\t\tstrikethrough: (text: string) => chalk.strikethrough(text),\n\t\thighlightCode: (code: string, lang?: string): string[] => {\n\t\t\t// Validate language before highlighting to avoid stderr spam from cli-highlight\n\t\t\tconst validLang = lang && supportsLanguage(lang) ? lang : undefined;\n\t\t\tconst opts = {\n\t\t\t\tlanguage: validLang,\n\t\t\t\tignoreIllegals: true,\n\t\t\t\ttheme: getCliHighlightTheme(theme),\n\t\t\t};\n\t\t\ttry {\n\t\t\t\treturn highlight(code, opts).split(\"\\n\");\n\t\t\t} catch {\n\t\t\t\treturn code.split(\"\\n\").map((line) => theme.fg(\"mdCodeBlock\", line));\n\t\t\t}\n\t\t},\n\t};\n}\n\nexport function getSelectListTheme(): SelectListTheme {\n\treturn {\n\t\tselectedPrefix: (text: string) => theme.fg(\"accent\", text),\n\t\tselectedText: (text: string) => theme.fg(\"accent\", text),\n\t\tdescription: (text: string) => theme.fg(\"muted\", text),\n\t\tscrollInfo: (text: string) => theme.fg(\"muted\", text),\n\t\tnoMatch: (text: string) => theme.fg(\"muted\", text),\n\t};\n}\n\nexport function getEditorTheme(): EditorTheme {\n\treturn {\n\t\tborderColor: (text: string) => theme.fg(\"borderMuted\", text),\n\t\tselectList: getSelectListTheme(),\n\t};\n}\n\nexport function getSettingsListTheme(): import(\"@mariozechner/pi-tui\").SettingsListTheme {\n\treturn {\n\t\tlabel: (text: string, selected: boolean) => (selected ? theme.fg(\"accent\", text) : text),\n\t\tvalue: (text: string, selected: boolean) => (selected ? theme.fg(\"accent\", text) : theme.fg(\"muted\", text)),\n\t\tdescription: (text: string) => theme.fg(\"dim\", text),\n\t\tcursor: theme.fg(\"accent\", \"→ \"),\n\t\thint: (text: string) => theme.fg(\"dim\", text),\n\t};\n}\n"]}
@@ -498,6 +498,9 @@ export function setTheme(name, enableWatcher = false) {
498
498
  if (enableWatcher) {
499
499
  startThemeWatcher();
500
500
  }
501
+ if (onThemeChangeCallback) {
502
+ onThemeChangeCallback();
503
+ }
501
504
  return { success: true };
502
505
  }
503
506
  catch (error) {
@@ -515,6 +518,9 @@ export function setThemeInstance(themeInstance) {
515
518
  theme = themeInstance;
516
519
  currentThemeName = "<in-memory>";
517
520
  stopThemeWatcher(); // Can't watch a direct instance
521
+ if (onThemeChangeCallback) {
522
+ onThemeChangeCallback();
523
+ }
518
524
  }
519
525
  export function onThemeChange(callback) {
520
526
  onThemeChangeCallback = callback;