mirror of
https://github.com/harivansh-afk/clanker-agent.git
synced 2026-04-16 22:03:48 +00:00
pull into local
This commit is contained in:
parent
dd0c89d8aa
commit
d0f85b30cc
50 changed files with 26814 additions and 86 deletions
22
packages/coding-agent/companion-out/export-html/ansi-to-html.d.ts
vendored
Normal file
22
packages/coding-agent/companion-out/export-html/ansi-to-html.d.ts
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* ANSI escape code to HTML converter.
|
||||
*
|
||||
* Converts terminal ANSI color/style codes to HTML with inline styles.
|
||||
* Supports:
|
||||
* - Standard foreground colors (30-37) and bright variants (90-97)
|
||||
* - Standard background colors (40-47) and bright variants (100-107)
|
||||
* - 256-color palette (38;5;N and 48;5;N)
|
||||
* - RGB true color (38;2;R;G;B and 48;2;R;G;B)
|
||||
* - Text styles: bold (1), dim (2), italic (3), underline (4)
|
||||
* - Reset (0)
|
||||
*/
|
||||
/**
|
||||
* Convert ANSI-escaped text to HTML with inline styles.
|
||||
*/
|
||||
export declare function ansiToHtml(text: string): string;
|
||||
/**
|
||||
* Convert array of ANSI-escaped lines to HTML.
|
||||
* Each line is wrapped in a div element.
|
||||
*/
|
||||
export declare function ansiLinesToHtml(lines: string[]): string;
|
||||
//# sourceMappingURL=ansi-to-html.d.ts.map
|
||||
File diff suppressed because one or more lines are too long
239
packages/coding-agent/companion-out/export-html/ansi-to-html.js
Normal file
239
packages/coding-agent/companion-out/export-html/ansi-to-html.js
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/**
|
||||
* ANSI escape code to HTML converter.
|
||||
*
|
||||
* Converts terminal ANSI color/style codes to HTML with inline styles.
|
||||
* Supports:
|
||||
* - Standard foreground colors (30-37) and bright variants (90-97)
|
||||
* - Standard background colors (40-47) and bright variants (100-107)
|
||||
* - 256-color palette (38;5;N and 48;5;N)
|
||||
* - RGB true color (38;2;R;G;B and 48;2;R;G;B)
|
||||
* - Text styles: bold (1), dim (2), italic (3), underline (4)
|
||||
* - Reset (0)
|
||||
*/
|
||||
// Standard ANSI color palette (0-15)
|
||||
const ANSI_COLORS = [
|
||||
"#000000", // 0: black
|
||||
"#800000", // 1: red
|
||||
"#008000", // 2: green
|
||||
"#808000", // 3: yellow
|
||||
"#000080", // 4: blue
|
||||
"#800080", // 5: magenta
|
||||
"#008080", // 6: cyan
|
||||
"#c0c0c0", // 7: white
|
||||
"#808080", // 8: bright black
|
||||
"#ff0000", // 9: bright red
|
||||
"#00ff00", // 10: bright green
|
||||
"#ffff00", // 11: bright yellow
|
||||
"#0000ff", // 12: bright blue
|
||||
"#ff00ff", // 13: bright magenta
|
||||
"#00ffff", // 14: bright cyan
|
||||
"#ffffff", // 15: bright white
|
||||
];
|
||||
/**
|
||||
* Convert 256-color index to hex.
|
||||
*/
|
||||
function color256ToHex(index) {
|
||||
// Standard colors (0-15)
|
||||
if (index < 16) {
|
||||
return ANSI_COLORS[index];
|
||||
}
|
||||
// Color cube (16-231): 6x6x6 = 216 colors
|
||||
if (index < 232) {
|
||||
const cubeIndex = index - 16;
|
||||
const r = Math.floor(cubeIndex / 36);
|
||||
const g = Math.floor((cubeIndex % 36) / 6);
|
||||
const b = cubeIndex % 6;
|
||||
const toComponent = (n) => (n === 0 ? 0 : 55 + n * 40);
|
||||
const toHex = (n) => toComponent(n).toString(16).padStart(2, "0");
|
||||
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
||||
}
|
||||
// Grayscale (232-255): 24 shades
|
||||
const gray = 8 + (index - 232) * 10;
|
||||
const grayHex = gray.toString(16).padStart(2, "0");
|
||||
return `#${grayHex}${grayHex}${grayHex}`;
|
||||
}
|
||||
/**
|
||||
* Escape HTML special characters.
|
||||
*/
|
||||
function escapeHtml(text) {
|
||||
return text
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
}
|
||||
function createEmptyStyle() {
|
||||
return {
|
||||
fg: null,
|
||||
bg: null,
|
||||
bold: false,
|
||||
dim: false,
|
||||
italic: false,
|
||||
underline: false,
|
||||
};
|
||||
}
|
||||
function styleToInlineCSS(style) {
|
||||
const parts = [];
|
||||
if (style.fg) parts.push(`color:${style.fg}`);
|
||||
if (style.bg) parts.push(`background-color:${style.bg}`);
|
||||
if (style.bold) parts.push("font-weight:bold");
|
||||
if (style.dim) parts.push("opacity:0.6");
|
||||
if (style.italic) parts.push("font-style:italic");
|
||||
if (style.underline) parts.push("text-decoration:underline");
|
||||
return parts.join(";");
|
||||
}
|
||||
function hasStyle(style) {
|
||||
return (
|
||||
style.fg !== null ||
|
||||
style.bg !== null ||
|
||||
style.bold ||
|
||||
style.dim ||
|
||||
style.italic ||
|
||||
style.underline
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Parse ANSI SGR (Select Graphic Rendition) codes and update style.
|
||||
*/
|
||||
function applySgrCode(params, style) {
|
||||
let i = 0;
|
||||
while (i < params.length) {
|
||||
const code = params[i];
|
||||
if (code === 0) {
|
||||
// Reset all
|
||||
style.fg = null;
|
||||
style.bg = null;
|
||||
style.bold = false;
|
||||
style.dim = false;
|
||||
style.italic = false;
|
||||
style.underline = false;
|
||||
} else if (code === 1) {
|
||||
style.bold = true;
|
||||
} else if (code === 2) {
|
||||
style.dim = true;
|
||||
} else if (code === 3) {
|
||||
style.italic = true;
|
||||
} else if (code === 4) {
|
||||
style.underline = true;
|
||||
} else if (code === 22) {
|
||||
// Reset bold/dim
|
||||
style.bold = false;
|
||||
style.dim = false;
|
||||
} else if (code === 23) {
|
||||
style.italic = false;
|
||||
} else if (code === 24) {
|
||||
style.underline = false;
|
||||
} else if (code >= 30 && code <= 37) {
|
||||
// Standard foreground colors
|
||||
style.fg = ANSI_COLORS[code - 30];
|
||||
} else if (code === 38) {
|
||||
// Extended foreground color
|
||||
if (params[i + 1] === 5 && params.length > i + 2) {
|
||||
// 256-color: 38;5;N
|
||||
style.fg = color256ToHex(params[i + 2]);
|
||||
i += 2;
|
||||
} else if (params[i + 1] === 2 && params.length > i + 4) {
|
||||
// RGB: 38;2;R;G;B
|
||||
const r = params[i + 2];
|
||||
const g = params[i + 3];
|
||||
const b = params[i + 4];
|
||||
style.fg = `rgb(${r},${g},${b})`;
|
||||
i += 4;
|
||||
}
|
||||
} else if (code === 39) {
|
||||
// Default foreground
|
||||
style.fg = null;
|
||||
} else if (code >= 40 && code <= 47) {
|
||||
// Standard background colors
|
||||
style.bg = ANSI_COLORS[code - 40];
|
||||
} else if (code === 48) {
|
||||
// Extended background color
|
||||
if (params[i + 1] === 5 && params.length > i + 2) {
|
||||
// 256-color: 48;5;N
|
||||
style.bg = color256ToHex(params[i + 2]);
|
||||
i += 2;
|
||||
} else if (params[i + 1] === 2 && params.length > i + 4) {
|
||||
// RGB: 48;2;R;G;B
|
||||
const r = params[i + 2];
|
||||
const g = params[i + 3];
|
||||
const b = params[i + 4];
|
||||
style.bg = `rgb(${r},${g},${b})`;
|
||||
i += 4;
|
||||
}
|
||||
} else if (code === 49) {
|
||||
// Default background
|
||||
style.bg = null;
|
||||
} else if (code >= 90 && code <= 97) {
|
||||
// Bright foreground colors
|
||||
style.fg = ANSI_COLORS[code - 90 + 8];
|
||||
} else if (code >= 100 && code <= 107) {
|
||||
// Bright background colors
|
||||
style.bg = ANSI_COLORS[code - 100 + 8];
|
||||
}
|
||||
// Ignore unrecognized codes
|
||||
i++;
|
||||
}
|
||||
}
|
||||
// Match ANSI escape sequences: ESC[ followed by params and ending with 'm'
|
||||
const ANSI_REGEX = /\x1b\[([\d;]*)m/g;
|
||||
/**
|
||||
* Convert ANSI-escaped text to HTML with inline styles.
|
||||
*/
|
||||
export function ansiToHtml(text) {
|
||||
const style = createEmptyStyle();
|
||||
let result = "";
|
||||
let lastIndex = 0;
|
||||
let inSpan = false;
|
||||
// Reset regex state
|
||||
ANSI_REGEX.lastIndex = 0;
|
||||
let match = ANSI_REGEX.exec(text);
|
||||
while (match !== null) {
|
||||
// Add text before this escape sequence
|
||||
const beforeText = text.slice(lastIndex, match.index);
|
||||
if (beforeText) {
|
||||
result += escapeHtml(beforeText);
|
||||
}
|
||||
// Parse SGR parameters
|
||||
const paramStr = match[1];
|
||||
const params = paramStr
|
||||
? paramStr.split(";").map((p) => parseInt(p, 10) || 0)
|
||||
: [0];
|
||||
// Close existing span if we have one
|
||||
if (inSpan) {
|
||||
result += "</span>";
|
||||
inSpan = false;
|
||||
}
|
||||
// Apply the codes
|
||||
applySgrCode(params, style);
|
||||
// Open new span if we have any styling
|
||||
if (hasStyle(style)) {
|
||||
result += `<span style="${styleToInlineCSS(style)}">`;
|
||||
inSpan = true;
|
||||
}
|
||||
lastIndex = match.index + match[0].length;
|
||||
match = ANSI_REGEX.exec(text);
|
||||
}
|
||||
// Add remaining text
|
||||
const remainingText = text.slice(lastIndex);
|
||||
if (remainingText) {
|
||||
result += escapeHtml(remainingText);
|
||||
}
|
||||
// Close any open span
|
||||
if (inSpan) {
|
||||
result += "</span>";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Convert array of ANSI-escaped lines to HTML.
|
||||
* Each line is wrapped in a div element.
|
||||
*/
|
||||
export function ansiLinesToHtml(lines) {
|
||||
return lines
|
||||
.map(
|
||||
(line) => `<div class="ansi-line">${ansiToHtml(line) || " "}</div>`,
|
||||
)
|
||||
.join("\n");
|
||||
}
|
||||
//# sourceMappingURL=ansi-to-html.js.map
|
||||
File diff suppressed because one or more lines are too long
46
packages/coding-agent/companion-out/export-html/index.d.ts
vendored
Normal file
46
packages/coding-agent/companion-out/export-html/index.d.ts
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import type { AgentState } from "@mariozechner/companion-agent-core";
|
||||
import { SessionManager } from "../session-manager.js";
|
||||
/**
|
||||
* Interface for rendering custom tools to HTML.
|
||||
* Used by agent-session to pre-render extension tool output.
|
||||
*/
|
||||
export interface ToolHtmlRenderer {
|
||||
/** Render a tool call to HTML. Returns undefined if tool has no custom renderer. */
|
||||
renderCall(toolName: string, args: unknown): string | undefined;
|
||||
/** Render a tool result to HTML. Returns undefined if tool has no custom renderer. */
|
||||
renderResult(
|
||||
toolName: string,
|
||||
result: Array<{
|
||||
type: string;
|
||||
text?: string;
|
||||
data?: string;
|
||||
mimeType?: string;
|
||||
}>,
|
||||
details: unknown,
|
||||
isError: boolean,
|
||||
): string | undefined;
|
||||
}
|
||||
export interface ExportOptions {
|
||||
outputPath?: string;
|
||||
themeName?: string;
|
||||
/** Optional tool renderer for custom tools */
|
||||
toolRenderer?: ToolHtmlRenderer;
|
||||
}
|
||||
/**
|
||||
* Export session to HTML using SessionManager and AgentState.
|
||||
* Used by TUI's /export command.
|
||||
*/
|
||||
export declare function exportSessionToHtml(
|
||||
sm: SessionManager,
|
||||
state?: AgentState,
|
||||
options?: ExportOptions | string,
|
||||
): Promise<string>;
|
||||
/**
|
||||
* Export session file to HTML (standalone, without AgentState).
|
||||
* Used by CLI for exporting arbitrary session files.
|
||||
*/
|
||||
export declare function exportFromFile(
|
||||
inputPath: string,
|
||||
options?: ExportOptions | string,
|
||||
): Promise<string>;
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
File diff suppressed because one or more lines are too long
254
packages/coding-agent/companion-out/export-html/index.js
Normal file
254
packages/coding-agent/companion-out/export-html/index.js
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import { basename, join } from "path";
|
||||
import { APP_NAME, getExportTemplateDir } from "../../config.js";
|
||||
import {
|
||||
getResolvedThemeColors,
|
||||
getThemeExportColors,
|
||||
} from "../../modes/interactive/theme/theme.js";
|
||||
import { SessionManager } from "../session-manager.js";
|
||||
/** Parse a color string to RGB values. Supports hex (#RRGGBB) and rgb(r,g,b) formats. */
|
||||
function parseColor(color) {
|
||||
const hexMatch = color.match(
|
||||
/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
|
||||
);
|
||||
if (hexMatch) {
|
||||
return {
|
||||
r: Number.parseInt(hexMatch[1], 16),
|
||||
g: Number.parseInt(hexMatch[2], 16),
|
||||
b: Number.parseInt(hexMatch[3], 16),
|
||||
};
|
||||
}
|
||||
const rgbMatch = color.match(
|
||||
/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/,
|
||||
);
|
||||
if (rgbMatch) {
|
||||
return {
|
||||
r: Number.parseInt(rgbMatch[1], 10),
|
||||
g: Number.parseInt(rgbMatch[2], 10),
|
||||
b: Number.parseInt(rgbMatch[3], 10),
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/** Calculate relative luminance of a color (0-1, higher = lighter). */
|
||||
function getLuminance(r, g, b) {
|
||||
const toLinear = (c) => {
|
||||
const s = c / 255;
|
||||
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
||||
};
|
||||
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
||||
}
|
||||
/** Adjust color brightness. Factor > 1 lightens, < 1 darkens. */
|
||||
function adjustBrightness(color, factor) {
|
||||
const parsed = parseColor(color);
|
||||
if (!parsed) return color;
|
||||
const adjust = (c) => Math.min(255, Math.max(0, Math.round(c * factor)));
|
||||
return `rgb(${adjust(parsed.r)}, ${adjust(parsed.g)}, ${adjust(parsed.b)})`;
|
||||
}
|
||||
/** Derive export background colors from a base color (e.g., userMessageBg). */
|
||||
function deriveExportColors(baseColor) {
|
||||
const parsed = parseColor(baseColor);
|
||||
if (!parsed) {
|
||||
return {
|
||||
pageBg: "rgb(24, 24, 30)",
|
||||
cardBg: "rgb(30, 30, 36)",
|
||||
infoBg: "rgb(60, 55, 40)",
|
||||
};
|
||||
}
|
||||
const luminance = getLuminance(parsed.r, parsed.g, parsed.b);
|
||||
const isLight = luminance > 0.5;
|
||||
if (isLight) {
|
||||
return {
|
||||
pageBg: adjustBrightness(baseColor, 0.96),
|
||||
cardBg: baseColor,
|
||||
infoBg: `rgb(${Math.min(255, parsed.r + 10)}, ${Math.min(255, parsed.g + 5)}, ${Math.max(0, parsed.b - 20)})`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
pageBg: adjustBrightness(baseColor, 0.7),
|
||||
cardBg: adjustBrightness(baseColor, 0.85),
|
||||
infoBg: `rgb(${Math.min(255, parsed.r + 20)}, ${Math.min(255, parsed.g + 15)}, ${parsed.b})`,
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Generate CSS custom property declarations from theme colors.
|
||||
*/
|
||||
function generateThemeVars(themeName) {
|
||||
const colors = getResolvedThemeColors(themeName);
|
||||
const lines = [];
|
||||
for (const [key, value] of Object.entries(colors)) {
|
||||
lines.push(`--${key}: ${value};`);
|
||||
}
|
||||
// Use explicit theme export colors if available, otherwise derive from userMessageBg
|
||||
const themeExport = getThemeExportColors(themeName);
|
||||
const userMessageBg = colors.userMessageBg || "#343541";
|
||||
const derivedColors = deriveExportColors(userMessageBg);
|
||||
lines.push(`--exportPageBg: ${themeExport.pageBg ?? derivedColors.pageBg};`);
|
||||
lines.push(`--exportCardBg: ${themeExport.cardBg ?? derivedColors.cardBg};`);
|
||||
lines.push(`--exportInfoBg: ${themeExport.infoBg ?? derivedColors.infoBg};`);
|
||||
return lines.join("\n ");
|
||||
}
|
||||
/**
|
||||
* Core HTML generation logic shared by both export functions.
|
||||
*/
|
||||
function generateHtml(sessionData, themeName) {
|
||||
const templateDir = getExportTemplateDir();
|
||||
const template = readFileSync(join(templateDir, "template.html"), "utf-8");
|
||||
const templateCss = readFileSync(join(templateDir, "template.css"), "utf-8");
|
||||
const templateJs = readFileSync(join(templateDir, "template.js"), "utf-8");
|
||||
const markedJs = readFileSync(
|
||||
join(templateDir, "vendor", "marked.min.js"),
|
||||
"utf-8",
|
||||
);
|
||||
const hljsJs = readFileSync(
|
||||
join(templateDir, "vendor", "highlight.min.js"),
|
||||
"utf-8",
|
||||
);
|
||||
const themeVars = generateThemeVars(themeName);
|
||||
const colors = getResolvedThemeColors(themeName);
|
||||
const exportColors = deriveExportColors(colors.userMessageBg || "#343541");
|
||||
const bodyBg = exportColors.pageBg;
|
||||
const containerBg = exportColors.cardBg;
|
||||
const infoBg = exportColors.infoBg;
|
||||
// Base64 encode session data to avoid escaping issues
|
||||
const sessionDataBase64 = Buffer.from(JSON.stringify(sessionData)).toString(
|
||||
"base64",
|
||||
);
|
||||
// Build the CSS with theme variables injected
|
||||
const css = templateCss
|
||||
.replace("{{THEME_VARS}}", themeVars)
|
||||
.replace("{{BODY_BG}}", bodyBg)
|
||||
.replace("{{CONTAINER_BG}}", containerBg)
|
||||
.replace("{{INFO_BG}}", infoBg);
|
||||
return template
|
||||
.replace("{{CSS}}", css)
|
||||
.replace("{{JS}}", templateJs)
|
||||
.replace("{{SESSION_DATA}}", sessionDataBase64)
|
||||
.replace("{{MARKED_JS}}", markedJs)
|
||||
.replace("{{HIGHLIGHT_JS}}", hljsJs);
|
||||
}
|
||||
/** Built-in tool names that have custom rendering in template.js */
|
||||
const BUILTIN_TOOLS = new Set([
|
||||
"bash",
|
||||
"read",
|
||||
"write",
|
||||
"edit",
|
||||
"ls",
|
||||
"find",
|
||||
"grep",
|
||||
]);
|
||||
/**
|
||||
* Pre-render custom tools to HTML using their TUI renderers.
|
||||
*/
|
||||
function preRenderCustomTools(entries, toolRenderer) {
|
||||
const renderedTools = {};
|
||||
for (const entry of entries) {
|
||||
if (entry.type !== "message") continue;
|
||||
const msg = entry.message;
|
||||
// Find tool calls in assistant messages
|
||||
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
||||
for (const block of msg.content) {
|
||||
if (block.type === "toolCall" && !BUILTIN_TOOLS.has(block.name)) {
|
||||
const callHtml = toolRenderer.renderCall(block.name, block.arguments);
|
||||
if (callHtml) {
|
||||
renderedTools[block.id] = { callHtml };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find tool results
|
||||
if (msg.role === "toolResult" && msg.toolCallId) {
|
||||
const toolName = msg.toolName || "";
|
||||
// Only render if we have a pre-rendered call OR it's not a built-in tool
|
||||
const existing = renderedTools[msg.toolCallId];
|
||||
if (existing || !BUILTIN_TOOLS.has(toolName)) {
|
||||
const resultHtml = toolRenderer.renderResult(
|
||||
toolName,
|
||||
msg.content,
|
||||
msg.details,
|
||||
msg.isError || false,
|
||||
);
|
||||
if (resultHtml) {
|
||||
renderedTools[msg.toolCallId] = {
|
||||
...existing,
|
||||
resultHtml,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return renderedTools;
|
||||
}
|
||||
/**
|
||||
* Export session to HTML using SessionManager and AgentState.
|
||||
* Used by TUI's /export command.
|
||||
*/
|
||||
export async function exportSessionToHtml(sm, state, options) {
|
||||
const opts =
|
||||
typeof options === "string" ? { outputPath: options } : options || {};
|
||||
const sessionFile = sm.getSessionFile();
|
||||
if (!sessionFile) {
|
||||
throw new Error("Cannot export in-memory session to HTML");
|
||||
}
|
||||
if (!existsSync(sessionFile)) {
|
||||
throw new Error("Nothing to export yet - start a conversation first");
|
||||
}
|
||||
const entries = sm.getEntries();
|
||||
// Pre-render custom tools if a tool renderer is provided
|
||||
let renderedTools;
|
||||
if (opts.toolRenderer) {
|
||||
renderedTools = preRenderCustomTools(entries, opts.toolRenderer);
|
||||
// Only include if we actually rendered something
|
||||
if (Object.keys(renderedTools).length === 0) {
|
||||
renderedTools = undefined;
|
||||
}
|
||||
}
|
||||
const sessionData = {
|
||||
header: sm.getHeader(),
|
||||
entries,
|
||||
leafId: sm.getLeafId(),
|
||||
systemPrompt: state?.systemPrompt,
|
||||
tools: state?.tools?.map((t) => ({
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
parameters: t.parameters,
|
||||
})),
|
||||
renderedTools,
|
||||
};
|
||||
const html = generateHtml(sessionData, opts.themeName);
|
||||
let outputPath = opts.outputPath;
|
||||
if (!outputPath) {
|
||||
const sessionBasename = basename(sessionFile, ".jsonl");
|
||||
outputPath = `${APP_NAME}-session-${sessionBasename}.html`;
|
||||
}
|
||||
writeFileSync(outputPath, html, "utf8");
|
||||
return outputPath;
|
||||
}
|
||||
/**
|
||||
* Export session file to HTML (standalone, without AgentState).
|
||||
* Used by CLI for exporting arbitrary session files.
|
||||
*/
|
||||
export async function exportFromFile(inputPath, options) {
|
||||
const opts =
|
||||
typeof options === "string" ? { outputPath: options } : options || {};
|
||||
if (!existsSync(inputPath)) {
|
||||
throw new Error(`File not found: ${inputPath}`);
|
||||
}
|
||||
const sm = SessionManager.open(inputPath);
|
||||
const sessionData = {
|
||||
header: sm.getHeader(),
|
||||
entries: sm.getEntries(),
|
||||
leafId: sm.getLeafId(),
|
||||
systemPrompt: undefined,
|
||||
tools: undefined,
|
||||
};
|
||||
const html = generateHtml(sessionData, opts.themeName);
|
||||
let outputPath = opts.outputPath;
|
||||
if (!outputPath) {
|
||||
const inputBasename = basename(inputPath, ".jsonl");
|
||||
outputPath = `${APP_NAME}-session-${inputBasename}.html`;
|
||||
}
|
||||
writeFileSync(outputPath, html, "utf8");
|
||||
return outputPath;
|
||||
}
|
||||
//# sourceMappingURL=index.js.map
|
||||
File diff suppressed because one or more lines are too long
971
packages/coding-agent/companion-out/export-html/template.css
Normal file
971
packages/coding-agent/companion-out/export-html/template.css
Normal file
|
|
@ -0,0 +1,971 @@
|
|||
:root {
|
||||
{{THEME_VARS}}
|
||||
--body-bg: {{BODY_BG}};
|
||||
--container-bg: {{CONTAINER_BG}};
|
||||
--info-bg: {{INFO_BG}};
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
:root {
|
||||
--line-height: 18px; /* 12px font * 1.5 */
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;
|
||||
font-size: 12px;
|
||||
line-height: var(--line-height);
|
||||
color: var(--text);
|
||||
background: var(--body-bg);
|
||||
}
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
#sidebar {
|
||||
width: 400px;
|
||||
background: var(--container-bg);
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
height: 100vh;
|
||||
border-right: 1px solid var(--dim);
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 8px 12px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.sidebar-controls {
|
||||
padding: 8px 8px 4px 8px;
|
||||
}
|
||||
|
||||
.sidebar-search {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
padding: 4px 8px;
|
||||
font-size: 11px;
|
||||
font-family: inherit;
|
||||
background: var(--body-bg);
|
||||
color: var(--text);
|
||||
border: 1px solid var(--dim);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.sidebar-filters {
|
||||
display: flex;
|
||||
padding: 4px 8px 8px 8px;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.sidebar-search:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.sidebar-search::placeholder {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.filter-btn {
|
||||
padding: 3px 8px;
|
||||
font-size: 10px;
|
||||
font-family: inherit;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
border: 1px solid var(--dim);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.filter-btn:hover {
|
||||
color: var(--text);
|
||||
border-color: var(--text);
|
||||
}
|
||||
|
||||
.filter-btn.active {
|
||||
background: var(--accent);
|
||||
color: var(--body-bg);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.sidebar-close {
|
||||
display: none;
|
||||
padding: 3px 8px;
|
||||
font-size: 12px;
|
||||
font-family: inherit;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
border: 1px solid var(--dim);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.sidebar-close:hover {
|
||||
color: var(--text);
|
||||
border-color: var(--text);
|
||||
}
|
||||
|
||||
.tree-container {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.tree-node {
|
||||
padding: 0 8px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
font-size: 11px;
|
||||
line-height: 13px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tree-node:hover {
|
||||
background: var(--selectedBg);
|
||||
}
|
||||
|
||||
.tree-node.active {
|
||||
background: var(--selectedBg);
|
||||
}
|
||||
|
||||
.tree-node.active .tree-content {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tree-node.in-path {
|
||||
background: color-mix(in srgb, var(--accent) 10%, transparent);
|
||||
}
|
||||
|
||||
.tree-node:not(.in-path) {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.tree-node:not(.in-path):hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.tree-prefix {
|
||||
color: var(--muted);
|
||||
flex-shrink: 0;
|
||||
font-family: monospace;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.tree-marker {
|
||||
color: var(--accent);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.tree-content {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tree-role-user {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.tree-role-assistant {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.tree-role-tool {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.tree-muted {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.tree-error {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.tree-compaction {
|
||||
color: var(--borderAccent);
|
||||
}
|
||||
|
||||
.tree-branch-summary {
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.tree-custom-message {
|
||||
color: var(--customMessageLabel);
|
||||
}
|
||||
|
||||
.tree-status {
|
||||
padding: 4px 12px;
|
||||
font-size: 10px;
|
||||
color: var(--muted);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* Main content */
|
||||
#content {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: var(--line-height) calc(var(--line-height) * 2);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#content > * {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
/* Help bar */
|
||||
.help-bar {
|
||||
font-size: 11px;
|
||||
color: var(--warning);
|
||||
margin-bottom: var(--line-height);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.download-json-btn {
|
||||
font-size: 10px;
|
||||
padding: 2px 8px;
|
||||
background: var(--container-bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 3px;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.download-json-btn:hover {
|
||||
background: var(--hover);
|
||||
border-color: var(--borderAccent);
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.header {
|
||||
background: var(--container-bg);
|
||||
border-radius: 4px;
|
||||
padding: var(--line-height);
|
||||
margin-bottom: var(--line-height);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: var(--borderAccent);
|
||||
margin-bottom: var(--line-height);
|
||||
}
|
||||
|
||||
.header-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
color: var(--dim);
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 600;
|
||||
margin-right: 8px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
color: var(--text);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Messages */
|
||||
#messages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--line-height);
|
||||
}
|
||||
|
||||
.message-timestamp {
|
||||
font-size: 10px;
|
||||
color: var(--dim);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.user-message {
|
||||
background: var(--userMessageBg);
|
||||
color: var(--userMessageText);
|
||||
padding: var(--line-height);
|
||||
border-radius: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.assistant-message {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Copy link button - appears on hover */
|
||||
.copy-link-btn {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 6px;
|
||||
background: var(--container-bg);
|
||||
border: 1px solid var(--dim);
|
||||
border-radius: 4px;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s, background 0.15s, color 0.15s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.user-message:hover .copy-link-btn,
|
||||
.assistant-message:hover .copy-link-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.copy-link-btn:hover {
|
||||
background: var(--accent);
|
||||
color: var(--body-bg);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
.copy-link-btn.copied {
|
||||
background: var(--success, #22c55e);
|
||||
color: white;
|
||||
border-color: var(--success, #22c55e);
|
||||
}
|
||||
|
||||
/* Highlight effect for deep-linked messages */
|
||||
.user-message.highlight,
|
||||
.assistant-message.highlight {
|
||||
animation: highlight-pulse 2s ease-out;
|
||||
}
|
||||
|
||||
@keyframes highlight-pulse {
|
||||
0% {
|
||||
box-shadow: 0 0 0 3px var(--accent);
|
||||
}
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.assistant-message > .message-timestamp {
|
||||
padding-left: var(--line-height);
|
||||
}
|
||||
|
||||
.assistant-text {
|
||||
padding: var(--line-height);
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.message-timestamp + .assistant-text,
|
||||
.message-timestamp + .thinking-block {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.thinking-block + .assistant-text {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.thinking-text {
|
||||
padding: var(--line-height);
|
||||
color: var(--thinkingText);
|
||||
font-style: italic;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.message-timestamp + .thinking-block .thinking-text,
|
||||
.message-timestamp + .thinking-block .thinking-collapsed {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.thinking-collapsed {
|
||||
display: none;
|
||||
padding: var(--line-height);
|
||||
color: var(--thinkingText);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Tool execution */
|
||||
.tool-execution {
|
||||
padding: var(--line-height);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.tool-execution + .tool-execution {
|
||||
margin-top: var(--line-height);
|
||||
}
|
||||
|
||||
.assistant-text + .tool-execution {
|
||||
margin-top: var(--line-height);
|
||||
}
|
||||
|
||||
.tool-execution.pending { background: var(--toolPendingBg); }
|
||||
.tool-execution.success { background: var(--toolSuccessBg); }
|
||||
.tool-execution.error { background: var(--toolErrorBg); }
|
||||
|
||||
.tool-header, .tool-name {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tool-path {
|
||||
color: var(--accent);
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.line-numbers {
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.line-count {
|
||||
color: var(--dim);
|
||||
}
|
||||
|
||||
.tool-command {
|
||||
font-weight: bold;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.tool-output {
|
||||
margin-top: var(--line-height);
|
||||
color: var(--toolOutput);
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-word;
|
||||
font-family: inherit;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.tool-output > div,
|
||||
.output-preview,
|
||||
.output-full {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: var(--line-height);
|
||||
}
|
||||
|
||||
.tool-output pre {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: inherit;
|
||||
color: inherit;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.tool-output code {
|
||||
padding: 0;
|
||||
background: none;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tool-output.expandable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tool-output.expandable:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.tool-output.expandable .output-full {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tool-output.expandable.expanded .output-preview {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tool-output.expandable.expanded .output-full {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.ansi-line {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.tool-images {
|
||||
}
|
||||
|
||||
.tool-image {
|
||||
max-width: 100%;
|
||||
max-height: 500px;
|
||||
border-radius: 4px;
|
||||
margin: var(--line-height) 0;
|
||||
}
|
||||
|
||||
.expand-hint {
|
||||
color: var(--toolOutput);
|
||||
}
|
||||
|
||||
/* Diff */
|
||||
.tool-diff {
|
||||
font-size: 11px;
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.diff-added { color: var(--toolDiffAdded); }
|
||||
.diff-removed { color: var(--toolDiffRemoved); }
|
||||
.diff-context { color: var(--toolDiffContext); }
|
||||
|
||||
/* Model change */
|
||||
.model-change {
|
||||
padding: 0 var(--line-height);
|
||||
color: var(--dim);
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.model-name {
|
||||
color: var(--borderAccent);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Compaction / Branch Summary - matches customMessage colors from TUI */
|
||||
.compaction {
|
||||
background: var(--customMessageBg);
|
||||
border-radius: 4px;
|
||||
padding: var(--line-height);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.compaction-label {
|
||||
color: var(--customMessageLabel);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.compaction-collapsed {
|
||||
color: var(--customMessageText);
|
||||
}
|
||||
|
||||
.compaction-content {
|
||||
display: none;
|
||||
color: var(--customMessageText);
|
||||
white-space: pre-wrap;
|
||||
margin-top: var(--line-height);
|
||||
}
|
||||
|
||||
.compaction.expanded .compaction-collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.compaction.expanded .compaction-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* System prompt */
|
||||
.system-prompt {
|
||||
background: var(--customMessageBg);
|
||||
padding: var(--line-height);
|
||||
border-radius: 4px;
|
||||
margin-bottom: var(--line-height);
|
||||
}
|
||||
|
||||
.system-prompt.expandable {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.system-prompt-header {
|
||||
font-weight: bold;
|
||||
color: var(--customMessageLabel);
|
||||
}
|
||||
|
||||
.system-prompt-preview {
|
||||
color: var(--customMessageText);
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-size: 11px;
|
||||
margin-top: var(--line-height);
|
||||
}
|
||||
|
||||
.system-prompt-expand-hint {
|
||||
color: var(--muted);
|
||||
font-style: italic;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.system-prompt-full {
|
||||
display: none;
|
||||
color: var(--customMessageText);
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-size: 11px;
|
||||
margin-top: var(--line-height);
|
||||
}
|
||||
|
||||
.system-prompt.expanded .system-prompt-preview,
|
||||
.system-prompt.expanded .system-prompt-expand-hint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.system-prompt.expanded .system-prompt-full {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.system-prompt.provider-prompt {
|
||||
border-left: 3px solid var(--warning);
|
||||
}
|
||||
|
||||
.system-prompt-note {
|
||||
font-size: 10px;
|
||||
font-style: italic;
|
||||
color: var(--muted);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Tools list */
|
||||
.tools-list {
|
||||
background: var(--customMessageBg);
|
||||
padding: var(--line-height);
|
||||
border-radius: 4px;
|
||||
margin-bottom: var(--line-height);
|
||||
}
|
||||
|
||||
.tools-header {
|
||||
font-weight: bold;
|
||||
color: var(--customMessageLabel);
|
||||
margin-bottom: var(--line-height);
|
||||
}
|
||||
|
||||
.tool-item {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.tool-item-name {
|
||||
font-weight: bold;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tool-item-desc {
|
||||
color: var(--dim);
|
||||
}
|
||||
|
||||
.tool-params-hint {
|
||||
color: var(--muted);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.tool-item:has(.tool-params-hint) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tool-params-hint::after {
|
||||
content: '[click to show parameters]';
|
||||
}
|
||||
|
||||
.tool-item.params-expanded .tool-params-hint::after {
|
||||
content: '[hide parameters]';
|
||||
}
|
||||
|
||||
.tool-params-content {
|
||||
display: none;
|
||||
margin-top: 4px;
|
||||
margin-left: 12px;
|
||||
padding-left: 8px;
|
||||
border-left: 1px solid var(--dim);
|
||||
}
|
||||
|
||||
.tool-item.params-expanded .tool-params-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tool-param {
|
||||
margin-bottom: 4px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.tool-param-name {
|
||||
font-weight: bold;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.tool-param-type {
|
||||
color: var(--dim);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.tool-param-required {
|
||||
color: var(--warning, #e8a838);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.tool-param-optional {
|
||||
color: var(--dim);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.tool-param-desc {
|
||||
color: var(--dim);
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
/* Hook/custom messages */
|
||||
.hook-message {
|
||||
background: var(--customMessageBg);
|
||||
color: var(--customMessageText);
|
||||
padding: var(--line-height);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.hook-type {
|
||||
color: var(--customMessageLabel);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Branch summary */
|
||||
.branch-summary {
|
||||
background: var(--customMessageBg);
|
||||
padding: var(--line-height);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.branch-summary-header {
|
||||
font-weight: bold;
|
||||
color: var(--borderAccent);
|
||||
}
|
||||
|
||||
/* Error */
|
||||
.error-text {
|
||||
color: var(--error);
|
||||
padding: 0 var(--line-height);
|
||||
}
|
||||
.tool-error {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
/* Images */
|
||||
.message-images {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.message-image {
|
||||
max-width: 100%;
|
||||
max-height: 400px;
|
||||
border-radius: 4px;
|
||||
margin: var(--line-height) 0;
|
||||
}
|
||||
|
||||
/* Markdown content */
|
||||
.markdown-content h1,
|
||||
.markdown-content h2,
|
||||
.markdown-content h3,
|
||||
.markdown-content h4,
|
||||
.markdown-content h5,
|
||||
.markdown-content h6 {
|
||||
color: var(--mdHeading);
|
||||
margin: var(--line-height) 0 0 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-content h1 { font-size: 1em; }
|
||||
.markdown-content h2 { font-size: 1em; }
|
||||
.markdown-content h3 { font-size: 1em; }
|
||||
.markdown-content h4 { font-size: 1em; }
|
||||
.markdown-content h5 { font-size: 1em; }
|
||||
.markdown-content h6 { font-size: 1em; }
|
||||
.markdown-content p { margin: 0; }
|
||||
.markdown-content p + p { margin-top: var(--line-height); }
|
||||
|
||||
.markdown-content a {
|
||||
color: var(--mdLink);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.markdown-content code {
|
||||
background: rgba(128, 128, 128, 0.2);
|
||||
color: var(--mdCode);
|
||||
padding: 0 4px;
|
||||
border-radius: 3px;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.markdown-content pre {
|
||||
background: transparent;
|
||||
margin: var(--line-height) 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.markdown-content pre code {
|
||||
display: block;
|
||||
background: none;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.markdown-content blockquote {
|
||||
border-left: 3px solid var(--mdQuoteBorder);
|
||||
padding-left: var(--line-height);
|
||||
margin: var(--line-height) 0;
|
||||
color: var(--mdQuote);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.markdown-content ul,
|
||||
.markdown-content ol {
|
||||
margin: var(--line-height) 0;
|
||||
padding-left: calc(var(--line-height) * 2);
|
||||
}
|
||||
|
||||
.markdown-content li { margin: 0; }
|
||||
.markdown-content li::marker { color: var(--mdListBullet); }
|
||||
|
||||
.markdown-content hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--mdHr);
|
||||
margin: var(--line-height) 0;
|
||||
}
|
||||
|
||||
.markdown-content table {
|
||||
border-collapse: collapse;
|
||||
margin: 0.5em 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.markdown-content th,
|
||||
.markdown-content td {
|
||||
border: 1px solid var(--mdCodeBlockBorder);
|
||||
padding: 6px 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.markdown-content th {
|
||||
background: rgba(128, 128, 128, 0.1);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-content img {
|
||||
max-width: 100%;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Syntax highlighting */
|
||||
.hljs { background: transparent; color: var(--text); }
|
||||
.hljs-comment, .hljs-quote { color: var(--syntaxComment); }
|
||||
.hljs-keyword, .hljs-selector-tag { color: var(--syntaxKeyword); }
|
||||
.hljs-number, .hljs-literal { color: var(--syntaxNumber); }
|
||||
.hljs-string, .hljs-doctag { color: var(--syntaxString); }
|
||||
/* Function names: hljs v11 uses .hljs-title.function_ compound class */
|
||||
.hljs-function, .hljs-title, .hljs-title.function_, .hljs-section, .hljs-name { color: var(--syntaxFunction); }
|
||||
/* Types: hljs v11 uses .hljs-title.class_ for class names */
|
||||
.hljs-type, .hljs-class, .hljs-title.class_, .hljs-built_in { color: var(--syntaxType); }
|
||||
.hljs-attr, .hljs-variable, .hljs-variable.language_, .hljs-params, .hljs-property { color: var(--syntaxVariable); }
|
||||
.hljs-meta, .hljs-meta .hljs-keyword, .hljs-meta .hljs-string { color: var(--syntaxKeyword); }
|
||||
.hljs-operator { color: var(--syntaxOperator); }
|
||||
.hljs-punctuation { color: var(--syntaxPunctuation); }
|
||||
.hljs-subst { color: var(--text); }
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
margin-top: 48px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
color: var(--dim);
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
#hamburger {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 100;
|
||||
padding: 3px 8px;
|
||||
font-size: 12px;
|
||||
font-family: inherit;
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
border: 1px solid var(--dim);
|
||||
border-radius: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#hamburger:hover {
|
||||
color: var(--text);
|
||||
border-color: var(--text);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#sidebar-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 98;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
#sidebar {
|
||||
position: fixed;
|
||||
left: -400px;
|
||||
width: 400px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
height: 100vh;
|
||||
z-index: 99;
|
||||
transition: left 0.3s;
|
||||
}
|
||||
|
||||
#sidebar.open {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#sidebar-overlay.open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#hamburger {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebar-close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#content {
|
||||
padding: var(--line-height) 16px;
|
||||
}
|
||||
|
||||
#content > * {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
#sidebar {
|
||||
width: 100vw;
|
||||
left: -100vw;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
#sidebar, #sidebar-toggle { display: none !important; }
|
||||
body { background: white; color: black; }
|
||||
#content { max-width: none; }
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Session Export</title>
|
||||
<style>
|
||||
{{CSS}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button id="hamburger" title="Open sidebar"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="none"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="12" r="2.5"/><rect x="5" y="6" width="2" height="12"/><path d="M6 12h10c1 0 2 0 2-2V8"/></svg></button>
|
||||
<div id="sidebar-overlay"></div>
|
||||
<div id="app">
|
||||
<aside id="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<div class="sidebar-controls">
|
||||
<input type="text" class="sidebar-search" id="tree-search" placeholder="Search...">
|
||||
</div>
|
||||
<div class="sidebar-filters">
|
||||
<button class="filter-btn active" data-filter="default" title="Hide settings entries">Default</button>
|
||||
<button class="filter-btn" data-filter="no-tools" title="Default minus tool results">No-tools</button>
|
||||
<button class="filter-btn" data-filter="user-only" title="Only user messages">User</button>
|
||||
<button class="filter-btn" data-filter="labeled-only" title="Only labeled entries">Labeled</button>
|
||||
<button class="filter-btn" data-filter="all" title="Show everything">All</button>
|
||||
<button class="sidebar-close" id="sidebar-close" title="Close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tree-container" id="tree-container"></div>
|
||||
<div class="tree-status" id="tree-status"></div>
|
||||
</aside>
|
||||
<main id="content">
|
||||
<div id="header-container"></div>
|
||||
<div id="messages"></div>
|
||||
</main>
|
||||
<div id="image-modal" class="image-modal">
|
||||
<img id="modal-image" src="" alt="">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script id="session-data" type="application/json">{{SESSION_DATA}}</script>
|
||||
|
||||
<!-- Vendored libraries -->
|
||||
<script>{{MARKED_JS}}</script>
|
||||
|
||||
<!-- highlight.js -->
|
||||
<script>{{HIGHLIGHT_JS}}</script>
|
||||
|
||||
<!-- Main application code -->
|
||||
<script>
|
||||
{{JS}}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1831
packages/coding-agent/companion-out/export-html/template.js
Normal file
1831
packages/coding-agent/companion-out/export-html/template.js
Normal file
File diff suppressed because it is too large
Load diff
42
packages/coding-agent/companion-out/export-html/tool-renderer.d.ts
vendored
Normal file
42
packages/coding-agent/companion-out/export-html/tool-renderer.d.ts
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Tool HTML renderer for custom tools in HTML export.
|
||||
*
|
||||
* Renders custom tool calls and results to HTML by invoking their TUI renderers
|
||||
* and converting the ANSI output to HTML.
|
||||
*/
|
||||
import type { Theme } from "../../modes/interactive/theme/theme.js";
|
||||
import type { ToolDefinition } from "../extensions/types.js";
|
||||
export interface ToolHtmlRendererDeps {
|
||||
/** Function to look up tool definition by name */
|
||||
getToolDefinition: (name: string) => ToolDefinition | undefined;
|
||||
/** Theme for styling */
|
||||
theme: Theme;
|
||||
/** Terminal width for rendering (default: 100) */
|
||||
width?: number;
|
||||
}
|
||||
export interface ToolHtmlRenderer {
|
||||
/** Render a tool call to HTML. Returns undefined if tool has no custom renderer. */
|
||||
renderCall(toolName: string, args: unknown): string | undefined;
|
||||
/** Render a tool result to HTML. Returns undefined if tool has no custom renderer. */
|
||||
renderResult(
|
||||
toolName: string,
|
||||
result: Array<{
|
||||
type: string;
|
||||
text?: string;
|
||||
data?: string;
|
||||
mimeType?: string;
|
||||
}>,
|
||||
details: unknown,
|
||||
isError: boolean,
|
||||
): string | undefined;
|
||||
}
|
||||
/**
|
||||
* Create a tool HTML renderer.
|
||||
*
|
||||
* The renderer looks up tool definitions and invokes their renderCall/renderResult
|
||||
* methods, converting the resulting TUI Component output (ANSI) to HTML.
|
||||
*/
|
||||
export declare function createToolHtmlRenderer(
|
||||
deps: ToolHtmlRendererDeps,
|
||||
): ToolHtmlRenderer;
|
||||
//# sourceMappingURL=tool-renderer.d.ts.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"tool-renderer.d.ts","sourceRoot":"","sources":["../../../src/core/export-html/tool-renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG7D,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,iBAAiB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,cAAc,GAAG,SAAS,CAAC;IAChE,wBAAwB;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,oFAAoF;IACpF,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAChE,sFAAsF;IACtF,YAAY,CACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,KAAK,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC,EACF,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GACf,MAAM,GAAG,SAAS,CAAC;CACvB;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,oBAAoB,GACzB,gBAAgB,CAiElB","sourcesContent":["/**\n * Tool HTML renderer for custom tools in HTML export.\n *\n * Renders custom tool calls and results to HTML by invoking their TUI renderers\n * and converting the ANSI output to HTML.\n */\n\nimport type { ImageContent, TextContent } from \"@mariozechner/companion-ai\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { ansiLinesToHtml } from \"./ansi-to-html.js\";\n\nexport interface ToolHtmlRendererDeps {\n /** Function to look up tool definition by name */\n getToolDefinition: (name: string) => ToolDefinition | undefined;\n /** Theme for styling */\n theme: Theme;\n /** Terminal width for rendering (default: 100) */\n width?: number;\n}\n\nexport interface ToolHtmlRenderer {\n /** Render a tool call to HTML. Returns undefined if tool has no custom renderer. */\n renderCall(toolName: string, args: unknown): string | undefined;\n /** Render a tool result to HTML. Returns undefined if tool has no custom renderer. */\n renderResult(\n toolName: string,\n result: Array<{\n type: string;\n text?: string;\n data?: string;\n mimeType?: string;\n }>,\n details: unknown,\n isError: boolean,\n ): string | undefined;\n}\n\n/**\n * Create a tool HTML renderer.\n *\n * The renderer looks up tool definitions and invokes their renderCall/renderResult\n * methods, converting the resulting TUI Component output (ANSI) to HTML.\n */\nexport function createToolHtmlRenderer(\n deps: ToolHtmlRendererDeps,\n): ToolHtmlRenderer {\n const { getToolDefinition, theme, width = 100 } = deps;\n\n return {\n renderCall(toolName: string, args: unknown): string | undefined {\n try {\n const toolDef = getToolDefinition(toolName);\n if (!toolDef?.renderCall) {\n return undefined;\n }\n\n const component = toolDef.renderCall(args, theme);\n if (!component) {\n return undefined;\n }\n const lines = component.render(width);\n return ansiLinesToHtml(lines);\n } catch {\n // On error, return undefined to trigger JSON fallback\n return undefined;\n }\n },\n\n renderResult(\n toolName: string,\n result: Array<{\n type: string;\n text?: string;\n data?: string;\n mimeType?: string;\n }>,\n details: unknown,\n isError: boolean,\n ): string | undefined {\n try {\n const toolDef = getToolDefinition(toolName);\n if (!toolDef?.renderResult) {\n return undefined;\n }\n\n // Build AgentToolResult from content array\n // Cast content since session storage uses generic object types\n const agentToolResult = {\n content: result as (TextContent | ImageContent)[],\n details,\n isError,\n };\n\n // Always render expanded, client-side will apply truncation\n const component = toolDef.renderResult(\n agentToolResult,\n { expanded: true, isPartial: false },\n theme,\n );\n if (!component) {\n return undefined;\n }\n const lines = component.render(width);\n return ansiLinesToHtml(lines);\n } catch {\n // On error, return undefined to trigger JSON fallback\n return undefined;\n }\n },\n };\n}\n"]}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* Tool HTML renderer for custom tools in HTML export.
|
||||
*
|
||||
* Renders custom tool calls and results to HTML by invoking their TUI renderers
|
||||
* and converting the ANSI output to HTML.
|
||||
*/
|
||||
import { ansiLinesToHtml } from "./ansi-to-html.js";
|
||||
/**
|
||||
* Create a tool HTML renderer.
|
||||
*
|
||||
* The renderer looks up tool definitions and invokes their renderCall/renderResult
|
||||
* methods, converting the resulting TUI Component output (ANSI) to HTML.
|
||||
*/
|
||||
export function createToolHtmlRenderer(deps) {
|
||||
const { getToolDefinition, theme, width = 100 } = deps;
|
||||
return {
|
||||
renderCall(toolName, args) {
|
||||
try {
|
||||
const toolDef = getToolDefinition(toolName);
|
||||
if (!toolDef?.renderCall) {
|
||||
return undefined;
|
||||
}
|
||||
const component = toolDef.renderCall(args, theme);
|
||||
if (!component) {
|
||||
return undefined;
|
||||
}
|
||||
const lines = component.render(width);
|
||||
return ansiLinesToHtml(lines);
|
||||
} catch {
|
||||
// On error, return undefined to trigger JSON fallback
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
renderResult(toolName, result, details, isError) {
|
||||
try {
|
||||
const toolDef = getToolDefinition(toolName);
|
||||
if (!toolDef?.renderResult) {
|
||||
return undefined;
|
||||
}
|
||||
// Build AgentToolResult from content array
|
||||
// Cast content since session storage uses generic object types
|
||||
const agentToolResult = {
|
||||
content: result,
|
||||
details,
|
||||
isError,
|
||||
};
|
||||
// Always render expanded, client-side will apply truncation
|
||||
const component = toolDef.renderResult(
|
||||
agentToolResult,
|
||||
{ expanded: true, isPartial: false },
|
||||
theme,
|
||||
);
|
||||
if (!component) {
|
||||
return undefined;
|
||||
}
|
||||
const lines = component.render(width);
|
||||
return ansiLinesToHtml(lines);
|
||||
} catch {
|
||||
// On error, return undefined to trigger JSON fallback
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=tool-renderer.js.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"tool-renderer.js","sourceRoot":"","sources":["../../../src/core/export-html/tool-renderer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AA4BpD;;;;;GAKG;AACH,MAAM,UAAU,sBAAsB,CACpC,IAA0B,EACR;IAClB,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC;IAEvD,OAAO;QACL,UAAU,CAAC,QAAgB,EAAE,IAAa,EAAsB;YAC9D,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;gBAC5C,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC;oBACzB,OAAO,SAAS,CAAC;gBACnB,CAAC;gBAED,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;gBAClD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,SAAS,CAAC;gBACnB,CAAC;gBACD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACtC,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,sDAAsD;gBACtD,OAAO,SAAS,CAAC;YACnB,CAAC;QAAA,CACF;QAED,YAAY,CACV,QAAgB,EAChB,MAKE,EACF,OAAgB,EAChB,OAAgB,EACI;YACpB,IAAI,CAAC;gBACH,MAAM,OAAO,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;gBAC5C,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;oBAC3B,OAAO,SAAS,CAAC;gBACnB,CAAC;gBAED,2CAA2C;gBAC3C,+DAA+D;gBAC/D,MAAM,eAAe,GAAG;oBACtB,OAAO,EAAE,MAAwC;oBACjD,OAAO;oBACP,OAAO;iBACR,CAAC;gBAEF,4DAA4D;gBAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,CACpC,eAAe,EACf,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,EACpC,KAAK,CACN,CAAC;gBACF,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,SAAS,CAAC;gBACnB,CAAC;gBACD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACtC,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;YAChC,CAAC;YAAC,MAAM,CAAC;gBACP,sDAAsD;gBACtD,OAAO,SAAS,CAAC;YACnB,CAAC;QAAA,CACF;KACF,CAAC;AAAA,CACH","sourcesContent":["/**\n * Tool HTML renderer for custom tools in HTML export.\n *\n * Renders custom tool calls and results to HTML by invoking their TUI renderers\n * and converting the ANSI output to HTML.\n */\n\nimport type { ImageContent, TextContent } from \"@mariozechner/companion-ai\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ToolDefinition } from \"../extensions/types.js\";\nimport { ansiLinesToHtml } from \"./ansi-to-html.js\";\n\nexport interface ToolHtmlRendererDeps {\n /** Function to look up tool definition by name */\n getToolDefinition: (name: string) => ToolDefinition | undefined;\n /** Theme for styling */\n theme: Theme;\n /** Terminal width for rendering (default: 100) */\n width?: number;\n}\n\nexport interface ToolHtmlRenderer {\n /** Render a tool call to HTML. Returns undefined if tool has no custom renderer. */\n renderCall(toolName: string, args: unknown): string | undefined;\n /** Render a tool result to HTML. Returns undefined if tool has no custom renderer. */\n renderResult(\n toolName: string,\n result: Array<{\n type: string;\n text?: string;\n data?: string;\n mimeType?: string;\n }>,\n details: unknown,\n isError: boolean,\n ): string | undefined;\n}\n\n/**\n * Create a tool HTML renderer.\n *\n * The renderer looks up tool definitions and invokes their renderCall/renderResult\n * methods, converting the resulting TUI Component output (ANSI) to HTML.\n */\nexport function createToolHtmlRenderer(\n deps: ToolHtmlRendererDeps,\n): ToolHtmlRenderer {\n const { getToolDefinition, theme, width = 100 } = deps;\n\n return {\n renderCall(toolName: string, args: unknown): string | undefined {\n try {\n const toolDef = getToolDefinition(toolName);\n if (!toolDef?.renderCall) {\n return undefined;\n }\n\n const component = toolDef.renderCall(args, theme);\n if (!component) {\n return undefined;\n }\n const lines = component.render(width);\n return ansiLinesToHtml(lines);\n } catch {\n // On error, return undefined to trigger JSON fallback\n return undefined;\n }\n },\n\n renderResult(\n toolName: string,\n result: Array<{\n type: string;\n text?: string;\n data?: string;\n mimeType?: string;\n }>,\n details: unknown,\n isError: boolean,\n ): string | undefined {\n try {\n const toolDef = getToolDefinition(toolName);\n if (!toolDef?.renderResult) {\n return undefined;\n }\n\n // Build AgentToolResult from content array\n // Cast content since session storage uses generic object types\n const agentToolResult = {\n content: result as (TextContent | ImageContent)[],\n details,\n isError,\n };\n\n // Always render expanded, client-side will apply truncation\n const component = toolDef.renderResult(\n agentToolResult,\n { expanded: true, isPartial: false },\n theme,\n );\n if (!component) {\n return undefined;\n }\n const lines = component.render(width);\n return ansiLinesToHtml(lines);\n } catch {\n // On error, return undefined to trigger JSON fallback\n return undefined;\n }\n },\n };\n}\n"]}
|
||||
8426
packages/coding-agent/companion-out/export-html/vendor/highlight.min.js
vendored
Normal file
8426
packages/coding-agent/companion-out/export-html/vendor/highlight.min.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
1998
packages/coding-agent/companion-out/export-html/vendor/marked.min.js
vendored
Normal file
1998
packages/coding-agent/companion-out/export-html/vendor/marked.min.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue