casabot 1.1.3 → 1.1.4
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/tui/app.js +2 -46
- package/package.json +1 -1
- package/src/tui/app.tsx +5 -73
package/dist/tui/app.js
CHANGED
|
@@ -22,27 +22,6 @@ function truncateOutput(content, maxLines = 8) {
|
|
|
22
22
|
return (lines.slice(0, maxLines).join("\n") +
|
|
23
23
|
`\n … ${lines.length - maxLines} more lines`);
|
|
24
24
|
}
|
|
25
|
-
function estimateMessageLines(message, width) {
|
|
26
|
-
const contentWidth = Math.max(width - 10, 20);
|
|
27
|
-
const countLines = (text) => text.split("\n").reduce((sum, line) => sum + Math.max(1, Math.ceil((line.length || 1) / contentWidth)), 0);
|
|
28
|
-
if (message.role === "user") {
|
|
29
|
-
return 2 + countLines(message.content);
|
|
30
|
-
}
|
|
31
|
-
if (message.role === "tool") {
|
|
32
|
-
return 3 + countLines(truncateOutput(message.content));
|
|
33
|
-
}
|
|
34
|
-
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
35
|
-
let lines = 2;
|
|
36
|
-
if (message.content)
|
|
37
|
-
lines += countLines(message.content);
|
|
38
|
-
lines += 4 + (message.toolCalls?.length ?? 0);
|
|
39
|
-
return lines;
|
|
40
|
-
}
|
|
41
|
-
if (message.role === "assistant") {
|
|
42
|
-
return 2 + countLines(message.content);
|
|
43
|
-
}
|
|
44
|
-
return 2;
|
|
45
|
-
}
|
|
46
25
|
function useMouseWheel(onScrollUp, onScrollDown) {
|
|
47
26
|
const { stdout } = useStdout();
|
|
48
27
|
const scrollUpRef = useRef(onScrollUp);
|
|
@@ -127,10 +106,6 @@ function WelcomeHint() {
|
|
|
127
106
|
function ProcessingIndicator() {
|
|
128
107
|
return (_jsxs(Box, { paddingX: 2, marginTop: 1, gap: 1, children: [_jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: "yellow", children: "Thinking…" })] }));
|
|
129
108
|
}
|
|
130
|
-
function ScrollIndicator({ direction, count, }) {
|
|
131
|
-
const arrow = direction === "above" ? "▲" : "▼";
|
|
132
|
-
return (_jsx(Box, { justifyContent: "center", paddingX: 2, children: _jsx(Text, { dimColor: true, children: `${arrow} ${count} more ${count === 1 ? "message" : "messages"} ${direction}` }) }));
|
|
133
|
-
}
|
|
134
109
|
// border(2) + header(3) + hrules(2) + input(3) + status(1) = 11
|
|
135
110
|
const CHROME_HEIGHT = 11;
|
|
136
111
|
function App({ provider, conversation, skills, }) {
|
|
@@ -160,26 +135,7 @@ function App({ provider, conversation, skills, }) {
|
|
|
160
135
|
setScrollOffset((prev) => (prev === 0 ? 0 : prev + 1));
|
|
161
136
|
}, [messages.length]);
|
|
162
137
|
const messagesHeight = Math.max(termSize.rows - CHROME_HEIGHT, 4);
|
|
163
|
-
const
|
|
164
|
-
if (messages.length === 0) {
|
|
165
|
-
return { visibleMessages: [], hiddenAbove: 0, hiddenBelow: 0 };
|
|
166
|
-
}
|
|
167
|
-
const endIndex = messages.length - scrollOffset;
|
|
168
|
-
let usedLines = isProcessing ? 2 : 0;
|
|
169
|
-
let startIndex = endIndex;
|
|
170
|
-
for (let i = endIndex - 1; i >= 0; i--) {
|
|
171
|
-
const lines = estimateMessageLines(messages[i], termSize.columns);
|
|
172
|
-
if (usedLines + lines > messagesHeight && startIndex < endIndex)
|
|
173
|
-
break;
|
|
174
|
-
usedLines += lines;
|
|
175
|
-
startIndex = i;
|
|
176
|
-
}
|
|
177
|
-
return {
|
|
178
|
-
visibleMessages: messages.slice(startIndex, endIndex),
|
|
179
|
-
hiddenAbove: startIndex,
|
|
180
|
-
hiddenBelow: scrollOffset,
|
|
181
|
-
};
|
|
182
|
-
}, [messages, scrollOffset, messagesHeight, termSize.columns, isProcessing]);
|
|
138
|
+
const visibleMessages = useMemo(() => messages.slice(0, messages.length - scrollOffset), [messages, scrollOffset]);
|
|
183
139
|
const maxScrollOffset = useMemo(() => {
|
|
184
140
|
return Math.max(0, messages.length - 1);
|
|
185
141
|
}, [messages.length]);
|
|
@@ -225,7 +181,7 @@ function App({ provider, conversation, skills, }) {
|
|
|
225
181
|
}
|
|
226
182
|
});
|
|
227
183
|
const userCount = messages.filter((m) => m.role === "user").length;
|
|
228
|
-
return (_jsxs(Box, { flexDirection: "column", width: termSize.columns, height: termSize.rows, borderStyle: "round", borderColor: "gray", children: [_jsx(Header, {}), _jsx(HRule, { width: termSize.columns }), _jsx(Box, { flexDirection: "column", height: messagesHeight, overflowY: "hidden", justifyContent: "flex-end", children: messages.length === 0 && !isProcessing ? (_jsx(WelcomeHint, {})) : (_jsxs(_Fragment, { children: [
|
|
184
|
+
return (_jsxs(Box, { flexDirection: "column", width: termSize.columns, height: termSize.rows, borderStyle: "round", borderColor: "gray", children: [_jsx(Header, {}), _jsx(HRule, { width: termSize.columns }), _jsx(Box, { flexDirection: "column", height: messagesHeight, overflowY: "hidden", justifyContent: "flex-end", children: messages.length === 0 && !isProcessing ? (_jsx(WelcomeHint, {})) : (_jsxs(_Fragment, { children: [visibleMessages.map((msg, i) => (_jsx(MessageView, { message: msg }, i))), isProcessing && _jsx(ProcessingIndicator, {})] })) }), _jsx(HRule, { width: termSize.columns }), _jsx(Box, { paddingX: 1, children: _jsxs(Box, { borderStyle: "round", borderColor: isProcessing ? "gray" : "cyan", paddingX: 1, width: "100%", children: [_jsx(Text, { color: "cyan", bold: true, children: "❯ " }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: (val) => {
|
|
229
185
|
handleSubmit(val).catch(() => { });
|
|
230
186
|
}, placeholder: "Type your message\u2026", focus: !isProcessing, showCursor: true })] }) }), _jsxs(Box, { paddingX: 2, justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: "Ctrl+C exit ↑↓/wheel scroll" }), _jsxs(Text, { dimColor: true, children: [userCount, " ", userCount === 1 ? "message" : "messages"] })] })] }));
|
|
231
187
|
}
|
package/package.json
CHANGED
package/src/tui/app.tsx
CHANGED
|
@@ -30,33 +30,6 @@ function truncateOutput(content: string, maxLines = 8): string {
|
|
|
30
30
|
);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function estimateMessageLines(message: Message, width: number): number {
|
|
34
|
-
const contentWidth = Math.max(width - 10, 20);
|
|
35
|
-
const countLines = (text: string): number =>
|
|
36
|
-
text.split("\n").reduce(
|
|
37
|
-
(sum, line) =>
|
|
38
|
-
sum + Math.max(1, Math.ceil((line.length || 1) / contentWidth)),
|
|
39
|
-
0,
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
if (message.role === "user") {
|
|
43
|
-
return 2 + countLines(message.content);
|
|
44
|
-
}
|
|
45
|
-
if (message.role === "tool") {
|
|
46
|
-
return 3 + countLines(truncateOutput(message.content));
|
|
47
|
-
}
|
|
48
|
-
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
49
|
-
let lines = 2;
|
|
50
|
-
if (message.content) lines += countLines(message.content);
|
|
51
|
-
lines += 4 + (message.toolCalls?.length ?? 0);
|
|
52
|
-
return lines;
|
|
53
|
-
}
|
|
54
|
-
if (message.role === "assistant") {
|
|
55
|
-
return 2 + countLines(message.content);
|
|
56
|
-
}
|
|
57
|
-
return 2;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
33
|
function useMouseWheel(
|
|
61
34
|
onScrollUp: () => void,
|
|
62
35
|
onScrollDown: () => void,
|
|
@@ -258,23 +231,6 @@ function ProcessingIndicator(): React.ReactElement {
|
|
|
258
231
|
);
|
|
259
232
|
}
|
|
260
233
|
|
|
261
|
-
function ScrollIndicator({
|
|
262
|
-
direction,
|
|
263
|
-
count,
|
|
264
|
-
}: {
|
|
265
|
-
direction: "above" | "below";
|
|
266
|
-
count: number;
|
|
267
|
-
}): React.ReactElement {
|
|
268
|
-
const arrow = direction === "above" ? "▲" : "▼";
|
|
269
|
-
return (
|
|
270
|
-
<Box justifyContent="center" paddingX={2}>
|
|
271
|
-
<Text dimColor>
|
|
272
|
-
{`${arrow} ${count} more ${count === 1 ? "message" : "messages"} ${direction}`}
|
|
273
|
-
</Text>
|
|
274
|
-
</Box>
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
234
|
interface AppProps {
|
|
279
235
|
provider: ChatProvider;
|
|
280
236
|
conversation: ConversationHistory;
|
|
@@ -320,28 +276,10 @@ function App({
|
|
|
320
276
|
|
|
321
277
|
const messagesHeight = Math.max(termSize.rows - CHROME_HEIGHT, 4);
|
|
322
278
|
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const endIndex = messages.length - scrollOffset;
|
|
329
|
-
let usedLines = isProcessing ? 2 : 0;
|
|
330
|
-
let startIndex = endIndex;
|
|
331
|
-
|
|
332
|
-
for (let i = endIndex - 1; i >= 0; i--) {
|
|
333
|
-
const lines = estimateMessageLines(messages[i], termSize.columns);
|
|
334
|
-
if (usedLines + lines > messagesHeight && startIndex < endIndex) break;
|
|
335
|
-
usedLines += lines;
|
|
336
|
-
startIndex = i;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return {
|
|
340
|
-
visibleMessages: messages.slice(startIndex, endIndex),
|
|
341
|
-
hiddenAbove: startIndex,
|
|
342
|
-
hiddenBelow: scrollOffset,
|
|
343
|
-
};
|
|
344
|
-
}, [messages, scrollOffset, messagesHeight, termSize.columns, isProcessing]);
|
|
279
|
+
const visibleMessages = useMemo(
|
|
280
|
+
() => messages.slice(0, messages.length - scrollOffset),
|
|
281
|
+
[messages, scrollOffset],
|
|
282
|
+
);
|
|
345
283
|
|
|
346
284
|
const maxScrollOffset = useMemo(() => {
|
|
347
285
|
return Math.max(0, messages.length - 1);
|
|
@@ -421,16 +359,10 @@ function App({
|
|
|
421
359
|
<WelcomeHint />
|
|
422
360
|
) : (
|
|
423
361
|
<>
|
|
424
|
-
{hiddenAbove > 0 && (
|
|
425
|
-
<ScrollIndicator direction="above" count={hiddenAbove} />
|
|
426
|
-
)}
|
|
427
362
|
{visibleMessages.map((msg, i) => (
|
|
428
|
-
<MessageView key={
|
|
363
|
+
<MessageView key={i} message={msg} />
|
|
429
364
|
))}
|
|
430
365
|
{isProcessing && <ProcessingIndicator />}
|
|
431
|
-
{hiddenBelow > 0 && (
|
|
432
|
-
<ScrollIndicator direction="below" count={hiddenBelow} />
|
|
433
|
-
)}
|
|
434
366
|
</>
|
|
435
367
|
)}
|
|
436
368
|
</Box>
|