@jun133/kitty 0.0.11 → 0.0.12
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/README.md +95 -90
- package/dist/{App-6FETP3LH.mjs → App-V6SLDWQH.mjs} +39 -5
- package/dist/chunk-4HIVDFN5.mjs +823 -0
- package/dist/{chunk-ELBEXOR7.mjs → chunk-MV5BYUNW.mjs} +293 -1
- package/dist/{chunk-6NJJLOY3.mjs → chunk-TISOA5U6.mjs} +85 -3
- package/dist/{chunk-YSWK3BGL.mjs → chunk-TOBF3KV3.mjs} +1 -1
- package/dist/cli.js +491 -45
- package/dist/cli.js.map +1 -1
- package/dist/{interactive-KLW4JL7R.mjs → interactive-WYSTB4UQ.mjs} +3 -3
- package/dist/{oneShot-YHDMPFQM.mjs → oneShot-INJ27LNB.mjs} +2 -2
- package/dist/tui.mjs +90 -10
- package/package.json +1 -1
- package/dist/chunk-DFDOKON5.mjs +0 -530
package/dist/chunk-DFDOKON5.mjs
DELETED
|
@@ -1,530 +0,0 @@
|
|
|
1
|
-
// src/shell/tui/theme.ts
|
|
2
|
-
var TUI_COLORS = {
|
|
3
|
-
background: "#080808",
|
|
4
|
-
panel: "#191919",
|
|
5
|
-
panelStrong: "#222222",
|
|
6
|
-
border: "#303030",
|
|
7
|
-
muted: "#8d8d8d",
|
|
8
|
-
text: "#e5e7eb",
|
|
9
|
-
user: "#d6a84f",
|
|
10
|
-
assistant: "#e5e7eb",
|
|
11
|
-
reasoning: "#a8a8a8",
|
|
12
|
-
thought: "#c99a3f",
|
|
13
|
-
system: "#cbd5e1",
|
|
14
|
-
success: "#34d399",
|
|
15
|
-
warning: "#d6a84f",
|
|
16
|
-
error: "#f87171"
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
// src/shell/tui/transcriptLayout.ts
|
|
20
|
-
import wrapAnsi from "wrap-ansi";
|
|
21
|
-
import stringWidth from "string-width";
|
|
22
|
-
|
|
23
|
-
// src/shell/tui/markdown.ts
|
|
24
|
-
import { marked } from "marked";
|
|
25
|
-
function renderMarkdownLines(markdown) {
|
|
26
|
-
const tokens = marked.lexer(markdown, {
|
|
27
|
-
gfm: true
|
|
28
|
-
});
|
|
29
|
-
const lines = [];
|
|
30
|
-
for (const token of tokens) {
|
|
31
|
-
appendToken(lines, token);
|
|
32
|
-
}
|
|
33
|
-
return trimOuterBlankLines(lines);
|
|
34
|
-
}
|
|
35
|
-
function appendToken(lines, token) {
|
|
36
|
-
switch (token.type) {
|
|
37
|
-
case "heading":
|
|
38
|
-
push(lines, "heading", inlineText(token.text));
|
|
39
|
-
pushBlank(lines);
|
|
40
|
-
return;
|
|
41
|
-
case "paragraph":
|
|
42
|
-
push(lines, "text", inlineText(token.text));
|
|
43
|
-
pushBlank(lines);
|
|
44
|
-
return;
|
|
45
|
-
case "list":
|
|
46
|
-
appendList(lines, token);
|
|
47
|
-
pushBlank(lines);
|
|
48
|
-
return;
|
|
49
|
-
case "code":
|
|
50
|
-
appendCode(lines, token);
|
|
51
|
-
pushBlank(lines);
|
|
52
|
-
return;
|
|
53
|
-
case "blockquote":
|
|
54
|
-
appendBlockquote(lines, token);
|
|
55
|
-
pushBlank(lines);
|
|
56
|
-
return;
|
|
57
|
-
case "hr":
|
|
58
|
-
push(lines, "rule", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
59
|
-
pushBlank(lines);
|
|
60
|
-
return;
|
|
61
|
-
case "space":
|
|
62
|
-
pushBlank(lines);
|
|
63
|
-
return;
|
|
64
|
-
case "table":
|
|
65
|
-
appendTable(lines, token);
|
|
66
|
-
pushBlank(lines);
|
|
67
|
-
return;
|
|
68
|
-
default:
|
|
69
|
-
if (typeof token.raw === "string" && token.raw.trim()) {
|
|
70
|
-
push(lines, "text", stripMarkdownInline(token.raw));
|
|
71
|
-
pushBlank(lines);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function appendList(lines, token) {
|
|
76
|
-
const start = typeof token.start === "number" ? token.start : Number.parseInt(String(token.start ?? 1), 10);
|
|
77
|
-
const orderedStart = Number.isFinite(start) ? start : 1;
|
|
78
|
-
token.items.forEach((item, index) => {
|
|
79
|
-
const marker = token.ordered ? `${orderedStart + index}.` : "\u2022";
|
|
80
|
-
const text = inlineText(item.text);
|
|
81
|
-
const itemLines = text.split("\n");
|
|
82
|
-
push(lines, "list", `${marker} ${itemLines[0] ?? ""}`);
|
|
83
|
-
for (const line of itemLines.slice(1)) {
|
|
84
|
-
push(lines, "list", ` ${line}`);
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
function appendCode(lines, token) {
|
|
89
|
-
for (const line of token.text.split(/\r?\n/)) {
|
|
90
|
-
push(lines, "code", line);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
function appendBlockquote(lines, token) {
|
|
94
|
-
const nested = renderMarkdownLines(token.text);
|
|
95
|
-
for (const line of nested) {
|
|
96
|
-
push(lines, "quote", line.text ? `\u2502 ${line.text}` : "\u2502");
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
function appendTable(lines, token) {
|
|
100
|
-
const header = token.header.map((cell) => inlineText(cell.text));
|
|
101
|
-
const rows = token.rows.map((row) => row.map((cell) => inlineText(cell.text)));
|
|
102
|
-
const widths = header.map((cell, index) => Math.max(
|
|
103
|
-
cell.length,
|
|
104
|
-
...rows.map((row) => row[index]?.length ?? 0)
|
|
105
|
-
));
|
|
106
|
-
push(lines, "table", joinTableRow(header, widths));
|
|
107
|
-
push(lines, "table", widths.map((width) => "\u2500".repeat(Math.max(3, width))).join("\u2500\u253C\u2500"));
|
|
108
|
-
for (const row of token.rows) {
|
|
109
|
-
push(lines, "table", joinTableRow(row.map((cell) => inlineText(cell.text)), widths));
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
function joinTableRow(cells, widths) {
|
|
113
|
-
return cells.map((cell, index) => cell.padEnd(widths[index] ?? cell.length)).join(" \u2502 ");
|
|
114
|
-
}
|
|
115
|
-
function inlineText(text) {
|
|
116
|
-
return stripMarkdownInline(text).replace(/\s+\n/g, "\n").trimEnd();
|
|
117
|
-
}
|
|
118
|
-
function stripMarkdownInline(text) {
|
|
119
|
-
return text.replace(/!\[([^\]]*)\]\([^)]+\)/g, "$1").replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1 ($2)").replace(/`([^`]+)`/g, "$1").replace(/\*\*([^*]+)\*\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/_([^_]+)_/g, "$1").replace(/~~([^~]+)~~/g, "$1").replace(/<br\s*\/?>/gi, "\n").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
120
|
-
}
|
|
121
|
-
function push(lines, kind, text) {
|
|
122
|
-
lines.push({ kind, text });
|
|
123
|
-
}
|
|
124
|
-
function pushBlank(lines) {
|
|
125
|
-
push(lines, "text", "");
|
|
126
|
-
}
|
|
127
|
-
function trimOuterBlankLines(lines) {
|
|
128
|
-
let start = 0;
|
|
129
|
-
let end = lines.length;
|
|
130
|
-
while (start < end && lines[start]?.text === "") {
|
|
131
|
-
start += 1;
|
|
132
|
-
}
|
|
133
|
-
while (end > start && lines[end - 1]?.text === "") {
|
|
134
|
-
end -= 1;
|
|
135
|
-
}
|
|
136
|
-
return lines.slice(start, end);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// src/shell/tui/transcriptLayout.ts
|
|
140
|
-
var TRANSCRIPT_OUTER_PADDING_X = 3;
|
|
141
|
-
var MIN_BODY_WIDTH = 8;
|
|
142
|
-
var REASONING_PREFIX = "Thinking: ";
|
|
143
|
-
function renderTranscriptLineViews(entries, viewportWidth, theme) {
|
|
144
|
-
return entries.flatMap((entry) => renderEntryLineViews(entry, viewportWidth, theme));
|
|
145
|
-
}
|
|
146
|
-
function measureTranscriptRows(entries, viewportWidth, theme) {
|
|
147
|
-
return renderTranscriptLineViews(entries, viewportWidth, theme).length;
|
|
148
|
-
}
|
|
149
|
-
function renderEntryLineViews(entry, viewportWidth, theme) {
|
|
150
|
-
const frame = readRoleFrame(entry.role, viewportWidth);
|
|
151
|
-
const style = readRoleStyle(entry.role, theme);
|
|
152
|
-
const sourceRows = readEntryDisplayRows(entry);
|
|
153
|
-
const contentRows = wrapEntryRows(entry, sourceRows, frame.bodyWidth);
|
|
154
|
-
const rows = contentRows.length > 0 ? contentRows : [{ markdownKind: void 0, prefix: "", text: "" }];
|
|
155
|
-
const entryId = entry.id;
|
|
156
|
-
return [
|
|
157
|
-
{
|
|
158
|
-
id: `${entryId}-spacer`,
|
|
159
|
-
entryId,
|
|
160
|
-
role: entry.role,
|
|
161
|
-
kind: "spacer",
|
|
162
|
-
text: "",
|
|
163
|
-
prefix: "",
|
|
164
|
-
markdownKind: void 0,
|
|
165
|
-
isFirstContentLine: false,
|
|
166
|
-
frame,
|
|
167
|
-
style
|
|
168
|
-
},
|
|
169
|
-
...rows.map((row, index) => ({
|
|
170
|
-
id: `${entryId}-line-${index + 1}`,
|
|
171
|
-
entryId,
|
|
172
|
-
role: entry.role,
|
|
173
|
-
kind: "content",
|
|
174
|
-
text: row.text,
|
|
175
|
-
prefix: row.prefix,
|
|
176
|
-
markdownKind: row.markdownKind,
|
|
177
|
-
isFirstContentLine: index === 0,
|
|
178
|
-
frame,
|
|
179
|
-
style: applyMarkdownStyle(style, row.markdownKind, theme)
|
|
180
|
-
}))
|
|
181
|
-
];
|
|
182
|
-
}
|
|
183
|
-
function readRoleFrame(role, viewportWidth) {
|
|
184
|
-
const frameWidth = Math.max(1, viewportWidth - TRANSCRIPT_OUTER_PADDING_X * 2);
|
|
185
|
-
const base = readRoleFrameBase(role);
|
|
186
|
-
const bodyWidth = Math.max(
|
|
187
|
-
MIN_BODY_WIDTH,
|
|
188
|
-
frameWidth - base.marginLeft - base.paddingLeft - base.paddingRight - stringWidth(base.gutter) - base.gap
|
|
189
|
-
);
|
|
190
|
-
return {
|
|
191
|
-
...base,
|
|
192
|
-
bodyWidth
|
|
193
|
-
};
|
|
194
|
-
}
|
|
195
|
-
function readRoleFrameBase(role) {
|
|
196
|
-
switch (role) {
|
|
197
|
-
case "user":
|
|
198
|
-
return {
|
|
199
|
-
gap: 2,
|
|
200
|
-
gutter: "\u2503",
|
|
201
|
-
marginLeft: 1,
|
|
202
|
-
paddingLeft: 1,
|
|
203
|
-
paddingRight: 1
|
|
204
|
-
};
|
|
205
|
-
case "reasoning":
|
|
206
|
-
return {
|
|
207
|
-
gap: 2,
|
|
208
|
-
gutter: "\u2503",
|
|
209
|
-
marginLeft: 1,
|
|
210
|
-
paddingLeft: 1,
|
|
211
|
-
paddingRight: 1
|
|
212
|
-
};
|
|
213
|
-
case "system":
|
|
214
|
-
return {
|
|
215
|
-
gap: 2,
|
|
216
|
-
gutter: "\u2502",
|
|
217
|
-
marginLeft: 2,
|
|
218
|
-
paddingLeft: 1,
|
|
219
|
-
paddingRight: 1
|
|
220
|
-
};
|
|
221
|
-
case "assistant":
|
|
222
|
-
return {
|
|
223
|
-
gap: 2,
|
|
224
|
-
gutter: " ",
|
|
225
|
-
marginLeft: 2,
|
|
226
|
-
paddingLeft: 1,
|
|
227
|
-
paddingRight: 1
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
function readRoleStyle(role, theme) {
|
|
232
|
-
switch (role) {
|
|
233
|
-
case "user":
|
|
234
|
-
return {
|
|
235
|
-
accent: theme.user,
|
|
236
|
-
background: theme.panelStrong,
|
|
237
|
-
text: theme.text,
|
|
238
|
-
bold: true,
|
|
239
|
-
dim: false,
|
|
240
|
-
italicPrefix: false
|
|
241
|
-
};
|
|
242
|
-
case "reasoning":
|
|
243
|
-
return {
|
|
244
|
-
accent: theme.border,
|
|
245
|
-
background: void 0,
|
|
246
|
-
text: theme.reasoning,
|
|
247
|
-
bold: false,
|
|
248
|
-
dim: true,
|
|
249
|
-
italicPrefix: true
|
|
250
|
-
};
|
|
251
|
-
case "system":
|
|
252
|
-
return {
|
|
253
|
-
accent: theme.border,
|
|
254
|
-
background: theme.panel,
|
|
255
|
-
text: theme.system,
|
|
256
|
-
bold: false,
|
|
257
|
-
dim: false,
|
|
258
|
-
italicPrefix: false
|
|
259
|
-
};
|
|
260
|
-
case "assistant":
|
|
261
|
-
return {
|
|
262
|
-
accent: theme.background,
|
|
263
|
-
background: void 0,
|
|
264
|
-
text: theme.assistant,
|
|
265
|
-
bold: false,
|
|
266
|
-
dim: false,
|
|
267
|
-
italicPrefix: false
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
function readEntryDisplayRows(entry) {
|
|
272
|
-
if (entry.role === "assistant" || entry.role === "reasoning") {
|
|
273
|
-
const markdownRows = renderMarkdownLines(entry.text);
|
|
274
|
-
return markdownRows.length > 0 ? markdownRows.map((row) => ({ markdownKind: row.kind, text: row.text })) : [{ markdownKind: void 0, text: "" }];
|
|
275
|
-
}
|
|
276
|
-
return entry.text.split(/\r?\n/).map((text) => ({ markdownKind: void 0, text }));
|
|
277
|
-
}
|
|
278
|
-
function wrapEntryRows(entry, sourceRows, bodyWidth) {
|
|
279
|
-
if (entry.role !== "reasoning") {
|
|
280
|
-
return sourceRows.flatMap((line) => wrapText(line.text, bodyWidth).map((text) => ({
|
|
281
|
-
markdownKind: line.markdownKind,
|
|
282
|
-
prefix: "",
|
|
283
|
-
text
|
|
284
|
-
})));
|
|
285
|
-
}
|
|
286
|
-
const rows = [];
|
|
287
|
-
const firstBodyWidth = Math.max(1, bodyWidth - stringWidth(REASONING_PREFIX));
|
|
288
|
-
sourceRows.forEach((line, sourceIndex) => {
|
|
289
|
-
const width = sourceIndex === 0 ? firstBodyWidth : bodyWidth;
|
|
290
|
-
const wrapped = wrapText(line.text, width);
|
|
291
|
-
wrapped.forEach((text, wrappedIndex) => {
|
|
292
|
-
rows.push({
|
|
293
|
-
markdownKind: line.markdownKind,
|
|
294
|
-
prefix: sourceIndex === 0 && wrappedIndex === 0 ? REASONING_PREFIX : "",
|
|
295
|
-
text
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
});
|
|
299
|
-
return rows;
|
|
300
|
-
}
|
|
301
|
-
function wrapText(text, width) {
|
|
302
|
-
const rows = [];
|
|
303
|
-
for (const line of text.split(/\r?\n/)) {
|
|
304
|
-
const wrapped = wrapAnsi(line, width, { hard: true, trim: false });
|
|
305
|
-
rows.push(...wrapped.split(/\r?\n/));
|
|
306
|
-
}
|
|
307
|
-
return rows.length > 0 ? rows : [""];
|
|
308
|
-
}
|
|
309
|
-
function applyMarkdownStyle(base, kind, theme) {
|
|
310
|
-
switch (kind) {
|
|
311
|
-
case "heading":
|
|
312
|
-
return {
|
|
313
|
-
...base,
|
|
314
|
-
text: theme.user,
|
|
315
|
-
bold: true
|
|
316
|
-
};
|
|
317
|
-
case "code":
|
|
318
|
-
return {
|
|
319
|
-
...base,
|
|
320
|
-
background: theme.panel,
|
|
321
|
-
text: theme.system
|
|
322
|
-
};
|
|
323
|
-
case "quote":
|
|
324
|
-
return {
|
|
325
|
-
...base,
|
|
326
|
-
text: theme.reasoning,
|
|
327
|
-
dim: true
|
|
328
|
-
};
|
|
329
|
-
case "rule":
|
|
330
|
-
case "table":
|
|
331
|
-
return {
|
|
332
|
-
...base,
|
|
333
|
-
text: theme.muted
|
|
334
|
-
};
|
|
335
|
-
case "list":
|
|
336
|
-
case "text":
|
|
337
|
-
case void 0:
|
|
338
|
-
return base;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// src/shell/tui/store.ts
|
|
343
|
-
var DEFAULT_DOCK = {
|
|
344
|
-
work: {
|
|
345
|
-
active: false,
|
|
346
|
-
label: "\u7A7A\u95F2",
|
|
347
|
-
detail: "\u6CA1\u6709\u540E\u53F0\u4EFB\u52A1\u6216\u5B50\u4EE3\u7406\u6B63\u5728\u6267\u884C"
|
|
348
|
-
},
|
|
349
|
-
background: "\u7A7A\u95F2",
|
|
350
|
-
subagent: "\u7A7A\u95F2",
|
|
351
|
-
context: "0 chars (0%)"
|
|
352
|
-
};
|
|
353
|
-
function createInitialTuiState(session) {
|
|
354
|
-
return {
|
|
355
|
-
transcript: session ? session.messages.flatMap(toTranscriptEntry) : [],
|
|
356
|
-
dock: {
|
|
357
|
-
...DEFAULT_DOCK,
|
|
358
|
-
context: formatContextBudget(session)
|
|
359
|
-
},
|
|
360
|
-
scroll: {
|
|
361
|
-
offset: 0,
|
|
362
|
-
stickToBottom: true,
|
|
363
|
-
newContentPending: false
|
|
364
|
-
},
|
|
365
|
-
composer: {
|
|
366
|
-
promptLabel: "> ",
|
|
367
|
-
visibleRows: 1
|
|
368
|
-
}
|
|
369
|
-
};
|
|
370
|
-
}
|
|
371
|
-
function appendTranscriptEntry(state, entry, viewport) {
|
|
372
|
-
const next = {
|
|
373
|
-
...state,
|
|
374
|
-
transcript: [...state.transcript, { ...entry, id: createEntryId(state.transcript.length) }]
|
|
375
|
-
};
|
|
376
|
-
return applyContentChange(next, viewport);
|
|
377
|
-
}
|
|
378
|
-
function appendTranscriptText(state, role, text, viewport) {
|
|
379
|
-
const last = state.transcript[state.transcript.length - 1];
|
|
380
|
-
if (last && last.role === role && (role === "assistant" || role === "reasoning")) {
|
|
381
|
-
const transcript = state.transcript.slice(0, -1);
|
|
382
|
-
const next = {
|
|
383
|
-
...state,
|
|
384
|
-
transcript: [...transcript, { ...last, text: `${last.text}${text}` }]
|
|
385
|
-
};
|
|
386
|
-
return applyContentChange(next, viewport);
|
|
387
|
-
}
|
|
388
|
-
return appendTranscriptEntry(state, { role, text }, viewport);
|
|
389
|
-
}
|
|
390
|
-
function updateRuntimeDock(state, dock) {
|
|
391
|
-
return {
|
|
392
|
-
...state,
|
|
393
|
-
dock: {
|
|
394
|
-
...state.dock,
|
|
395
|
-
...dock,
|
|
396
|
-
work: {
|
|
397
|
-
...state.dock.work,
|
|
398
|
-
...dock.work
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
function updateComposerState(state, composer) {
|
|
404
|
-
return {
|
|
405
|
-
...state,
|
|
406
|
-
composer: {
|
|
407
|
-
...state.composer,
|
|
408
|
-
...composer
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
function scrollTuiTranscript(state, viewport, delta) {
|
|
413
|
-
const maxOffset = getMaxScrollOffset(state, viewport);
|
|
414
|
-
const offset = clamp(state.scroll.offset + delta, 0, maxOffset);
|
|
415
|
-
return {
|
|
416
|
-
...state,
|
|
417
|
-
scroll: {
|
|
418
|
-
offset,
|
|
419
|
-
stickToBottom: offset >= maxOffset,
|
|
420
|
-
newContentPending: offset >= maxOffset ? false : state.scroll.newContentPending
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
}
|
|
424
|
-
function scrollTuiTranscriptToTop(state) {
|
|
425
|
-
return {
|
|
426
|
-
...state,
|
|
427
|
-
scroll: {
|
|
428
|
-
offset: 0,
|
|
429
|
-
stickToBottom: false,
|
|
430
|
-
newContentPending: state.scroll.newContentPending
|
|
431
|
-
}
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
function scrollTuiTranscriptToBottom(state, viewport) {
|
|
435
|
-
return {
|
|
436
|
-
...state,
|
|
437
|
-
scroll: {
|
|
438
|
-
offset: getMaxScrollOffset(state, viewport),
|
|
439
|
-
stickToBottom: true,
|
|
440
|
-
newContentPending: false
|
|
441
|
-
}
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
function applyViewportResize(state, viewport) {
|
|
445
|
-
if (state.scroll.stickToBottom) {
|
|
446
|
-
return scrollTuiTranscriptToBottom(state, viewport);
|
|
447
|
-
}
|
|
448
|
-
return {
|
|
449
|
-
...state,
|
|
450
|
-
scroll: {
|
|
451
|
-
...state.scroll,
|
|
452
|
-
offset: clamp(state.scroll.offset, 0, getMaxScrollOffset(state, viewport))
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
function getMaxScrollOffset(state, viewport) {
|
|
457
|
-
return Math.max(0, measureTranscriptRows2(state.transcript, viewport.width) - viewport.height);
|
|
458
|
-
}
|
|
459
|
-
function measureTranscriptRows2(entries, width) {
|
|
460
|
-
return measureTranscriptRows(entries, width, TUI_COLORS);
|
|
461
|
-
}
|
|
462
|
-
function renderTranscriptLineViews2(entries, width) {
|
|
463
|
-
return renderTranscriptLineViews(entries, width, TUI_COLORS);
|
|
464
|
-
}
|
|
465
|
-
function formatContextBudget(session) {
|
|
466
|
-
const budget = session?.contextBudget;
|
|
467
|
-
if (!budget) {
|
|
468
|
-
return "0 chars (0%)";
|
|
469
|
-
}
|
|
470
|
-
const percent = Math.round(budget.usageRatio * 100);
|
|
471
|
-
return `${budget.estimatedChars}/${budget.limitChars} chars (${percent}%)`;
|
|
472
|
-
}
|
|
473
|
-
function applyContentChange(state, viewport) {
|
|
474
|
-
if (state.scroll.stickToBottom) {
|
|
475
|
-
return scrollTuiTranscriptToBottom(state, viewport);
|
|
476
|
-
}
|
|
477
|
-
return {
|
|
478
|
-
...state,
|
|
479
|
-
scroll: {
|
|
480
|
-
...state.scroll,
|
|
481
|
-
newContentPending: true
|
|
482
|
-
}
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
function toTranscriptEntry(message, index) {
|
|
486
|
-
if (message.source === "internal" || !message.content?.trim()) {
|
|
487
|
-
return [];
|
|
488
|
-
}
|
|
489
|
-
if (message.role === "user") {
|
|
490
|
-
return [{ id: createEntryId(index), role: "user", text: message.content }];
|
|
491
|
-
}
|
|
492
|
-
if (message.role === "assistant") {
|
|
493
|
-
return [{ id: createEntryId(index), role: "assistant", text: message.content }];
|
|
494
|
-
}
|
|
495
|
-
return [];
|
|
496
|
-
}
|
|
497
|
-
function parseSubmittedInputEcho(text) {
|
|
498
|
-
const lines = text.split(/\r?\n/);
|
|
499
|
-
if (lines.length === 0 || !lines[0]?.startsWith("> ")) {
|
|
500
|
-
return void 0;
|
|
501
|
-
}
|
|
502
|
-
const parsed = lines.map((line, index) => {
|
|
503
|
-
const prefix = index === 0 ? "> " : "\u2026 ";
|
|
504
|
-
return line.startsWith(prefix) ? line.slice(prefix.length) : line;
|
|
505
|
-
}).join("\n");
|
|
506
|
-
return parsed.trim() ? parsed : void 0;
|
|
507
|
-
}
|
|
508
|
-
function createEntryId(index) {
|
|
509
|
-
return `entry-${index + 1}`;
|
|
510
|
-
}
|
|
511
|
-
function clamp(value, min, max) {
|
|
512
|
-
return Math.max(min, Math.min(max, value));
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
export {
|
|
516
|
-
TUI_COLORS,
|
|
517
|
-
TRANSCRIPT_OUTER_PADDING_X,
|
|
518
|
-
createInitialTuiState,
|
|
519
|
-
appendTranscriptEntry,
|
|
520
|
-
appendTranscriptText,
|
|
521
|
-
updateRuntimeDock,
|
|
522
|
-
updateComposerState,
|
|
523
|
-
scrollTuiTranscript,
|
|
524
|
-
scrollTuiTranscriptToTop,
|
|
525
|
-
scrollTuiTranscriptToBottom,
|
|
526
|
-
applyViewportResize,
|
|
527
|
-
renderTranscriptLineViews2 as renderTranscriptLineViews,
|
|
528
|
-
formatContextBudget,
|
|
529
|
-
parseSubmittedInputEcho
|
|
530
|
-
};
|