@aexol/spectral 0.7.7 → 0.8.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.
- package/dist/agent/agents.js +4 -4
- package/dist/agent/index.js +24 -148
- package/dist/cli.js +25 -220
- package/dist/commands/serve.js +1 -1
- package/dist/extensions/spectral-vision-fallback.js +225 -0
- package/dist/mcp/agent-dir.js +1 -1
- package/dist/mcp/config.js +3 -3
- package/dist/mcp/sampling-handler.js +1 -1
- package/dist/mcp/server-manager.js +5 -1
- package/dist/memory/commands/status.js +6 -6
- package/dist/memory/commands/view.js +16 -14
- package/dist/memory/compaction.js +33 -5
- package/dist/memory/config.js +3 -3
- package/dist/memory/debug-log.js +1 -1
- package/dist/memory/observer.js +2 -2
- package/dist/memory/prompts.js +5 -5
- package/dist/memory/tokens.js +1 -1
- package/dist/memory/tools/read-project-observations.js +2 -2
- package/dist/memory/tools/recall-observation.js +4 -4
- package/dist/relay/auto-research.js +23 -23
- package/dist/relay/dispatcher.js +28 -2
- package/dist/relay/models-fetch.js +15 -3
- package/dist/{pi → sdk}/coding-agent/cli/args.js +4 -4
- package/dist/{pi → sdk}/coding-agent/config.js +9 -20
- package/dist/{pi → sdk}/coding-agent/core/agent-session.js +5 -17
- package/dist/{pi → sdk}/coding-agent/core/compaction/compaction.js +161 -5
- package/dist/{pi → sdk}/coding-agent/core/extensions/loader.js +0 -6
- package/dist/{pi → sdk}/coding-agent/core/extensions/runner.js +7 -1
- package/dist/{pi → sdk}/coding-agent/core/keybindings.js +129 -2
- package/dist/{pi → sdk}/coding-agent/core/model-registry.js +11 -4
- package/dist/{pi → sdk}/coding-agent/core/package-manager.js +5 -5
- package/dist/{pi → sdk}/coding-agent/core/sdk.js +1 -1
- package/dist/{pi → sdk}/coding-agent/core/session-manager.js +4 -4
- package/dist/{pi → sdk}/coding-agent/core/settings-manager.js +20 -0
- package/dist/{pi → sdk}/coding-agent/core/telemetry.js +1 -1
- package/dist/{pi → sdk}/coding-agent/core/tools/bash.js +17 -63
- package/dist/{pi → sdk}/coding-agent/core/tools/edit.js +4 -141
- package/dist/{pi → sdk}/coding-agent/core/tools/find.js +0 -11
- package/dist/{pi → sdk}/coding-agent/core/tools/grep.js +0 -11
- package/dist/{pi → sdk}/coding-agent/core/tools/ls.js +0 -11
- package/dist/{pi → sdk}/coding-agent/core/tools/read.js +0 -12
- package/dist/{pi → sdk}/coding-agent/core/tools/render-utils.js +1 -14
- package/dist/{pi → sdk}/coding-agent/core/tools/write.js +2 -97
- package/dist/{pi → sdk}/coding-agent/migrations.js +3 -3
- package/dist/{pi → sdk}/coding-agent/modes/interactive/components/keybinding-hints.js +1 -1
- package/dist/sdk/coding-agent/modes/interactive/components/visual-truncate.js +26 -0
- package/dist/{pi → sdk}/coding-agent/modes/interactive/theme/theme.js +1 -2
- package/dist/{pi → sdk}/coding-agent/utils/tools-manager.js +1 -1
- package/dist/{pi → sdk}/coding-agent/utils/version-check.js +2 -2
- package/dist/{pi → sdk}/coding-agent/utils/windows-self-update.js +1 -1
- package/dist/server/{pi-bridge.js → agent-bridge.js} +158 -89
- package/dist/server/handlers/sessions.js +21 -0
- package/dist/server/session-stream.js +12 -6
- package/package.json +6 -3
- package/dist/pi/coding-agent/core/export-html/ansi-to-html.js +0 -248
- package/dist/pi/coding-agent/core/export-html/index.js +0 -225
- package/dist/pi/coding-agent/core/export-html/tool-renderer.js +0 -107
- package/dist/pi/coding-agent/modes/interactive/components/visual-truncate.js +0 -32
- package/dist/pi/tui/autocomplete.js +0 -631
- package/dist/pi/tui/components/box.js +0 -103
- package/dist/pi/tui/components/cancellable-loader.js +0 -34
- package/dist/pi/tui/components/editor.js +0 -1915
- package/dist/pi/tui/components/image.js +0 -88
- package/dist/pi/tui/components/input.js +0 -425
- package/dist/pi/tui/components/loader.js +0 -68
- package/dist/pi/tui/components/markdown.js +0 -633
- package/dist/pi/tui/components/select-list.js +0 -158
- package/dist/pi/tui/components/settings-list.js +0 -184
- package/dist/pi/tui/components/spacer.js +0 -22
- package/dist/pi/tui/components/text.js +0 -88
- package/dist/pi/tui/components/truncated-text.js +0 -50
- package/dist/pi/tui/editor-component.js +0 -1
- package/dist/pi/tui/fuzzy.js +0 -109
- package/dist/pi/tui/index.js +0 -31
- package/dist/pi/tui/keybindings.js +0 -173
- package/dist/pi/tui/keys.js +0 -1172
- package/dist/pi/tui/kill-ring.js +0 -43
- package/dist/pi/tui/stdin-buffer.js +0 -360
- package/dist/pi/tui/terminal-image.js +0 -335
- package/dist/pi/tui/terminal.js +0 -324
- package/dist/pi/tui/tui.js +0 -1076
- package/dist/pi/tui/undo-stack.js +0 -24
- package/dist/pi/tui/utils.js +0 -1016
- /package/dist/{pi → sdk}/agent-core/agent-loop.js +0 -0
- /package/dist/{pi → sdk}/agent-core/agent.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/agent-harness.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/compaction/branch-summarization.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/compaction/compaction.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/compaction/utils.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/env/nodejs.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/messages.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/prompt-templates.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/session/jsonl-repo.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/session/jsonl-storage.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/session/memory-repo.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/session/memory-storage.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/session/repo-utils.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/session/session.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/session/uuid.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/skills.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/system-prompt.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/types.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/utils/shell-output.js +0 -0
- /package/dist/{pi → sdk}/agent-core/harness/utils/truncate.js +0 -0
- /package/dist/{pi → sdk}/agent-core/index.js +0 -0
- /package/dist/{pi → sdk}/agent-core/node.js +0 -0
- /package/dist/{pi → sdk}/agent-core/proxy.js +0 -0
- /package/dist/{pi → sdk}/agent-core/types.js +0 -0
- /package/dist/{pi → sdk}/ai/api-registry.js +0 -0
- /package/dist/{pi → sdk}/ai/cli.js +0 -0
- /package/dist/{pi → sdk}/ai/env-api-keys.js +0 -0
- /package/dist/{pi → sdk}/ai/image-models.generated.js +0 -0
- /package/dist/{pi → sdk}/ai/image-models.js +0 -0
- /package/dist/{pi → sdk}/ai/images-api-registry.js +0 -0
- /package/dist/{pi → sdk}/ai/images.js +0 -0
- /package/dist/{pi → sdk}/ai/index.js +0 -0
- /package/dist/{pi → sdk}/ai/models.generated.js +0 -0
- /package/dist/{pi → sdk}/ai/models.js +0 -0
- /package/dist/{pi → sdk}/ai/oauth.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/anthropic.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/faux.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/github-copilot-headers.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/openai-completions.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/openai-prompt-cache.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/register-builtins.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/simple-options.js +0 -0
- /package/dist/{pi → sdk}/ai/providers/transform-messages.js +0 -0
- /package/dist/{pi → sdk}/ai/session-resources.js +0 -0
- /package/dist/{pi → sdk}/ai/stream.js +0 -0
- /package/dist/{pi → sdk}/ai/types.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/diagnostics.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/event-stream.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/hash.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/headers.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/json-parse.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/node-http-proxy.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/anthropic.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/device-code.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/github-copilot.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/index.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/oauth-page.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/openai-codex.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/pkce.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/oauth/types.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/overflow.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/sanitize-unicode.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/typebox-helpers.js +0 -0
- /package/dist/{pi → sdk}/ai/utils/validation.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/bun/cli.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/bun/restore-sandbox-env.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/cli/file-processor.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/cli/initial-message.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/cli.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/agent-session-runtime.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/agent-session-services.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/auth-guidance.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/auth-storage.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/bash-executor.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/compaction/branch-summarization.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/compaction/index.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/compaction/utils.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/defaults.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/diagnostics.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/event-bus.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/exec.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/extensions/index.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/extensions/types.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/extensions/wrapper.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/footer-data-provider.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/http-dispatcher.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/index.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/messages.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/model-resolver.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/output-guard.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/prompt-templates.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/provider-display-names.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/resolve-config-value.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/resource-loader.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/session-cwd.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/skills.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/slash-commands.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/source-info.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/system-prompt.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/timings.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/tools/edit-diff.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/tools/file-mutation-queue.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/tools/index.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/tools/output-accumulator.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/tools/path-utils.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/tools/tool-definition-wrapper.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/core/tools/truncate.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/index.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/main.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/index.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/interactive/components/diff.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/interactive/interactive-mode.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/print-mode.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/rpc/jsonl.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/rpc/rpc-client.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/rpc/rpc-mode.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/modes/rpc/rpc-types.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/ansi.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/changelog.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/child-process.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/clipboard-image.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/clipboard-native.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/clipboard.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/exif-orientation.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/frontmatter.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/fs-watch.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/git.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/html.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/image-convert.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/image-resize.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/mime.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/paths.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/photon.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/pi-user-agent.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/shell.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/sleep.js +0 -0
- /package/dist/{pi → sdk}/coding-agent/utils/syntax-highlight.js +0 -0
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ANSI escape code to HTML converter.
|
|
3
|
-
*
|
|
4
|
-
* Converts terminal ANSI color/style codes to HTML with inline styles.
|
|
5
|
-
* Supports:
|
|
6
|
-
* - Standard foreground colors (30-37) and bright variants (90-97)
|
|
7
|
-
* - Standard background colors (40-47) and bright variants (100-107)
|
|
8
|
-
* - 256-color palette (38;5;N and 48;5;N)
|
|
9
|
-
* - RGB true color (38;2;R;G;B and 48;2;R;G;B)
|
|
10
|
-
* - Text styles: bold (1), dim (2), italic (3), underline (4)
|
|
11
|
-
* - Reset (0)
|
|
12
|
-
*/
|
|
13
|
-
// Standard ANSI color palette (0-15)
|
|
14
|
-
const ANSI_COLORS = [
|
|
15
|
-
"#000000", // 0: black
|
|
16
|
-
"#800000", // 1: red
|
|
17
|
-
"#008000", // 2: green
|
|
18
|
-
"#808000", // 3: yellow
|
|
19
|
-
"#000080", // 4: blue
|
|
20
|
-
"#800080", // 5: magenta
|
|
21
|
-
"#008080", // 6: cyan
|
|
22
|
-
"#c0c0c0", // 7: white
|
|
23
|
-
"#808080", // 8: bright black
|
|
24
|
-
"#ff0000", // 9: bright red
|
|
25
|
-
"#00ff00", // 10: bright green
|
|
26
|
-
"#ffff00", // 11: bright yellow
|
|
27
|
-
"#0000ff", // 12: bright blue
|
|
28
|
-
"#ff00ff", // 13: bright magenta
|
|
29
|
-
"#00ffff", // 14: bright cyan
|
|
30
|
-
"#ffffff", // 15: bright white
|
|
31
|
-
];
|
|
32
|
-
/**
|
|
33
|
-
* Convert 256-color index to hex.
|
|
34
|
-
*/
|
|
35
|
-
function color256ToHex(index) {
|
|
36
|
-
// Standard colors (0-15)
|
|
37
|
-
if (index < 16) {
|
|
38
|
-
return ANSI_COLORS[index];
|
|
39
|
-
}
|
|
40
|
-
// Color cube (16-231): 6x6x6 = 216 colors
|
|
41
|
-
if (index < 232) {
|
|
42
|
-
const cubeIndex = index - 16;
|
|
43
|
-
const r = Math.floor(cubeIndex / 36);
|
|
44
|
-
const g = Math.floor((cubeIndex % 36) / 6);
|
|
45
|
-
const b = cubeIndex % 6;
|
|
46
|
-
const toComponent = (n) => (n === 0 ? 0 : 55 + n * 40);
|
|
47
|
-
const toHex = (n) => toComponent(n).toString(16).padStart(2, "0");
|
|
48
|
-
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
49
|
-
}
|
|
50
|
-
// Grayscale (232-255): 24 shades
|
|
51
|
-
const gray = 8 + (index - 232) * 10;
|
|
52
|
-
const grayHex = gray.toString(16).padStart(2, "0");
|
|
53
|
-
return `#${grayHex}${grayHex}${grayHex}`;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Escape HTML special characters.
|
|
57
|
-
*/
|
|
58
|
-
function escapeHtml(text) {
|
|
59
|
-
return text
|
|
60
|
-
.replace(/&/g, "&")
|
|
61
|
-
.replace(/</g, "<")
|
|
62
|
-
.replace(/>/g, ">")
|
|
63
|
-
.replace(/"/g, """)
|
|
64
|
-
.replace(/'/g, "'");
|
|
65
|
-
}
|
|
66
|
-
function createEmptyStyle() {
|
|
67
|
-
return {
|
|
68
|
-
fg: null,
|
|
69
|
-
bg: null,
|
|
70
|
-
bold: false,
|
|
71
|
-
dim: false,
|
|
72
|
-
italic: false,
|
|
73
|
-
underline: false,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
function styleToInlineCSS(style) {
|
|
77
|
-
const parts = [];
|
|
78
|
-
if (style.fg)
|
|
79
|
-
parts.push(`color:${style.fg}`);
|
|
80
|
-
if (style.bg)
|
|
81
|
-
parts.push(`background-color:${style.bg}`);
|
|
82
|
-
if (style.bold)
|
|
83
|
-
parts.push("font-weight:bold");
|
|
84
|
-
if (style.dim)
|
|
85
|
-
parts.push("opacity:0.6");
|
|
86
|
-
if (style.italic)
|
|
87
|
-
parts.push("font-style:italic");
|
|
88
|
-
if (style.underline)
|
|
89
|
-
parts.push("text-decoration:underline");
|
|
90
|
-
return parts.join(";");
|
|
91
|
-
}
|
|
92
|
-
function hasStyle(style) {
|
|
93
|
-
return style.fg !== null || style.bg !== null || style.bold || style.dim || style.italic || style.underline;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Parse ANSI SGR (Select Graphic Rendition) codes and update style.
|
|
97
|
-
*/
|
|
98
|
-
function applySgrCode(params, style) {
|
|
99
|
-
let i = 0;
|
|
100
|
-
while (i < params.length) {
|
|
101
|
-
const code = params[i];
|
|
102
|
-
if (code === 0) {
|
|
103
|
-
// Reset all
|
|
104
|
-
style.fg = null;
|
|
105
|
-
style.bg = null;
|
|
106
|
-
style.bold = false;
|
|
107
|
-
style.dim = false;
|
|
108
|
-
style.italic = false;
|
|
109
|
-
style.underline = false;
|
|
110
|
-
}
|
|
111
|
-
else if (code === 1) {
|
|
112
|
-
style.bold = true;
|
|
113
|
-
}
|
|
114
|
-
else if (code === 2) {
|
|
115
|
-
style.dim = true;
|
|
116
|
-
}
|
|
117
|
-
else if (code === 3) {
|
|
118
|
-
style.italic = true;
|
|
119
|
-
}
|
|
120
|
-
else if (code === 4) {
|
|
121
|
-
style.underline = true;
|
|
122
|
-
}
|
|
123
|
-
else if (code === 22) {
|
|
124
|
-
// Reset bold/dim
|
|
125
|
-
style.bold = false;
|
|
126
|
-
style.dim = false;
|
|
127
|
-
}
|
|
128
|
-
else if (code === 23) {
|
|
129
|
-
style.italic = false;
|
|
130
|
-
}
|
|
131
|
-
else if (code === 24) {
|
|
132
|
-
style.underline = false;
|
|
133
|
-
}
|
|
134
|
-
else if (code >= 30 && code <= 37) {
|
|
135
|
-
// Standard foreground colors
|
|
136
|
-
style.fg = ANSI_COLORS[code - 30];
|
|
137
|
-
}
|
|
138
|
-
else if (code === 38) {
|
|
139
|
-
// Extended foreground color
|
|
140
|
-
if (params[i + 1] === 5 && params.length > i + 2) {
|
|
141
|
-
// 256-color: 38;5;N
|
|
142
|
-
style.fg = color256ToHex(params[i + 2]);
|
|
143
|
-
i += 2;
|
|
144
|
-
}
|
|
145
|
-
else if (params[i + 1] === 2 && params.length > i + 4) {
|
|
146
|
-
// RGB: 38;2;R;G;B
|
|
147
|
-
const r = params[i + 2];
|
|
148
|
-
const g = params[i + 3];
|
|
149
|
-
const b = params[i + 4];
|
|
150
|
-
style.fg = `rgb(${r},${g},${b})`;
|
|
151
|
-
i += 4;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
else if (code === 39) {
|
|
155
|
-
// Default foreground
|
|
156
|
-
style.fg = null;
|
|
157
|
-
}
|
|
158
|
-
else if (code >= 40 && code <= 47) {
|
|
159
|
-
// Standard background colors
|
|
160
|
-
style.bg = ANSI_COLORS[code - 40];
|
|
161
|
-
}
|
|
162
|
-
else if (code === 48) {
|
|
163
|
-
// Extended background color
|
|
164
|
-
if (params[i + 1] === 5 && params.length > i + 2) {
|
|
165
|
-
// 256-color: 48;5;N
|
|
166
|
-
style.bg = color256ToHex(params[i + 2]);
|
|
167
|
-
i += 2;
|
|
168
|
-
}
|
|
169
|
-
else if (params[i + 1] === 2 && params.length > i + 4) {
|
|
170
|
-
// RGB: 48;2;R;G;B
|
|
171
|
-
const r = params[i + 2];
|
|
172
|
-
const g = params[i + 3];
|
|
173
|
-
const b = params[i + 4];
|
|
174
|
-
style.bg = `rgb(${r},${g},${b})`;
|
|
175
|
-
i += 4;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
else if (code === 49) {
|
|
179
|
-
// Default background
|
|
180
|
-
style.bg = null;
|
|
181
|
-
}
|
|
182
|
-
else if (code >= 90 && code <= 97) {
|
|
183
|
-
// Bright foreground colors
|
|
184
|
-
style.fg = ANSI_COLORS[code - 90 + 8];
|
|
185
|
-
}
|
|
186
|
-
else if (code >= 100 && code <= 107) {
|
|
187
|
-
// Bright background colors
|
|
188
|
-
style.bg = ANSI_COLORS[code - 100 + 8];
|
|
189
|
-
}
|
|
190
|
-
// Ignore unrecognized codes
|
|
191
|
-
i++;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
// Match ANSI escape sequences: ESC[ followed by params and ending with 'm'
|
|
195
|
-
const ANSI_REGEX = /\x1b\[([\d;]*)m/g;
|
|
196
|
-
/**
|
|
197
|
-
* Convert ANSI-escaped text to HTML with inline styles.
|
|
198
|
-
*/
|
|
199
|
-
export function ansiToHtml(text) {
|
|
200
|
-
const style = createEmptyStyle();
|
|
201
|
-
let result = "";
|
|
202
|
-
let lastIndex = 0;
|
|
203
|
-
let inSpan = false;
|
|
204
|
-
// Reset regex state
|
|
205
|
-
ANSI_REGEX.lastIndex = 0;
|
|
206
|
-
let match = ANSI_REGEX.exec(text);
|
|
207
|
-
while (match !== null) {
|
|
208
|
-
// Add text before this escape sequence
|
|
209
|
-
const beforeText = text.slice(lastIndex, match.index);
|
|
210
|
-
if (beforeText) {
|
|
211
|
-
result += escapeHtml(beforeText);
|
|
212
|
-
}
|
|
213
|
-
// Parse SGR parameters
|
|
214
|
-
const paramStr = match[1];
|
|
215
|
-
const params = paramStr ? paramStr.split(";").map((p) => parseInt(p, 10) || 0) : [0];
|
|
216
|
-
// Close existing span if we have one
|
|
217
|
-
if (inSpan) {
|
|
218
|
-
result += "</span>";
|
|
219
|
-
inSpan = false;
|
|
220
|
-
}
|
|
221
|
-
// Apply the codes
|
|
222
|
-
applySgrCode(params, style);
|
|
223
|
-
// Open new span if we have any styling
|
|
224
|
-
if (hasStyle(style)) {
|
|
225
|
-
result += `<span style="${styleToInlineCSS(style)}">`;
|
|
226
|
-
inSpan = true;
|
|
227
|
-
}
|
|
228
|
-
lastIndex = match.index + match[0].length;
|
|
229
|
-
match = ANSI_REGEX.exec(text);
|
|
230
|
-
}
|
|
231
|
-
// Add remaining text
|
|
232
|
-
const remainingText = text.slice(lastIndex);
|
|
233
|
-
if (remainingText) {
|
|
234
|
-
result += escapeHtml(remainingText);
|
|
235
|
-
}
|
|
236
|
-
// Close any open span
|
|
237
|
-
if (inSpan) {
|
|
238
|
-
result += "</span>";
|
|
239
|
-
}
|
|
240
|
-
return result;
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Convert array of ANSI-escaped lines to HTML.
|
|
244
|
-
* Each line is wrapped in a div element.
|
|
245
|
-
*/
|
|
246
|
-
export function ansiLinesToHtml(lines) {
|
|
247
|
-
return lines.map((line) => `<div class="ansi-line">${ansiToHtml(line) || " "}</div>`).join("");
|
|
248
|
-
}
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
-
import { basename, join } from "path";
|
|
3
|
-
import { APP_NAME, getExportTemplateDir } from "../../config.js";
|
|
4
|
-
import { getResolvedThemeColors, getThemeExportColors } from "../../modes/interactive/theme/theme.js";
|
|
5
|
-
import { normalizePath, resolvePath } from "../../utils/paths.js";
|
|
6
|
-
import { SessionManager } from "../session-manager.js";
|
|
7
|
-
/** Parse a color string to RGB values. Supports hex (#RRGGBB) and rgb(r,g,b) formats. */
|
|
8
|
-
function parseColor(color) {
|
|
9
|
-
const hexMatch = color.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);
|
|
10
|
-
if (hexMatch) {
|
|
11
|
-
return {
|
|
12
|
-
r: Number.parseInt(hexMatch[1], 16),
|
|
13
|
-
g: Number.parseInt(hexMatch[2], 16),
|
|
14
|
-
b: Number.parseInt(hexMatch[3], 16),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
const rgbMatch = color.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/);
|
|
18
|
-
if (rgbMatch) {
|
|
19
|
-
return {
|
|
20
|
-
r: Number.parseInt(rgbMatch[1], 10),
|
|
21
|
-
g: Number.parseInt(rgbMatch[2], 10),
|
|
22
|
-
b: Number.parseInt(rgbMatch[3], 10),
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
/** Calculate relative luminance of a color (0-1, higher = lighter). */
|
|
28
|
-
function getLuminance(r, g, b) {
|
|
29
|
-
const toLinear = (c) => {
|
|
30
|
-
const s = c / 255;
|
|
31
|
-
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
32
|
-
};
|
|
33
|
-
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
34
|
-
}
|
|
35
|
-
/** Adjust color brightness. Factor > 1 lightens, < 1 darkens. */
|
|
36
|
-
function adjustBrightness(color, factor) {
|
|
37
|
-
const parsed = parseColor(color);
|
|
38
|
-
if (!parsed)
|
|
39
|
-
return color;
|
|
40
|
-
const adjust = (c) => Math.min(255, Math.max(0, Math.round(c * factor)));
|
|
41
|
-
return `rgb(${adjust(parsed.r)}, ${adjust(parsed.g)}, ${adjust(parsed.b)})`;
|
|
42
|
-
}
|
|
43
|
-
/** Derive export background colors from a base color (e.g., userMessageBg). */
|
|
44
|
-
function deriveExportColors(baseColor) {
|
|
45
|
-
const parsed = parseColor(baseColor);
|
|
46
|
-
if (!parsed) {
|
|
47
|
-
return {
|
|
48
|
-
pageBg: "rgb(24, 24, 30)",
|
|
49
|
-
cardBg: "rgb(30, 30, 36)",
|
|
50
|
-
infoBg: "rgb(60, 55, 40)",
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
const luminance = getLuminance(parsed.r, parsed.g, parsed.b);
|
|
54
|
-
const isLight = luminance > 0.5;
|
|
55
|
-
if (isLight) {
|
|
56
|
-
return {
|
|
57
|
-
pageBg: adjustBrightness(baseColor, 0.96),
|
|
58
|
-
cardBg: baseColor,
|
|
59
|
-
infoBg: `rgb(${Math.min(255, parsed.r + 10)}, ${Math.min(255, parsed.g + 5)}, ${Math.max(0, parsed.b - 20)})`,
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
return {
|
|
63
|
-
pageBg: adjustBrightness(baseColor, 0.7),
|
|
64
|
-
cardBg: adjustBrightness(baseColor, 0.85),
|
|
65
|
-
infoBg: `rgb(${Math.min(255, parsed.r + 20)}, ${Math.min(255, parsed.g + 15)}, ${parsed.b})`,
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
/**
|
|
69
|
-
* Generate CSS custom property declarations from theme colors.
|
|
70
|
-
*/
|
|
71
|
-
function generateThemeVars(themeName) {
|
|
72
|
-
const colors = getResolvedThemeColors(themeName);
|
|
73
|
-
const lines = [];
|
|
74
|
-
for (const [key, value] of Object.entries(colors)) {
|
|
75
|
-
lines.push(`--${key}: ${value};`);
|
|
76
|
-
}
|
|
77
|
-
// Use explicit theme export colors if available, otherwise derive from userMessageBg
|
|
78
|
-
const themeExport = getThemeExportColors(themeName);
|
|
79
|
-
const userMessageBg = colors.userMessageBg || "#343541";
|
|
80
|
-
const derivedColors = deriveExportColors(userMessageBg);
|
|
81
|
-
lines.push(`--exportPageBg: ${themeExport.pageBg ?? derivedColors.pageBg};`);
|
|
82
|
-
lines.push(`--exportCardBg: ${themeExport.cardBg ?? derivedColors.cardBg};`);
|
|
83
|
-
lines.push(`--exportInfoBg: ${themeExport.infoBg ?? derivedColors.infoBg};`);
|
|
84
|
-
return lines.join("\n ");
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Core HTML generation logic shared by both export functions.
|
|
88
|
-
*/
|
|
89
|
-
function generateHtml(sessionData, themeName) {
|
|
90
|
-
const templateDir = getExportTemplateDir();
|
|
91
|
-
const template = readFileSync(join(templateDir, "template.html"), "utf-8");
|
|
92
|
-
const templateCss = readFileSync(join(templateDir, "template.css"), "utf-8");
|
|
93
|
-
const templateJs = readFileSync(join(templateDir, "template.js"), "utf-8");
|
|
94
|
-
const markedJs = readFileSync(join(templateDir, "vendor", "marked.min.js"), "utf-8");
|
|
95
|
-
const hljsJs = readFileSync(join(templateDir, "vendor", "highlight.min.js"), "utf-8");
|
|
96
|
-
const themeVars = generateThemeVars(themeName);
|
|
97
|
-
const colors = getResolvedThemeColors(themeName);
|
|
98
|
-
const themeExport = getThemeExportColors(themeName);
|
|
99
|
-
const derivedExportColors = deriveExportColors(colors.userMessageBg || "#343541");
|
|
100
|
-
const bodyBg = themeExport.pageBg ?? derivedExportColors.pageBg;
|
|
101
|
-
const containerBg = themeExport.cardBg ?? derivedExportColors.cardBg;
|
|
102
|
-
const infoBg = themeExport.infoBg ?? derivedExportColors.infoBg;
|
|
103
|
-
// Base64 encode session data to avoid escaping issues
|
|
104
|
-
const sessionDataBase64 = Buffer.from(JSON.stringify(sessionData)).toString("base64");
|
|
105
|
-
// Build the CSS with theme variables injected
|
|
106
|
-
const css = templateCss
|
|
107
|
-
.replace("{{THEME_VARS}}", themeVars)
|
|
108
|
-
.replace("{{BODY_BG}}", bodyBg)
|
|
109
|
-
.replace("{{CONTAINER_BG}}", containerBg)
|
|
110
|
-
.replace("{{INFO_BG}}", infoBg);
|
|
111
|
-
return template
|
|
112
|
-
.replace("{{CSS}}", css)
|
|
113
|
-
.replace("{{JS}}", templateJs)
|
|
114
|
-
.replace("{{SESSION_DATA}}", sessionDataBase64)
|
|
115
|
-
.replace("{{MARKED_JS}}", markedJs)
|
|
116
|
-
.replace("{{HIGHLIGHT_JS}}", hljsJs);
|
|
117
|
-
}
|
|
118
|
-
/** Tools rendered directly by the HTML template (not pre-rendered via TUI→ANSI→HTML pipeline) */
|
|
119
|
-
const TEMPLATE_RENDERED_TOOLS = new Set(["bash", "read", "write", "edit", "ls"]);
|
|
120
|
-
/**
|
|
121
|
-
* Pre-render custom tools to HTML using their TUI renderers.
|
|
122
|
-
*/
|
|
123
|
-
function preRenderCustomTools(entries, toolRenderer) {
|
|
124
|
-
const renderedTools = {};
|
|
125
|
-
for (const entry of entries) {
|
|
126
|
-
if (entry.type !== "message")
|
|
127
|
-
continue;
|
|
128
|
-
const msg = entry.message;
|
|
129
|
-
// Find tool calls in assistant messages
|
|
130
|
-
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
|
131
|
-
for (const block of msg.content) {
|
|
132
|
-
if (block.type === "toolCall" && !TEMPLATE_RENDERED_TOOLS.has(block.name)) {
|
|
133
|
-
const callHtml = toolRenderer.renderCall(block.id, block.name, block.arguments);
|
|
134
|
-
if (callHtml) {
|
|
135
|
-
renderedTools[block.id] = { callHtml };
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// Find tool results
|
|
141
|
-
if (msg.role === "toolResult" && msg.toolCallId) {
|
|
142
|
-
const toolName = msg.toolName || "";
|
|
143
|
-
// Only render if we have a pre-rendered call OR it's not template-rendered
|
|
144
|
-
const existing = renderedTools[msg.toolCallId];
|
|
145
|
-
if (existing || !TEMPLATE_RENDERED_TOOLS.has(toolName)) {
|
|
146
|
-
const rendered = toolRenderer.renderResult(msg.toolCallId, toolName, msg.content, msg.details, msg.isError || false);
|
|
147
|
-
if (rendered) {
|
|
148
|
-
renderedTools[msg.toolCallId] = {
|
|
149
|
-
...existing,
|
|
150
|
-
resultHtmlCollapsed: rendered.collapsed,
|
|
151
|
-
resultHtmlExpanded: rendered.expanded,
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return renderedTools;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Export session to HTML using SessionManager and AgentState.
|
|
161
|
-
* Used by TUI's /export command.
|
|
162
|
-
*/
|
|
163
|
-
export async function exportSessionToHtml(sm, state, options) {
|
|
164
|
-
const opts = typeof options === "string" ? { outputPath: options } : options || {};
|
|
165
|
-
const sessionFile = sm.getSessionFile();
|
|
166
|
-
if (!sessionFile) {
|
|
167
|
-
throw new Error("Cannot export in-memory session to HTML");
|
|
168
|
-
}
|
|
169
|
-
if (!existsSync(sessionFile)) {
|
|
170
|
-
throw new Error("Nothing to export yet - start a conversation first");
|
|
171
|
-
}
|
|
172
|
-
const entries = sm.getEntries();
|
|
173
|
-
// Pre-render custom tools if a tool renderer is provided
|
|
174
|
-
let renderedTools;
|
|
175
|
-
if (opts.toolRenderer) {
|
|
176
|
-
renderedTools = preRenderCustomTools(entries, opts.toolRenderer);
|
|
177
|
-
// Only include if we actually rendered something
|
|
178
|
-
if (Object.keys(renderedTools).length === 0) {
|
|
179
|
-
renderedTools = undefined;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
const sessionData = {
|
|
183
|
-
header: sm.getHeader(),
|
|
184
|
-
entries,
|
|
185
|
-
leafId: sm.getLeafId(),
|
|
186
|
-
systemPrompt: state?.systemPrompt,
|
|
187
|
-
tools: state?.tools?.map((t) => ({ name: t.name, description: t.description, parameters: t.parameters })),
|
|
188
|
-
renderedTools,
|
|
189
|
-
};
|
|
190
|
-
const html = generateHtml(sessionData, opts.themeName);
|
|
191
|
-
let outputPath = opts.outputPath ? normalizePath(opts.outputPath) : undefined;
|
|
192
|
-
if (!outputPath) {
|
|
193
|
-
const sessionBasename = basename(sessionFile, ".jsonl");
|
|
194
|
-
outputPath = `${APP_NAME}-session-${sessionBasename}.html`;
|
|
195
|
-
}
|
|
196
|
-
writeFileSync(outputPath, html, "utf8");
|
|
197
|
-
return outputPath;
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Export session file to HTML (standalone, without AgentState).
|
|
201
|
-
* Used by CLI for exporting arbitrary session files.
|
|
202
|
-
*/
|
|
203
|
-
export async function exportFromFile(inputPath, options) {
|
|
204
|
-
const opts = typeof options === "string" ? { outputPath: options } : options || {};
|
|
205
|
-
const resolvedInputPath = resolvePath(inputPath);
|
|
206
|
-
if (!existsSync(resolvedInputPath)) {
|
|
207
|
-
throw new Error(`File not found: ${resolvedInputPath}`);
|
|
208
|
-
}
|
|
209
|
-
const sm = SessionManager.open(resolvedInputPath);
|
|
210
|
-
const sessionData = {
|
|
211
|
-
header: sm.getHeader(),
|
|
212
|
-
entries: sm.getEntries(),
|
|
213
|
-
leafId: sm.getLeafId(),
|
|
214
|
-
systemPrompt: undefined,
|
|
215
|
-
tools: undefined,
|
|
216
|
-
};
|
|
217
|
-
const html = generateHtml(sessionData, opts.themeName);
|
|
218
|
-
let outputPath = opts.outputPath ? normalizePath(opts.outputPath) : undefined;
|
|
219
|
-
if (!outputPath) {
|
|
220
|
-
const inputBasename = basename(resolvedInputPath, ".jsonl");
|
|
221
|
-
outputPath = `${APP_NAME}-session-${inputBasename}.html`;
|
|
222
|
-
}
|
|
223
|
-
writeFileSync(outputPath, html, "utf8");
|
|
224
|
-
return outputPath;
|
|
225
|
-
}
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tool HTML renderer for custom tools in HTML export.
|
|
3
|
-
*
|
|
4
|
-
* Renders custom tool calls and results to HTML by invoking their TUI renderers
|
|
5
|
-
* and converting the ANSI output to HTML.
|
|
6
|
-
*/
|
|
7
|
-
import { ansiLinesToHtml } from "./ansi-to-html.js";
|
|
8
|
-
/**
|
|
9
|
-
* Create a tool HTML renderer.
|
|
10
|
-
*
|
|
11
|
-
* The renderer looks up tool definitions and invokes their renderCall/renderResult
|
|
12
|
-
* methods, converting the resulting TUI Component output (ANSI) to HTML.
|
|
13
|
-
*/
|
|
14
|
-
const ANSI_ESCAPE_REGEX = /\x1b\[[\d;]*m/g;
|
|
15
|
-
function isBlankRenderedLine(line) {
|
|
16
|
-
return line.replace(ANSI_ESCAPE_REGEX, "").trim().length === 0;
|
|
17
|
-
}
|
|
18
|
-
function trimRenderedResultLines(lines) {
|
|
19
|
-
let start = 0;
|
|
20
|
-
let end = lines.length;
|
|
21
|
-
while (start < end && isBlankRenderedLine(lines[start]))
|
|
22
|
-
start++;
|
|
23
|
-
while (end > start && isBlankRenderedLine(lines[end - 1]))
|
|
24
|
-
end--;
|
|
25
|
-
return lines.slice(start, end);
|
|
26
|
-
}
|
|
27
|
-
export function createToolHtmlRenderer(deps) {
|
|
28
|
-
const { getToolDefinition, theme, cwd, width = 100 } = deps;
|
|
29
|
-
const renderedCallComponents = new Map();
|
|
30
|
-
const renderedResultComponents = new Map();
|
|
31
|
-
const renderedStates = new Map();
|
|
32
|
-
const renderedArgs = new Map();
|
|
33
|
-
const getState = (toolCallId) => {
|
|
34
|
-
let state = renderedStates.get(toolCallId);
|
|
35
|
-
if (!state) {
|
|
36
|
-
state = {};
|
|
37
|
-
renderedStates.set(toolCallId, state);
|
|
38
|
-
}
|
|
39
|
-
return state;
|
|
40
|
-
};
|
|
41
|
-
const createRenderContext = (toolCallId, lastComponent, expanded, isPartial, isError) => {
|
|
42
|
-
return {
|
|
43
|
-
args: renderedArgs.get(toolCallId),
|
|
44
|
-
toolCallId,
|
|
45
|
-
invalidate: () => { },
|
|
46
|
-
lastComponent,
|
|
47
|
-
state: getState(toolCallId),
|
|
48
|
-
cwd,
|
|
49
|
-
executionStarted: true,
|
|
50
|
-
argsComplete: true,
|
|
51
|
-
isPartial,
|
|
52
|
-
expanded,
|
|
53
|
-
showImages: false,
|
|
54
|
-
isError,
|
|
55
|
-
};
|
|
56
|
-
};
|
|
57
|
-
return {
|
|
58
|
-
renderCall(toolCallId, toolName, args) {
|
|
59
|
-
try {
|
|
60
|
-
renderedArgs.set(toolCallId, args);
|
|
61
|
-
const toolDef = getToolDefinition(toolName);
|
|
62
|
-
if (!toolDef?.renderCall) {
|
|
63
|
-
return undefined;
|
|
64
|
-
}
|
|
65
|
-
const component = toolDef.renderCall(args, theme, createRenderContext(toolCallId, renderedCallComponents.get(toolCallId), false, true, false));
|
|
66
|
-
renderedCallComponents.set(toolCallId, component);
|
|
67
|
-
const lines = component.render(width);
|
|
68
|
-
return ansiLinesToHtml(lines);
|
|
69
|
-
}
|
|
70
|
-
catch {
|
|
71
|
-
// On error, return undefined so HTML export can fall back to structured result rendering
|
|
72
|
-
return undefined;
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
renderResult(toolCallId, toolName, result, details, isError) {
|
|
76
|
-
try {
|
|
77
|
-
const toolDef = getToolDefinition(toolName);
|
|
78
|
-
if (!toolDef?.renderResult) {
|
|
79
|
-
return undefined;
|
|
80
|
-
}
|
|
81
|
-
// Build AgentToolResult from content array
|
|
82
|
-
// Cast content since session storage uses generic object types
|
|
83
|
-
const agentToolResult = {
|
|
84
|
-
content: result,
|
|
85
|
-
details,
|
|
86
|
-
isError,
|
|
87
|
-
};
|
|
88
|
-
// Render collapsed
|
|
89
|
-
const collapsedComponent = toolDef.renderResult(agentToolResult, { expanded: false, isPartial: false }, theme, createRenderContext(toolCallId, renderedResultComponents.get(toolCallId), false, false, isError));
|
|
90
|
-
renderedResultComponents.set(toolCallId, collapsedComponent);
|
|
91
|
-
const collapsed = ansiLinesToHtml(trimRenderedResultLines(collapsedComponent.render(width)));
|
|
92
|
-
// Render expanded
|
|
93
|
-
const expandedComponent = toolDef.renderResult(agentToolResult, { expanded: true, isPartial: false }, theme, createRenderContext(toolCallId, renderedResultComponents.get(toolCallId), true, false, isError));
|
|
94
|
-
renderedResultComponents.set(toolCallId, expandedComponent);
|
|
95
|
-
const expanded = ansiLinesToHtml(trimRenderedResultLines(expandedComponent.render(width)));
|
|
96
|
-
return {
|
|
97
|
-
...(collapsed && collapsed !== expanded ? { collapsed } : {}),
|
|
98
|
-
expanded,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
// On error, return undefined so HTML export can fall back to structured result rendering
|
|
103
|
-
return undefined;
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared utility for truncating text to visual lines (accounting for line wrapping).
|
|
3
|
-
* Used by both tool-execution.ts and bash-execution.ts for consistent behavior.
|
|
4
|
-
*/
|
|
5
|
-
import { Text } from "../../../../tui/index.js";
|
|
6
|
-
/**
|
|
7
|
-
* Truncate text to a maximum number of visual lines (from the end).
|
|
8
|
-
* This accounts for line wrapping based on terminal width.
|
|
9
|
-
*
|
|
10
|
-
* @param text - The text content (may contain newlines)
|
|
11
|
-
* @param maxVisualLines - Maximum number of visual lines to show
|
|
12
|
-
* @param width - Terminal/render width
|
|
13
|
-
* @param paddingX - Horizontal padding for Text component (default 0).
|
|
14
|
-
* Use 0 when result will be placed in a Box (Box adds its own padding).
|
|
15
|
-
* Use 1 when result will be placed in a plain Container.
|
|
16
|
-
* @returns The truncated visual lines and count of skipped lines
|
|
17
|
-
*/
|
|
18
|
-
export function truncateToVisualLines(text, maxVisualLines, width, paddingX = 0) {
|
|
19
|
-
if (!text) {
|
|
20
|
-
return { visualLines: [], skippedCount: 0 };
|
|
21
|
-
}
|
|
22
|
-
// Create a temporary Text component to render and get visual lines
|
|
23
|
-
const tempText = new Text(text, paddingX, 0);
|
|
24
|
-
const allVisualLines = tempText.render(width);
|
|
25
|
-
if (allVisualLines.length <= maxVisualLines) {
|
|
26
|
-
return { visualLines: allVisualLines, skippedCount: 0 };
|
|
27
|
-
}
|
|
28
|
-
// Take the last N visual lines
|
|
29
|
-
const truncatedLines = allVisualLines.slice(-maxVisualLines);
|
|
30
|
-
const skippedCount = allVisualLines.length - maxVisualLines;
|
|
31
|
-
return { visualLines: truncatedLines, skippedCount };
|
|
32
|
-
}
|