codebase-cli 2.0.0-pre.12 → 2.0.0-pre.19
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/agent.js +1 -0
- package/dist/agent/agent.js.map +1 -1
- package/dist/cli.js +19 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/builtins.js +44 -5
- package/dist/commands/builtins.js.map +1 -1
- package/dist/commands/registry.js +46 -1
- package/dist/commands/registry.js.map +1 -1
- package/dist/ui/App.js +121 -12
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/FirstRunSetup.js +3 -5
- package/dist/ui/FirstRunSetup.js.map +1 -1
- package/dist/ui/Input.js +245 -13
- package/dist/ui/Input.js.map +1 -1
- package/dist/ui/Markdown.js +286 -0
- package/dist/ui/Markdown.js.map +1 -0
- package/dist/ui/Message.js +192 -24
- package/dist/ui/Message.js.map +1 -1
- package/dist/ui/PixelC.js +12 -27
- package/dist/ui/PixelC.js.map +1 -1
- package/dist/ui/Status.js +201 -6
- package/dist/ui/Status.js.map +1 -1
- package/dist/ui/Welcome.js +45 -2
- package/dist/ui/Welcome.js.map +1 -1
- package/dist/ui/attachments.js +68 -0
- package/dist/ui/attachments.js.map +1 -0
- package/dist/ui/debug-input.js +44 -0
- package/dist/ui/debug-input.js.map +1 -0
- package/dist/ui/highlight.js +324 -0
- package/dist/ui/highlight.js.map +1 -0
- package/dist/ui/history-store.js +60 -0
- package/dist/ui/history-store.js.map +1 -0
- package/dist/ui/path-complete.js +102 -0
- package/dist/ui/path-complete.js.map +1 -0
- package/dist/ui/terminal-restore.js +83 -0
- package/dist/ui/terminal-restore.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { colorForKind, highlight, rulesFor } from "./highlight.js";
|
|
4
|
+
import { wrapText } from "./wrap.js";
|
|
5
|
+
export function Markdown({ text, width, keyPrefix }) {
|
|
6
|
+
const blocks = parseBlocks(text);
|
|
7
|
+
return (_jsx(Box, { flexDirection: "column", children: blocks.map((block, i) => (_jsx(MarkdownBlock, { block: block, width: width, keyPrefix: `${keyPrefix}-${i}` }, `${keyPrefix}-${i}-${block.kind}`))) }));
|
|
8
|
+
}
|
|
9
|
+
function MarkdownBlock({ block, width, keyPrefix }) {
|
|
10
|
+
if (block.kind === "blank") {
|
|
11
|
+
return _jsx(Text, { children: " " });
|
|
12
|
+
}
|
|
13
|
+
if (block.kind === "code-block") {
|
|
14
|
+
return _jsx(HighlightedCodeBlock, { text: block.text, lang: block.lang, keyPrefix: keyPrefix });
|
|
15
|
+
}
|
|
16
|
+
if (block.kind === "heading") {
|
|
17
|
+
return _jsx(SpanLine, { spans: block.spans, width: width, bold: true, color: "cyan", keyPrefix: keyPrefix });
|
|
18
|
+
}
|
|
19
|
+
if (block.kind === "list") {
|
|
20
|
+
return (_jsx(Box, { flexDirection: "column", children: block.items.map((item, i) => (_jsx(ListRow, { item: item, width: width, keyPrefix: `${keyPrefix}-li-${i}` }, `${keyPrefix}-li-${i}-${item.marker}`))) }));
|
|
21
|
+
}
|
|
22
|
+
if (block.kind === "quote") {
|
|
23
|
+
// Use SpanLine to preserve inline styling, but wrap in a left-bar gutter
|
|
24
|
+
// so block-quotes read like one in a terminal.
|
|
25
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Box, { marginRight: 1, children: _jsx(Text, { dimColor: true, children: "\u2502" }) }), _jsx(Box, { flexDirection: "column", flexGrow: 1, children: _jsx(SpanLine, { spans: block.spans, width: Math.max(20, width - 2), keyPrefix: keyPrefix, dim: true }) })] }));
|
|
26
|
+
}
|
|
27
|
+
return _jsx(SpanLine, { spans: block.spans, width: width, keyPrefix: keyPrefix });
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Render a fenced code block with regex-based syntax highlighting if
|
|
31
|
+
* the language is recognized. Walks the token list and splits on \n so
|
|
32
|
+
* the per-line key invariant from the rest of the renderer holds.
|
|
33
|
+
* Unsupported languages render in the original cyan tone.
|
|
34
|
+
*/
|
|
35
|
+
function HighlightedCodeBlock({ text, lang, keyPrefix, }) {
|
|
36
|
+
const rules = rulesFor(lang);
|
|
37
|
+
if (!rules) {
|
|
38
|
+
const lines = text.split("\n");
|
|
39
|
+
return (_jsx(Box, { flexDirection: "column", marginLeft: 2, children: lines.map((line, i) => (_jsx(Text, { color: "cyan", children: line.length === 0 ? " " : line }, `${keyPrefix}-cl-${i}-${line.slice(0, 12)}`))) }));
|
|
40
|
+
}
|
|
41
|
+
// Split the highlighted token stream into per-line rows so the
|
|
42
|
+
// columns stay aligned with the surrounding markdown and the keys
|
|
43
|
+
// stay stable.
|
|
44
|
+
const rows = [[]];
|
|
45
|
+
for (const tok of highlight(text, lang)) {
|
|
46
|
+
const color = colorForKind(tok.kind);
|
|
47
|
+
const parts = tok.text.split("\n");
|
|
48
|
+
for (let i = 0; i < parts.length; i++) {
|
|
49
|
+
if (i > 0)
|
|
50
|
+
rows.push([]);
|
|
51
|
+
if (parts[i].length > 0)
|
|
52
|
+
rows[rows.length - 1].push({ color, text: parts[i] });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return (_jsx(Box, { flexDirection: "column", marginLeft: 2, children: rows.map((row, i) => {
|
|
56
|
+
const previewKey = row
|
|
57
|
+
.map((c) => c.text)
|
|
58
|
+
.join("")
|
|
59
|
+
.slice(0, 12);
|
|
60
|
+
return (_jsx(Text, { children: row.length === 0
|
|
61
|
+
? " "
|
|
62
|
+
: row.map((c, ci) => (
|
|
63
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: pure presentational
|
|
64
|
+
_jsx(Text, { color: c.color, children: c.text }, `${keyPrefix}-hl-${i}-c${ci}`))) }, `${keyPrefix}-hl-${i}-${previewKey}`));
|
|
65
|
+
}) }));
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* One list-item row: marker in cyan (e.g. "•" / "1.") + the item body
|
|
69
|
+
* wrapped to the remaining width, with continuation lines indented
|
|
70
|
+
* under the body so wrapped lines hang neatly past the marker.
|
|
71
|
+
*/
|
|
72
|
+
function ListRow({ item, width, keyPrefix }) {
|
|
73
|
+
const markerCol = item.marker.length + 1; // marker + the gap space
|
|
74
|
+
const indentCols = item.indent * 2;
|
|
75
|
+
const bodyWidth = Math.max(10, width - markerCol - indentCols);
|
|
76
|
+
const plain = item.spans.map((s) => s.text).join("");
|
|
77
|
+
const wrapped = bodyWidth > 0 ? wrapText(plain, bodyWidth) : [plain];
|
|
78
|
+
let consumed = 0;
|
|
79
|
+
return (_jsx(Box, { flexDirection: "column", children: wrapped.map((line, lineIdx) => {
|
|
80
|
+
const chunks = sliceSpans(item.spans, consumed, consumed + line.length);
|
|
81
|
+
consumed += line.length;
|
|
82
|
+
if (lineIdx < wrapped.length - 1 && plain[consumed] === " ")
|
|
83
|
+
consumed += 1;
|
|
84
|
+
const rowKey = `${keyPrefix}-row-${lineIdx}-${line.slice(0, 8)}`;
|
|
85
|
+
return (_jsxs(Box, { flexDirection: "row", children: [_jsx(Text, { children: " ".repeat(indentCols) }), lineIdx === 0 ? _jsxs(Text, { color: "cyan", children: [item.marker, " "] }) : _jsx(Text, { children: " ".repeat(markerCol) }), _jsx(Box, { flexGrow: 1, children: _jsx(Text, { children: chunks.map((c, ci) => (_jsx(Text
|
|
86
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: ci is a stable position within a single wrapped row; reusing instances is harmless
|
|
87
|
+
, { bold: c.kind === "bold", italic: c.kind === "italic", color: c.kind === "code" ? "cyan" : undefined, children: c.text }, `${rowKey}-c${ci}`))) }) })] }, rowKey));
|
|
88
|
+
}) }));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Render a sequence of inline spans, wrapped to `width`. We wrap on
|
|
92
|
+
* the plain-text representation, then walk the spans in parallel to
|
|
93
|
+
* decide where to break and what styling each chunk gets. This keeps
|
|
94
|
+
* select-copy clean while preserving styled segments across line
|
|
95
|
+
* breaks.
|
|
96
|
+
*/
|
|
97
|
+
function SpanLine({ spans, width, bold, color, dim, keyPrefix, }) {
|
|
98
|
+
// For the first cut: serialize spans into one rich-text line, wrap
|
|
99
|
+
// the plain projection, and emit one <Text> per row with all spans
|
|
100
|
+
// inlined. Wrap calculation uses the plain text so column counts
|
|
101
|
+
// stay accurate; the rendered output retains the styling.
|
|
102
|
+
const plain = spans.map((s) => s.text).join("");
|
|
103
|
+
const wrapped = wrapText(plain, width);
|
|
104
|
+
let consumed = 0;
|
|
105
|
+
return (_jsx(_Fragment, { children: wrapped.map((line, lineIdx) => {
|
|
106
|
+
const chunks = sliceSpans(spans, consumed, consumed + line.length);
|
|
107
|
+
consumed += line.length;
|
|
108
|
+
// Account for the line break (wrap-ansi drops the trailing space).
|
|
109
|
+
if (lineIdx < wrapped.length - 1 && plain[consumed] === " ")
|
|
110
|
+
consumed += 1;
|
|
111
|
+
const rowKey = `${keyPrefix}-r-${lineIdx}-${line.slice(0, 12)}`;
|
|
112
|
+
return (_jsx(Text, { children: chunks.map((c, ci) => (_jsx(Text
|
|
113
|
+
// biome-ignore lint/suspicious/noArrayIndexKey: ci is a stable position within a single wrapped row
|
|
114
|
+
, { bold: bold || c.kind === "bold", italic: c.kind === "italic", dimColor: dim, color: c.kind === "code" ? "cyan" : color, children: c.text }, `${rowKey}-c${ci}`))) }, rowKey));
|
|
115
|
+
}) }));
|
|
116
|
+
}
|
|
117
|
+
/** Slice the span sequence to the [start, end) range of the plain projection. */
|
|
118
|
+
function sliceSpans(spans, start, end) {
|
|
119
|
+
const out = [];
|
|
120
|
+
let cursor = 0;
|
|
121
|
+
for (const span of spans) {
|
|
122
|
+
const spanEnd = cursor + span.text.length;
|
|
123
|
+
if (spanEnd <= start) {
|
|
124
|
+
cursor = spanEnd;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (cursor >= end)
|
|
128
|
+
break;
|
|
129
|
+
const sliceStart = Math.max(0, start - cursor);
|
|
130
|
+
const sliceEnd = Math.min(span.text.length, end - cursor);
|
|
131
|
+
out.push({ kind: span.kind, text: span.text.slice(sliceStart, sliceEnd) });
|
|
132
|
+
cursor = spanEnd;
|
|
133
|
+
}
|
|
134
|
+
return out;
|
|
135
|
+
}
|
|
136
|
+
// ── parsing ─────────────────────────────────────────────────────────
|
|
137
|
+
function parseBlocks(text) {
|
|
138
|
+
const blocks = [];
|
|
139
|
+
const lines = text.split("\n");
|
|
140
|
+
let i = 0;
|
|
141
|
+
while (i < lines.length) {
|
|
142
|
+
const line = lines[i];
|
|
143
|
+
// Fenced code block.
|
|
144
|
+
const fence = line.match(/^```(.*)$/);
|
|
145
|
+
if (fence) {
|
|
146
|
+
const lang = fence[1].trim() || undefined;
|
|
147
|
+
const body = [];
|
|
148
|
+
i++;
|
|
149
|
+
while (i < lines.length && !lines[i].match(/^```\s*$/)) {
|
|
150
|
+
body.push(lines[i]);
|
|
151
|
+
i++;
|
|
152
|
+
}
|
|
153
|
+
i++; // skip closing fence (or EOF)
|
|
154
|
+
blocks.push({ kind: "code-block", lang, text: body.join("\n") });
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
// Blank line.
|
|
158
|
+
if (line.trim() === "") {
|
|
159
|
+
blocks.push({ kind: "blank" });
|
|
160
|
+
i++;
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
// Heading.
|
|
164
|
+
const heading = line.match(/^(#{1,3})\s+(.+)$/);
|
|
165
|
+
if (heading) {
|
|
166
|
+
const level = heading[1].length;
|
|
167
|
+
blocks.push({ kind: "heading", level, spans: parseInline(heading[2]) });
|
|
168
|
+
i++;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
// List (bulleted or ordered). Consumes consecutive list rows + any
|
|
172
|
+
// continuation lines that are deeper-indented than the list marker.
|
|
173
|
+
const listProbe = matchListLine(line);
|
|
174
|
+
if (listProbe) {
|
|
175
|
+
const items = [];
|
|
176
|
+
let ordered = listProbe.ordered;
|
|
177
|
+
while (i < lines.length) {
|
|
178
|
+
const row = matchListLine(lines[i]);
|
|
179
|
+
if (!row)
|
|
180
|
+
break;
|
|
181
|
+
ordered = ordered || row.ordered;
|
|
182
|
+
const itemLines = [row.body];
|
|
183
|
+
i++;
|
|
184
|
+
// Continuation lines: indented, non-empty, non-list rows.
|
|
185
|
+
while (i < lines.length) {
|
|
186
|
+
const peek = lines[i];
|
|
187
|
+
if (peek.trim() === "")
|
|
188
|
+
break;
|
|
189
|
+
if (matchListLine(peek))
|
|
190
|
+
break;
|
|
191
|
+
if (peek.match(/^#{1,3}\s+/))
|
|
192
|
+
break;
|
|
193
|
+
if (peek.match(/^```/))
|
|
194
|
+
break;
|
|
195
|
+
itemLines.push(peek.trim());
|
|
196
|
+
i++;
|
|
197
|
+
}
|
|
198
|
+
items.push({
|
|
199
|
+
marker: row.marker,
|
|
200
|
+
indent: row.indent,
|
|
201
|
+
spans: parseInline(itemLines.join(" ")),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
blocks.push({ kind: "list", ordered, items });
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
// Block-quote (single-line for now; runs collapse on blank line).
|
|
208
|
+
if (line.match(/^>\s?/)) {
|
|
209
|
+
const quoteLines = [line.replace(/^>\s?/, "")];
|
|
210
|
+
i++;
|
|
211
|
+
while (i < lines.length && lines[i].match(/^>\s?/)) {
|
|
212
|
+
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
213
|
+
i++;
|
|
214
|
+
}
|
|
215
|
+
blocks.push({ kind: "quote", spans: parseInline(quoteLines.join(" ")) });
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
// Paragraph (consume until blank line, fence, list, quote, or heading).
|
|
219
|
+
const paraLines = [line];
|
|
220
|
+
i++;
|
|
221
|
+
while (i < lines.length) {
|
|
222
|
+
const peek = lines[i];
|
|
223
|
+
if (peek.trim() === "")
|
|
224
|
+
break;
|
|
225
|
+
if (peek.match(/^```/))
|
|
226
|
+
break;
|
|
227
|
+
if (peek.match(/^#{1,3}\s+/))
|
|
228
|
+
break;
|
|
229
|
+
if (matchListLine(peek))
|
|
230
|
+
break;
|
|
231
|
+
if (peek.match(/^>\s?/))
|
|
232
|
+
break;
|
|
233
|
+
paraLines.push(peek);
|
|
234
|
+
i++;
|
|
235
|
+
}
|
|
236
|
+
blocks.push({ kind: "paragraph", spans: parseInline(paraLines.join(" ")) });
|
|
237
|
+
}
|
|
238
|
+
return blocks;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Detect a list row and return its marker, body, indent depth, and
|
|
242
|
+
* kind. Matches `- foo`, `* foo`, `+ foo`, and ordered `12. foo`. The
|
|
243
|
+
* leading-whitespace count maps to a 2-space-per-level indent: 0 or 1
|
|
244
|
+
* leading spaces stay at level 0, 2-3 → 1, 4-5 → 2, etc.
|
|
245
|
+
*/
|
|
246
|
+
function matchListLine(line) {
|
|
247
|
+
const m = line.match(/^(\s*)([-*+]|\d+\.)\s+(.*)$/);
|
|
248
|
+
if (!m)
|
|
249
|
+
return null;
|
|
250
|
+
const indent = Math.floor(m[1].length / 2);
|
|
251
|
+
const raw = m[2];
|
|
252
|
+
const ordered = /^\d+\./.test(raw);
|
|
253
|
+
const marker = ordered ? raw : "•";
|
|
254
|
+
return { marker, body: m[3], indent, ordered };
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Split a single line of inline text into styled spans. Greedy, non-
|
|
258
|
+
* nested — `**bold _italic_**` doesn't render correctly, but plain
|
|
259
|
+
* `**bold**` and `*italic*` and `` `code` `` all work, which is what
|
|
260
|
+
* 95% of real responses look like.
|
|
261
|
+
*/
|
|
262
|
+
function parseInline(text) {
|
|
263
|
+
const spans = [];
|
|
264
|
+
const pattern = /(\*\*(.+?)\*\*|`([^`]+?)`|\*([^*\s][^*]*?)\*)/g;
|
|
265
|
+
let lastIndex = 0;
|
|
266
|
+
for (const match of text.matchAll(pattern)) {
|
|
267
|
+
const matchStart = match.index ?? 0;
|
|
268
|
+
if (matchStart > lastIndex) {
|
|
269
|
+
spans.push({ kind: "text", text: text.slice(lastIndex, matchStart) });
|
|
270
|
+
}
|
|
271
|
+
if (match[2] !== undefined)
|
|
272
|
+
spans.push({ kind: "bold", text: match[2] });
|
|
273
|
+
else if (match[3] !== undefined)
|
|
274
|
+
spans.push({ kind: "code", text: match[3] });
|
|
275
|
+
else if (match[4] !== undefined)
|
|
276
|
+
spans.push({ kind: "italic", text: match[4] });
|
|
277
|
+
lastIndex = matchStart + match[0].length;
|
|
278
|
+
}
|
|
279
|
+
if (lastIndex < text.length) {
|
|
280
|
+
spans.push({ kind: "text", text: text.slice(lastIndex) });
|
|
281
|
+
}
|
|
282
|
+
if (spans.length === 0)
|
|
283
|
+
spans.push({ kind: "text", text });
|
|
284
|
+
return spans;
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=Markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Markdown.js","sourceRoot":"","sources":["../../src/ui/Markdown.tsx"],"names":[],"mappings":"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"}
|
package/dist/ui/Message.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { sep as pathSep, relative as relativePath } from "node:path";
|
|
2
3
|
import { Box, Text } from "ink";
|
|
3
4
|
import { useEffect, useState } from "react";
|
|
5
|
+
import { Markdown } from "./Markdown.js";
|
|
4
6
|
import { wrapText } from "./wrap.js";
|
|
5
7
|
const SPINNER_FRAMES = ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
|
|
6
8
|
function useSpinner(active, intervalMs = 90) {
|
|
@@ -31,29 +33,20 @@ export function Message({ message, streaming, width = 80, tools }) {
|
|
|
31
33
|
}
|
|
32
34
|
function MessageBody({ message, width, tools, }) {
|
|
33
35
|
if (message.role === "user") {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
if (typeof message.content === "string") {
|
|
37
|
+
return _jsx(WrappedLines, { text: message.content, width: width, keyPrefix: "user" });
|
|
38
|
+
}
|
|
39
|
+
return _jsx(UserBlocks, { blocks: message.content, width: width });
|
|
36
40
|
}
|
|
37
41
|
if (message.role === "assistant") {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (block.type === "text") {
|
|
41
|
-
return _jsx(WrappedLines, { text: block.text, width: width, keyPrefix: key }, key);
|
|
42
|
-
}
|
|
43
|
-
if (block.type === "thinking") {
|
|
44
|
-
return (_jsx(WrappedLines, { text: `(thinking) ${block.thinking}`, width: width, keyPrefix: key, dimColor: true, italic: true }, key));
|
|
45
|
-
}
|
|
46
|
-
if (block.type === "toolCall") {
|
|
47
|
-
return (_jsx(ToolCallLine, { id: block.id, name: block.name, args: block.arguments, width: width, keyPrefix: key, tools: tools }, key));
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
50
|
-
}), message.errorMessage ? (_jsx(WrappedLines, { text: `! ${message.errorMessage}`, width: width, keyPrefix: "err", color: "red" })) : null] }));
|
|
42
|
+
const rendered = renderAssistantBlocks(message.content, width, tools);
|
|
43
|
+
return (_jsxs(_Fragment, { children: [rendered, message.errorMessage ? (_jsx(WrappedLines, { text: `! ${message.errorMessage}`, width: width, keyPrefix: "err", color: "red" })) : null] }));
|
|
51
44
|
}
|
|
52
45
|
if (message.role === "toolResult") {
|
|
53
46
|
const text = message.content
|
|
54
47
|
.map((block) => (block.type === "text" ? block.text : `[image:${block.mimeType}]`))
|
|
55
48
|
.join("");
|
|
56
|
-
return _jsx(
|
|
49
|
+
return _jsx(TruncatedOutput, { text: text, width: width, keyPrefix: "tool", color: message.isError ? "red" : undefined });
|
|
57
50
|
}
|
|
58
51
|
return null;
|
|
59
52
|
}
|
|
@@ -82,6 +75,119 @@ function ToolCallLine({ id, name, args, width, keyPrefix, tools, }) {
|
|
|
82
75
|
const diff = !isError ? diffSummary(name, args) : null;
|
|
83
76
|
return (_jsxs(_Fragment, { children: [_jsx(WrappedLines, { text: `${glyph} ${past}`, width: width, keyPrefix: keyPrefix, color: isError ? "red" : "magenta" }), diff ? _jsx(DiffSummary, { diff: diff, width: width, keyPrefix: `${keyPrefix}-diff` }) : null] }));
|
|
84
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Tool calls that are pure reads — runs of these collapse into a single
|
|
80
|
+
* "Read N files" / "Searched 3 patterns" line, the Claude Code pattern.
|
|
81
|
+
* Keep the set tight: anything that mutates state, runs shell, or has a
|
|
82
|
+
* meaningful argument shape (grep query, fetch URL) reads weird when
|
|
83
|
+
* collapsed and stays per-row.
|
|
84
|
+
*/
|
|
85
|
+
const COLLAPSIBLE_READ_TOOLS = new Set(["read_file"]);
|
|
86
|
+
/**
|
|
87
|
+
* Walk an assistant message's content blocks, collapsing runs of
|
|
88
|
+
* consecutive `read_file` (and other safe read-only) tool calls into a
|
|
89
|
+
* single summary row. A run only collapses when every call in it is
|
|
90
|
+
* completed (done or errored) — if any is still running we render the
|
|
91
|
+
* group expanded so the spinner stays visible on the active row.
|
|
92
|
+
*/
|
|
93
|
+
function renderAssistantBlocks(content, width, tools) {
|
|
94
|
+
const out = [];
|
|
95
|
+
let i = 0;
|
|
96
|
+
while (i < content.length) {
|
|
97
|
+
const block = content[i];
|
|
98
|
+
const key = blockKey(block, i);
|
|
99
|
+
if (block.type === "text") {
|
|
100
|
+
out.push(_jsx(Markdown, { text: block.text, width: width, keyPrefix: key }, key));
|
|
101
|
+
i++;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (block.type === "thinking") {
|
|
105
|
+
out.push(_jsx(WrappedLines, { text: `(thinking) ${block.thinking}`, width: width, keyPrefix: key, dimColor: true, italic: true }, key));
|
|
106
|
+
i++;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (block.type === "toolCall") {
|
|
110
|
+
if (COLLAPSIBLE_READ_TOOLS.has(block.name)) {
|
|
111
|
+
let runEnd = i + 1;
|
|
112
|
+
while (runEnd < content.length) {
|
|
113
|
+
const next = content[runEnd];
|
|
114
|
+
if (next.type !== "toolCall" || next.name !== block.name)
|
|
115
|
+
break;
|
|
116
|
+
runEnd++;
|
|
117
|
+
}
|
|
118
|
+
const run = [];
|
|
119
|
+
for (let j = i; j < runEnd; j++) {
|
|
120
|
+
const b = content[j];
|
|
121
|
+
if (b.type === "toolCall")
|
|
122
|
+
run.push(b);
|
|
123
|
+
}
|
|
124
|
+
if (run.length >= 2) {
|
|
125
|
+
out.push(_jsx(CollapsedReadGroup, { calls: run, width: width, keyPrefix: `run-${run[0].id}`, tools: tools }, `run-${run[0].id}`));
|
|
126
|
+
i = runEnd;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
out.push(_jsx(ToolCallLine, { id: block.id, name: block.name, args: block.arguments, width: width, keyPrefix: key, tools: tools }, key));
|
|
131
|
+
i++;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
i++;
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
function CollapsedReadGroup({ calls, width, keyPrefix, tools, }) {
|
|
139
|
+
const statuses = calls.map((c) => tools?.get(c.id)?.status);
|
|
140
|
+
const anyRunning = statuses.some((s) => s === "running");
|
|
141
|
+
const anyError = statuses.some((s) => s === "error");
|
|
142
|
+
const doneCount = statuses.filter((s) => s !== "running").length;
|
|
143
|
+
const spinner = useSpinner(anyRunning);
|
|
144
|
+
const glyph = anyRunning ? spinner : anyError ? "✗" : "✓";
|
|
145
|
+
const color = anyError ? "red" : "magenta";
|
|
146
|
+
const verb = anyRunning ? presentVerbForReadTool(calls[0].name) : pastVerbForReadTool(calls[0].name);
|
|
147
|
+
const noun = nounForReadTool(calls[0].name, calls.length);
|
|
148
|
+
const header = anyRunning
|
|
149
|
+
? `${glyph} ${verb} ${doneCount} of ${calls.length} ${noun}…`
|
|
150
|
+
: `${glyph} ${verb} ${calls.length} ${noun}`;
|
|
151
|
+
return (_jsxs(_Fragment, { children: [_jsx(WrappedLines, { text: header, width: width, keyPrefix: keyPrefix, color: color }), _jsx(Box, { flexDirection: "column", marginLeft: 2, children: calls.map((c) => {
|
|
152
|
+
const a = (c.arguments ?? {});
|
|
153
|
+
const rawPath = typeof a.path === "string" ? a.path : typeof a.file_path === "string" ? a.file_path : "";
|
|
154
|
+
const path = displayPath(rawPath);
|
|
155
|
+
const status = tools?.get(c.id)?.status;
|
|
156
|
+
const failed = status === "error";
|
|
157
|
+
const running = status === "running";
|
|
158
|
+
const marker = failed ? " ✗ " : running ? " → " : " · ";
|
|
159
|
+
return (_jsxs(Text, { color: failed ? "red" : running ? "magenta" : undefined, dimColor: !failed && !running, children: [marker, truncate(path, Math.max(20, width - 6))] }, `${keyPrefix}-f-${c.id}`));
|
|
160
|
+
}) })] }));
|
|
161
|
+
}
|
|
162
|
+
function presentVerbForReadTool(name) {
|
|
163
|
+
if (name === "read_file")
|
|
164
|
+
return "Reading";
|
|
165
|
+
if (name === "list_files")
|
|
166
|
+
return "Listing";
|
|
167
|
+
if (name === "glob")
|
|
168
|
+
return "Searching";
|
|
169
|
+
if (name === "grep")
|
|
170
|
+
return "Grepping";
|
|
171
|
+
return "Running";
|
|
172
|
+
}
|
|
173
|
+
function pastVerbForReadTool(name) {
|
|
174
|
+
if (name === "read_file")
|
|
175
|
+
return "Read";
|
|
176
|
+
if (name === "list_files")
|
|
177
|
+
return "Listed";
|
|
178
|
+
if (name === "glob")
|
|
179
|
+
return "Searched";
|
|
180
|
+
if (name === "grep")
|
|
181
|
+
return "Grepped";
|
|
182
|
+
return "Ran";
|
|
183
|
+
}
|
|
184
|
+
function nounForReadTool(name, count) {
|
|
185
|
+
if (name === "read_file")
|
|
186
|
+
return count === 1 ? "file" : "files";
|
|
187
|
+
if (name === "list_files")
|
|
188
|
+
return count === 1 ? "directory" : "directories";
|
|
189
|
+
return count === 1 ? "call" : "calls";
|
|
190
|
+
}
|
|
85
191
|
/**
|
|
86
192
|
* Build a diff summary for a completed file-edit tool call from the
|
|
87
193
|
* tool's args. We have old_string + new_string right there, so no
|
|
@@ -150,6 +256,26 @@ function DiffSummary({ diff, width, keyPrefix }) {
|
|
|
150
256
|
const counts = ` +${diff.added} -${diff.removed}`;
|
|
151
257
|
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsx(Text, { dimColor: true, children: counts }), diff.hunks.map((h) => (_jsxs(Box, { flexDirection: "column", children: [h.minus ? (_jsxs(Text, { color: "red", children: [" - ", truncate(h.minus, Math.max(20, width - 8))] })) : null, h.plus ? (_jsxs(Text, { color: "green", children: [" + ", truncate(h.plus, Math.max(20, width - 8))] })) : null] }, `${keyPrefix}-h-${h.minus.slice(0, 16)}-${h.plus.slice(0, 16)}`)))] }));
|
|
152
258
|
}
|
|
259
|
+
const MAX_TOOL_OUTPUT_LINES = 12;
|
|
260
|
+
const HEAD_TOOL_OUTPUT_LINES = 8;
|
|
261
|
+
const TAIL_TOOL_OUTPUT_LINES = 3;
|
|
262
|
+
/**
|
|
263
|
+
* Truncate tool output past MAX_TOOL_OUTPUT_LINES into "head + (N hidden)
|
|
264
|
+
* + tail" — long shell or grep output otherwise dominates the
|
|
265
|
+
* transcript and pushes context off-screen. The agent still gets the
|
|
266
|
+
* full output; this is purely a display trim. Errors are NEVER
|
|
267
|
+
* truncated since the user needs to see exactly what blew up.
|
|
268
|
+
*/
|
|
269
|
+
function TruncatedOutput({ text, width, keyPrefix, color, }) {
|
|
270
|
+
const lines = text.split("\n");
|
|
271
|
+
if (color === "red" || lines.length <= MAX_TOOL_OUTPUT_LINES) {
|
|
272
|
+
return _jsx(WrappedLines, { text: text, width: width, keyPrefix: keyPrefix, color: color });
|
|
273
|
+
}
|
|
274
|
+
const head = lines.slice(0, HEAD_TOOL_OUTPUT_LINES).join("\n");
|
|
275
|
+
const tail = lines.slice(lines.length - TAIL_TOOL_OUTPUT_LINES).join("\n");
|
|
276
|
+
const hidden = lines.length - HEAD_TOOL_OUTPUT_LINES - TAIL_TOOL_OUTPUT_LINES;
|
|
277
|
+
return (_jsxs(_Fragment, { children: [_jsx(WrappedLines, { text: head, width: width, keyPrefix: `${keyPrefix}-h`, color: color }), _jsx(Text, { dimColor: true, children: `… ${hidden} line${hidden === 1 ? "" : "s"} hidden …` }), _jsx(WrappedLines, { text: tail, width: width, keyPrefix: `${keyPrefix}-t`, color: color })] }));
|
|
278
|
+
}
|
|
153
279
|
/**
|
|
154
280
|
* Render text as N <Text> elements, one per pre-wrapped line. Stacks
|
|
155
281
|
* vertically inside the parent column-flex Box. Pre-wrap means the
|
|
@@ -164,12 +290,36 @@ function WrappedLines({ text, width, keyPrefix, color, dimColor, italic }) {
|
|
|
164
290
|
// biome-ignore lint/suspicious/noArrayIndexKey: stateless leaf, reuse is safe
|
|
165
291
|
_jsx(Text, { color: color, dimColor: dimColor, italic: italic, children: line.length === 0 ? " " : line }, `${keyPrefix}:${i}`))) }));
|
|
166
292
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
293
|
+
/**
|
|
294
|
+
* Render an array-content user message — typically text + one or more
|
|
295
|
+
* image attachments. Text blocks pass through `WrappedLines`; image
|
|
296
|
+
* blocks render as a dim "image (PNG, 142 KB)" line so the user can
|
|
297
|
+
* see at a glance that an image was sent.
|
|
298
|
+
*/
|
|
299
|
+
function UserBlocks({ blocks, width }) {
|
|
300
|
+
if (!Array.isArray(blocks))
|
|
301
|
+
return null;
|
|
302
|
+
const rows = [];
|
|
303
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
304
|
+
const b = blocks[i];
|
|
305
|
+
if (b.type === "text" && b.text) {
|
|
306
|
+
rows.push(_jsx(WrappedLines, { text: b.text, width: width, keyPrefix: `u-t-${i}` }, `u-t-${i}`));
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (b.type === "image") {
|
|
310
|
+
const subtype = (b.mimeType ?? "image/?").split("/")[1]?.toUpperCase() ?? "?";
|
|
311
|
+
const size = b.data ? formatBytes(Math.floor((b.data.length * 3) / 4)) : "";
|
|
312
|
+
rows.push(_jsxs(Text, { dimColor: true, children: ["\uD83D\uDCF7 image (", subtype, size ? `, ${size}` : "", ")"] }, `u-i-${i}`));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return _jsx(_Fragment, { children: rows });
|
|
316
|
+
}
|
|
317
|
+
function formatBytes(n) {
|
|
318
|
+
if (n < 1024)
|
|
319
|
+
return `${n} B`;
|
|
320
|
+
if (n < 1024 * 1024)
|
|
321
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
322
|
+
return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
173
323
|
}
|
|
174
324
|
/**
|
|
175
325
|
* Stable key per assistant content block. Tool calls have an id; text and
|
|
@@ -201,7 +351,7 @@ function summarizeArgs(args) {
|
|
|
201
351
|
function toolActionLabel(name, args) {
|
|
202
352
|
const a = (args ?? {});
|
|
203
353
|
const str = (k) => (typeof a[k] === "string" ? a[k] : "");
|
|
204
|
-
const path = str("path") || str("file_path");
|
|
354
|
+
const path = displayPath(str("path") || str("file_path"));
|
|
205
355
|
switch (name) {
|
|
206
356
|
case "read_file":
|
|
207
357
|
return `Reading ${path}`;
|
|
@@ -270,6 +420,24 @@ function truncate(s, n) {
|
|
|
270
420
|
return s;
|
|
271
421
|
return `${s.slice(0, n - 1)}…`;
|
|
272
422
|
}
|
|
423
|
+
/**
|
|
424
|
+
* Show a path relative to the working directory when it's inside (so
|
|
425
|
+
* "src/ui/Message.tsx" instead of "/home/half/.../src/ui/Message.tsx"),
|
|
426
|
+
* but keep it absolute when it points outside the project — that's
|
|
427
|
+
* useful information the user should see at full fidelity. Empty
|
|
428
|
+
* strings pass through unchanged.
|
|
429
|
+
*/
|
|
430
|
+
function displayPath(p) {
|
|
431
|
+
if (!p)
|
|
432
|
+
return p;
|
|
433
|
+
if (!p.startsWith(pathSep))
|
|
434
|
+
return p; // already relative
|
|
435
|
+
const cwd = process.cwd();
|
|
436
|
+
const rel = relativePath(cwd, p);
|
|
437
|
+
if (!rel || rel.startsWith(".."))
|
|
438
|
+
return p; // outside cwd — keep absolute
|
|
439
|
+
return rel;
|
|
440
|
+
}
|
|
273
441
|
/**
|
|
274
442
|
* Past-tense action label, used when a tool has finished. Same shape
|
|
275
443
|
* as `toolActionLabel` but with the verbs swapped to past tense:
|
|
@@ -278,7 +446,7 @@ function truncate(s, n) {
|
|
|
278
446
|
function toolActionPast(name, args) {
|
|
279
447
|
const a = (args ?? {});
|
|
280
448
|
const str = (k) => (typeof a[k] === "string" ? a[k] : "");
|
|
281
|
-
const path = str("path") || str("file_path");
|
|
449
|
+
const path = displayPath(str("path") || str("file_path"));
|
|
282
450
|
switch (name) {
|
|
283
451
|
case "read_file":
|
|
284
452
|
return `Read ${path}`;
|