casabot 1.1.6 → 1.1.8
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 +39 -33
- package/package.json +1 -1
- package/src/tui/app.tsx +59 -41
package/dist/tui/app.js
CHANGED
|
@@ -4,14 +4,14 @@ import { render, Box, Text, Static, useInput, useApp, useStdout } from "ink";
|
|
|
4
4
|
import TextInput from "ink-text-input";
|
|
5
5
|
import Spinner from "ink-spinner";
|
|
6
6
|
import Gradient from "ink-gradient";
|
|
7
|
-
import {
|
|
7
|
+
import { Marked } from "marked";
|
|
8
8
|
import { markedTerminal } from "marked-terminal";
|
|
9
9
|
import { runAgent } from "../agent/base.js";
|
|
10
|
-
marked.use({ gfm: true });
|
|
11
10
|
function renderMarkdown(content) {
|
|
12
11
|
const width = Math.max((process.stdout.columns ?? 80) - 8, 40);
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const md = new Marked({ gfm: true });
|
|
13
|
+
md.use(markedTerminal({ showSectionPrefix: false, tab: 2, width, reflowText: true }));
|
|
14
|
+
return md.parse(content, { async: false }).trimEnd();
|
|
15
15
|
}
|
|
16
16
|
function truncateOutput(content, maxLines = 8) {
|
|
17
17
|
const lines = content.split("\n");
|
|
@@ -20,22 +20,21 @@ function truncateOutput(content, maxLines = 8) {
|
|
|
20
20
|
return (lines.slice(0, maxLines).join("\n") +
|
|
21
21
|
`\n … ${lines.length - maxLines} more lines`);
|
|
22
22
|
}
|
|
23
|
-
function HRule() {
|
|
24
|
-
|
|
25
|
-
const width = stdout.columns ?? 80;
|
|
26
|
-
return (_jsx(Box, { paddingX: 1, children: _jsx(Text, { dimColor: true, children: "─".repeat(Math.max(width - 4, 10)) }) }));
|
|
23
|
+
function HRule({ columns }) {
|
|
24
|
+
return (_jsx(Box, { paddingX: 1, width: columns, children: _jsx(Text, { dimColor: true, children: "─".repeat(Math.max(columns - 4, 1)) }) }));
|
|
27
25
|
}
|
|
28
|
-
function HeaderBlock() {
|
|
29
|
-
return (_jsxs(Box, { flexDirection: "column", paddingTop: 1, children: [_jsx(Box, { paddingX: 2, children: _jsx(Gradient, { name: "vice", children: _jsx(Text, { bold: true, children: "✦ CasAbot" }) }) }), _jsx(Box, { paddingX: 2, children: _jsx(Text, { dimColor: true, children: "Cassiopeia A — Freely creates everything, like a supernova explosion." }) }), _jsx(HRule, {})] }));
|
|
26
|
+
function HeaderBlock({ columns }) {
|
|
27
|
+
return (_jsxs(Box, { flexDirection: "column", paddingTop: 1, width: columns, children: [_jsx(Box, { paddingX: 2, children: _jsx(Gradient, { name: "vice", children: _jsx(Text, { bold: true, children: "✦ CasAbot" }) }) }), _jsx(Box, { paddingX: 2, children: _jsx(Text, { wrap: "wrap", dimColor: true, children: "Cassiopeia A — Freely creates everything, like a supernova explosion." }) }), _jsx(HRule, { columns: columns })] }));
|
|
30
28
|
}
|
|
31
|
-
function UserMessageView({ content }) {
|
|
32
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, children: [_jsx(Text, { color: "green", bold: true, children: "▶ You" }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { wrap: "wrap", children: content }) })] }));
|
|
29
|
+
function UserMessageView({ content, columns }) {
|
|
30
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, width: columns, children: [_jsx(Text, { color: "green", bold: true, children: "▶ You" }), _jsx(Box, { marginLeft: 2, width: Math.max(columns - 6, 10), children: _jsx(Text, { wrap: "wrap", children: content }) })] }));
|
|
33
31
|
}
|
|
34
|
-
function AssistantMessageView({ content, }) {
|
|
35
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, children: [_jsx(Text, { color: "cyan", bold: true, children: "✦ CasAbot" }), _jsx(Box, { marginLeft: 2, children: _jsx(Text, { wrap: "wrap", children: renderMarkdown(content) }) })] }));
|
|
32
|
+
function AssistantMessageView({ content, columns, }) {
|
|
33
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, width: columns, children: [_jsx(Text, { color: "cyan", bold: true, children: "✦ CasAbot" }), _jsx(Box, { marginLeft: 2, width: Math.max(columns - 6, 10), children: _jsx(Text, { wrap: "wrap", children: renderMarkdown(content) }) })] }));
|
|
36
34
|
}
|
|
37
|
-
function ToolCallsView({ message, }) {
|
|
38
|
-
|
|
35
|
+
function ToolCallsView({ message, columns, }) {
|
|
36
|
+
const boxWidth = Math.max(columns - 6, 10);
|
|
37
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, width: columns, children: [_jsx(Text, { color: "cyan", bold: true, children: "✦ CasAbot" }), message.content ? (_jsx(Box, { marginLeft: 2, width: boxWidth, children: _jsx(Text, { wrap: "wrap", children: renderMarkdown(message.content) }) })) : null, _jsxs(Box, { flexDirection: "column", marginLeft: 2, marginTop: 1, borderStyle: "round", borderColor: "yellow", paddingX: 1, width: boxWidth, overflow: "hidden", children: [_jsx(Text, { color: "yellow", bold: true, children: "⚡ Tool Calls" }), message.toolCalls?.map((tc, i) => {
|
|
39
38
|
let display = tc.arguments;
|
|
40
39
|
try {
|
|
41
40
|
const args = JSON.parse(tc.arguments);
|
|
@@ -45,38 +44,45 @@ function ToolCallsView({ message, }) {
|
|
|
45
44
|
catch {
|
|
46
45
|
/* keep raw */
|
|
47
46
|
}
|
|
47
|
+
const maxArgLen = Math.max(boxWidth - tc.name.length - 8, 20);
|
|
48
|
+
if (display.length > maxArgLen) {
|
|
49
|
+
display = display.slice(0, maxArgLen - 1) + "…";
|
|
50
|
+
}
|
|
48
51
|
return (_jsxs(Box, { children: [_jsx(Text, { dimColor: true, children: tc.name }), _jsx(Text, { children: " → " }), _jsx(Text, { color: "white", wrap: "wrap", children: display })] }, i));
|
|
49
52
|
})] })] }));
|
|
50
53
|
}
|
|
51
|
-
function ToolResultView({ content, }) {
|
|
52
|
-
|
|
54
|
+
function ToolResultView({ content, columns, }) {
|
|
55
|
+
const boxWidth = Math.max(columns - 6, 10);
|
|
56
|
+
return (_jsxs(Box, { flexDirection: "column", marginLeft: 4, marginRight: 2, borderStyle: "round", borderColor: "gray", paddingX: 1, width: boxWidth, overflow: "hidden", children: [_jsx(Text, { dimColor: true, bold: true, children: "📋 Result" }), _jsx(Text, { dimColor: true, wrap: "wrap", children: truncateOutput(content) })] }));
|
|
53
57
|
}
|
|
54
|
-
function MessageView({ message, }) {
|
|
58
|
+
function MessageView({ message, columns, }) {
|
|
55
59
|
if (message.role === "user") {
|
|
56
|
-
return _jsx(UserMessageView, { content: message.content });
|
|
60
|
+
return _jsx(UserMessageView, { content: message.content, columns: columns });
|
|
57
61
|
}
|
|
58
62
|
if (message.role === "tool") {
|
|
59
|
-
return _jsx(ToolResultView, { content: message.content });
|
|
63
|
+
return _jsx(ToolResultView, { content: message.content, columns: columns });
|
|
60
64
|
}
|
|
61
65
|
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
62
|
-
return _jsx(ToolCallsView, { message: message });
|
|
66
|
+
return _jsx(ToolCallsView, { message: message, columns: columns });
|
|
63
67
|
}
|
|
64
68
|
if (message.role === "assistant") {
|
|
65
|
-
return _jsx(AssistantMessageView, { content: message.content });
|
|
69
|
+
return _jsx(AssistantMessageView, { content: message.content, columns: columns });
|
|
66
70
|
}
|
|
67
|
-
return _jsx(Text, { children: message.content });
|
|
71
|
+
return _jsx(Text, { wrap: "wrap", children: message.content });
|
|
68
72
|
}
|
|
69
|
-
function WelcomeHint() {
|
|
70
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, marginBottom: 1, children: [_jsx(Text, { dimColor: true, children: "Type a message below to get started." }), _jsx(Text, { dimColor: true, children: "CasAbot will orchestrate agents to help you." })] }));
|
|
73
|
+
function WelcomeHint({ columns }) {
|
|
74
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, marginBottom: 1, width: columns, children: [_jsx(Text, { dimColor: true, children: "Type a message below to get started." }), _jsx(Text, { dimColor: true, children: "CasAbot will orchestrate agents to help you." })] }));
|
|
71
75
|
}
|
|
72
|
-
function ProcessingIndicator() {
|
|
73
|
-
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…" })] }));
|
|
76
|
+
function ProcessingIndicator({ columns }) {
|
|
77
|
+
return (_jsxs(Box, { paddingX: 2, marginTop: 1, gap: 1, width: columns, children: [_jsx(Text, { color: "yellow", children: _jsx(Spinner, { type: "dots" }) }), _jsx(Text, { color: "yellow", children: "Thinking…" })] }));
|
|
74
78
|
}
|
|
75
79
|
function App({ provider, conversation, skills, }) {
|
|
76
80
|
const [messages, setMessages] = useState([]);
|
|
77
81
|
const [input, setInput] = useState("");
|
|
78
82
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
79
83
|
const { exit } = useApp();
|
|
84
|
+
const { stdout } = useStdout();
|
|
85
|
+
const columns = stdout.columns ?? 80;
|
|
80
86
|
const handleSubmit = useCallback(async (text) => {
|
|
81
87
|
const trimmed = text.trim();
|
|
82
88
|
if (!trimmed || isProcessing)
|
|
@@ -114,14 +120,14 @@ function App({ provider, conversation, skills, }) {
|
|
|
114
120
|
message: msg,
|
|
115
121
|
})),
|
|
116
122
|
], [messages]);
|
|
117
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Static, { items: items, children: (item) => {
|
|
123
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Static, { items: items, children: (item) => {
|
|
118
124
|
if (item.type === "header") {
|
|
119
|
-
return (_jsx(Box, { flexDirection: "column", children: _jsx(HeaderBlock, {}) }, item.key));
|
|
125
|
+
return (_jsx(Box, { flexDirection: "column", width: columns, children: _jsx(HeaderBlock, { columns: columns }) }, item.key));
|
|
120
126
|
}
|
|
121
|
-
return (_jsx(Box, { flexDirection: "column", children: _jsx(MessageView, { message: item.message }) }, item.key));
|
|
122
|
-
} }), messages.length === 0 && !isProcessing && _jsx(WelcomeHint, {}), isProcessing && _jsx(ProcessingIndicator, {}), _jsx(HRule, {}), _jsx(Box, { paddingX: 1, children: _jsxs(Box, { borderStyle: "round", borderColor: isProcessing ? "gray" : "cyan", paddingX: 1, width: "
|
|
127
|
+
return (_jsx(Box, { flexDirection: "column", width: columns, children: _jsx(MessageView, { message: item.message, columns: columns }) }, item.key));
|
|
128
|
+
} }), messages.length === 0 && !isProcessing && _jsx(WelcomeHint, { columns: columns }), isProcessing && _jsx(ProcessingIndicator, { columns: columns }), _jsx(HRule, { columns: columns }), _jsx(Box, { paddingX: 1, width: columns, children: _jsxs(Box, { borderStyle: "round", borderColor: isProcessing ? "gray" : "cyan", paddingX: 1, width: Math.max(columns - 2, 10), overflow: "hidden", children: [_jsx(Text, { color: "cyan", bold: true, children: "❯ " }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: (val) => {
|
|
123
129
|
handleSubmit(val).catch(() => { });
|
|
124
|
-
}, 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" }), _jsxs(Text, { dimColor: true, children: [userCount, " ", userCount === 1 ? "message" : "messages"] })] })] }));
|
|
130
|
+
}, placeholder: "Type your message\u2026", focus: !isProcessing, showCursor: true })] }) }), _jsxs(Box, { paddingX: 2, width: columns, justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: "Ctrl+C exit" }), _jsxs(Text, { dimColor: true, children: [userCount, " ", userCount === 1 ? "message" : "messages"] })] })] }));
|
|
125
131
|
}
|
|
126
132
|
export function startTUI(provider, conversation, skills) {
|
|
127
133
|
render(_jsx(App, { provider: provider, conversation: conversation, skills: skills }));
|
package/package.json
CHANGED
package/src/tui/app.tsx
CHANGED
|
@@ -3,18 +3,17 @@ import { render, Box, Text, Static, useInput, useApp, useStdout } from "ink";
|
|
|
3
3
|
import TextInput from "ink-text-input";
|
|
4
4
|
import Spinner from "ink-spinner";
|
|
5
5
|
import Gradient from "ink-gradient";
|
|
6
|
-
import {
|
|
6
|
+
import { Marked } from "marked";
|
|
7
7
|
import { markedTerminal } from "marked-terminal";
|
|
8
8
|
import type { ChatProvider } from "../providers/base.js";
|
|
9
9
|
import type { ConversationHistory, Message, Skill } from "../config/types.js";
|
|
10
10
|
import { runAgent } from "../agent/base.js";
|
|
11
11
|
|
|
12
|
-
marked.use({ gfm: true });
|
|
13
|
-
|
|
14
12
|
function renderMarkdown(content: string): string {
|
|
15
13
|
const width = Math.max((process.stdout.columns ?? 80) - 8, 40);
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
const md = new Marked({ gfm: true });
|
|
15
|
+
md.use(markedTerminal({ showSectionPrefix: false, tab: 2, width, reflowText: true }));
|
|
16
|
+
return (md.parse(content, { async: false }) as string).trimEnd();
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
function truncateOutput(content: string, maxLines = 8): string {
|
|
@@ -26,41 +25,39 @@ function truncateOutput(content: string, maxLines = 8): string {
|
|
|
26
25
|
);
|
|
27
26
|
}
|
|
28
27
|
|
|
29
|
-
function HRule(): React.ReactElement {
|
|
30
|
-
const { stdout } = useStdout();
|
|
31
|
-
const width = stdout.columns ?? 80;
|
|
28
|
+
function HRule({ columns }: { columns: number }): React.ReactElement {
|
|
32
29
|
return (
|
|
33
|
-
<Box paddingX={1}>
|
|
34
|
-
<Text dimColor>{"─".repeat(Math.max(
|
|
30
|
+
<Box paddingX={1} width={columns}>
|
|
31
|
+
<Text dimColor>{"─".repeat(Math.max(columns - 4, 1))}</Text>
|
|
35
32
|
</Box>
|
|
36
33
|
);
|
|
37
34
|
}
|
|
38
35
|
|
|
39
|
-
function HeaderBlock(): React.ReactElement {
|
|
36
|
+
function HeaderBlock({ columns }: { columns: number }): React.ReactElement {
|
|
40
37
|
return (
|
|
41
|
-
<Box flexDirection="column" paddingTop={1}>
|
|
38
|
+
<Box flexDirection="column" paddingTop={1} width={columns}>
|
|
42
39
|
<Box paddingX={2}>
|
|
43
40
|
<Gradient name="vice">
|
|
44
41
|
<Text bold>{"✦ CasAbot"}</Text>
|
|
45
42
|
</Gradient>
|
|
46
43
|
</Box>
|
|
47
44
|
<Box paddingX={2}>
|
|
48
|
-
<Text dimColor>
|
|
45
|
+
<Text wrap="wrap" dimColor>
|
|
49
46
|
{"Cassiopeia A — Freely creates everything, like a supernova explosion."}
|
|
50
47
|
</Text>
|
|
51
48
|
</Box>
|
|
52
|
-
<HRule />
|
|
49
|
+
<HRule columns={columns} />
|
|
53
50
|
</Box>
|
|
54
51
|
);
|
|
55
52
|
}
|
|
56
53
|
|
|
57
|
-
function UserMessageView({ content }: { content: string }): React.ReactElement {
|
|
54
|
+
function UserMessageView({ content, columns }: { content: string; columns: number }): React.ReactElement {
|
|
58
55
|
return (
|
|
59
|
-
<Box flexDirection="column" paddingX={2} marginTop={1}>
|
|
56
|
+
<Box flexDirection="column" paddingX={2} marginTop={1} width={columns}>
|
|
60
57
|
<Text color="green" bold>
|
|
61
58
|
{"▶ You"}
|
|
62
59
|
</Text>
|
|
63
|
-
<Box marginLeft={2}>
|
|
60
|
+
<Box marginLeft={2} width={Math.max(columns - 6, 10)}>
|
|
64
61
|
<Text wrap="wrap">{content}</Text>
|
|
65
62
|
</Box>
|
|
66
63
|
</Box>
|
|
@@ -69,15 +66,17 @@ function UserMessageView({ content }: { content: string }): React.ReactElement {
|
|
|
69
66
|
|
|
70
67
|
function AssistantMessageView({
|
|
71
68
|
content,
|
|
69
|
+
columns,
|
|
72
70
|
}: {
|
|
73
71
|
content: string;
|
|
72
|
+
columns: number;
|
|
74
73
|
}): React.ReactElement {
|
|
75
74
|
return (
|
|
76
|
-
<Box flexDirection="column" paddingX={2} marginTop={1}>
|
|
75
|
+
<Box flexDirection="column" paddingX={2} marginTop={1} width={columns}>
|
|
77
76
|
<Text color="cyan" bold>
|
|
78
77
|
{"✦ CasAbot"}
|
|
79
78
|
</Text>
|
|
80
|
-
<Box marginLeft={2}>
|
|
79
|
+
<Box marginLeft={2} width={Math.max(columns - 6, 10)}>
|
|
81
80
|
<Text wrap="wrap">{renderMarkdown(content)}</Text>
|
|
82
81
|
</Box>
|
|
83
82
|
</Box>
|
|
@@ -86,16 +85,19 @@ function AssistantMessageView({
|
|
|
86
85
|
|
|
87
86
|
function ToolCallsView({
|
|
88
87
|
message,
|
|
88
|
+
columns,
|
|
89
89
|
}: {
|
|
90
90
|
message: Message;
|
|
91
|
+
columns: number;
|
|
91
92
|
}): React.ReactElement {
|
|
93
|
+
const boxWidth = Math.max(columns - 6, 10);
|
|
92
94
|
return (
|
|
93
|
-
<Box flexDirection="column" paddingX={2} marginTop={1}>
|
|
95
|
+
<Box flexDirection="column" paddingX={2} marginTop={1} width={columns}>
|
|
94
96
|
<Text color="cyan" bold>
|
|
95
97
|
{"✦ CasAbot"}
|
|
96
98
|
</Text>
|
|
97
99
|
{message.content ? (
|
|
98
|
-
<Box marginLeft={2}>
|
|
100
|
+
<Box marginLeft={2} width={boxWidth}>
|
|
99
101
|
<Text wrap="wrap">{renderMarkdown(message.content)}</Text>
|
|
100
102
|
</Box>
|
|
101
103
|
) : null}
|
|
@@ -106,6 +108,8 @@ function ToolCallsView({
|
|
|
106
108
|
borderStyle="round"
|
|
107
109
|
borderColor="yellow"
|
|
108
110
|
paddingX={1}
|
|
111
|
+
width={boxWidth}
|
|
112
|
+
overflow="hidden"
|
|
109
113
|
>
|
|
110
114
|
<Text color="yellow" bold>
|
|
111
115
|
{"⚡ Tool Calls"}
|
|
@@ -118,6 +122,10 @@ function ToolCallsView({
|
|
|
118
122
|
} catch {
|
|
119
123
|
/* keep raw */
|
|
120
124
|
}
|
|
125
|
+
const maxArgLen = Math.max(boxWidth - tc.name.length - 8, 20);
|
|
126
|
+
if (display.length > maxArgLen) {
|
|
127
|
+
display = display.slice(0, maxArgLen - 1) + "…";
|
|
128
|
+
}
|
|
121
129
|
return (
|
|
122
130
|
<Box key={i}>
|
|
123
131
|
<Text dimColor>{tc.name}</Text>
|
|
@@ -133,9 +141,12 @@ function ToolCallsView({
|
|
|
133
141
|
|
|
134
142
|
function ToolResultView({
|
|
135
143
|
content,
|
|
144
|
+
columns,
|
|
136
145
|
}: {
|
|
137
146
|
content: string;
|
|
147
|
+
columns: number;
|
|
138
148
|
}): React.ReactElement {
|
|
149
|
+
const boxWidth = Math.max(columns - 6, 10);
|
|
139
150
|
return (
|
|
140
151
|
<Box
|
|
141
152
|
flexDirection="column"
|
|
@@ -144,6 +155,8 @@ function ToolResultView({
|
|
|
144
155
|
borderStyle="round"
|
|
145
156
|
borderColor="gray"
|
|
146
157
|
paddingX={1}
|
|
158
|
+
width={boxWidth}
|
|
159
|
+
overflow="hidden"
|
|
147
160
|
>
|
|
148
161
|
<Text dimColor bold>
|
|
149
162
|
{"📋 Result"}
|
|
@@ -155,36 +168,38 @@ function ToolResultView({
|
|
|
155
168
|
|
|
156
169
|
function MessageView({
|
|
157
170
|
message,
|
|
171
|
+
columns,
|
|
158
172
|
}: {
|
|
159
173
|
message: Message;
|
|
174
|
+
columns: number;
|
|
160
175
|
}): React.ReactElement {
|
|
161
176
|
if (message.role === "user") {
|
|
162
|
-
return <UserMessageView content={message.content} />;
|
|
177
|
+
return <UserMessageView content={message.content} columns={columns} />;
|
|
163
178
|
}
|
|
164
179
|
if (message.role === "tool") {
|
|
165
|
-
return <ToolResultView content={message.content} />;
|
|
180
|
+
return <ToolResultView content={message.content} columns={columns} />;
|
|
166
181
|
}
|
|
167
182
|
if (message.role === "assistant" && message.toolCalls?.length) {
|
|
168
|
-
return <ToolCallsView message={message} />;
|
|
183
|
+
return <ToolCallsView message={message} columns={columns} />;
|
|
169
184
|
}
|
|
170
185
|
if (message.role === "assistant") {
|
|
171
|
-
return <AssistantMessageView content={message.content} />;
|
|
186
|
+
return <AssistantMessageView content={message.content} columns={columns} />;
|
|
172
187
|
}
|
|
173
|
-
return <Text>{message.content}</Text>;
|
|
188
|
+
return <Text wrap="wrap">{message.content}</Text>;
|
|
174
189
|
}
|
|
175
190
|
|
|
176
|
-
function WelcomeHint(): React.ReactElement {
|
|
191
|
+
function WelcomeHint({ columns }: { columns: number }): React.ReactElement {
|
|
177
192
|
return (
|
|
178
|
-
<Box flexDirection="column" paddingX={2} marginTop={1} marginBottom={1}>
|
|
193
|
+
<Box flexDirection="column" paddingX={2} marginTop={1} marginBottom={1} width={columns}>
|
|
179
194
|
<Text dimColor>{"Type a message below to get started."}</Text>
|
|
180
195
|
<Text dimColor>{"CasAbot will orchestrate agents to help you."}</Text>
|
|
181
196
|
</Box>
|
|
182
197
|
);
|
|
183
198
|
}
|
|
184
199
|
|
|
185
|
-
function ProcessingIndicator(): React.ReactElement {
|
|
200
|
+
function ProcessingIndicator({ columns }: { columns: number }): React.ReactElement {
|
|
186
201
|
return (
|
|
187
|
-
<Box paddingX={2} marginTop={1} gap={1}>
|
|
202
|
+
<Box paddingX={2} marginTop={1} gap={1} width={columns}>
|
|
188
203
|
<Text color="yellow">
|
|
189
204
|
<Spinner type="dots" />
|
|
190
205
|
</Text>
|
|
@@ -212,6 +227,8 @@ function App({
|
|
|
212
227
|
const [input, setInput] = useState("");
|
|
213
228
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
214
229
|
const { exit } = useApp();
|
|
230
|
+
const { stdout } = useStdout();
|
|
231
|
+
const columns = stdout.columns ?? 80;
|
|
215
232
|
|
|
216
233
|
const handleSubmit = useCallback(
|
|
217
234
|
async (text: string) => {
|
|
@@ -260,35 +277,36 @@ function App({
|
|
|
260
277
|
], [messages]);
|
|
261
278
|
|
|
262
279
|
return (
|
|
263
|
-
<Box flexDirection="column">
|
|
280
|
+
<Box flexDirection="column" width={columns}>
|
|
264
281
|
<Static items={items}>
|
|
265
282
|
{(item) => {
|
|
266
283
|
if (item.type === "header") {
|
|
267
284
|
return (
|
|
268
|
-
<Box key={item.key} flexDirection="column">
|
|
269
|
-
<HeaderBlock />
|
|
285
|
+
<Box key={item.key} flexDirection="column" width={columns}>
|
|
286
|
+
<HeaderBlock columns={columns} />
|
|
270
287
|
</Box>
|
|
271
288
|
);
|
|
272
289
|
}
|
|
273
290
|
return (
|
|
274
|
-
<Box key={item.key} flexDirection="column">
|
|
275
|
-
<MessageView message={item.message} />
|
|
291
|
+
<Box key={item.key} flexDirection="column" width={columns}>
|
|
292
|
+
<MessageView message={item.message} columns={columns} />
|
|
276
293
|
</Box>
|
|
277
294
|
);
|
|
278
295
|
}}
|
|
279
296
|
</Static>
|
|
280
297
|
|
|
281
|
-
{messages.length === 0 && !isProcessing && <WelcomeHint />}
|
|
282
|
-
{isProcessing && <ProcessingIndicator />}
|
|
298
|
+
{messages.length === 0 && !isProcessing && <WelcomeHint columns={columns} />}
|
|
299
|
+
{isProcessing && <ProcessingIndicator columns={columns} />}
|
|
283
300
|
|
|
284
|
-
<HRule />
|
|
301
|
+
<HRule columns={columns} />
|
|
285
302
|
|
|
286
|
-
<Box paddingX={1}>
|
|
303
|
+
<Box paddingX={1} width={columns}>
|
|
287
304
|
<Box
|
|
288
305
|
borderStyle="round"
|
|
289
306
|
borderColor={isProcessing ? "gray" : "cyan"}
|
|
290
307
|
paddingX={1}
|
|
291
|
-
width=
|
|
308
|
+
width={Math.max(columns - 2, 10)}
|
|
309
|
+
overflow="hidden"
|
|
292
310
|
>
|
|
293
311
|
<Text color="cyan" bold>
|
|
294
312
|
{"❯ "}
|
|
@@ -306,7 +324,7 @@ function App({
|
|
|
306
324
|
</Box>
|
|
307
325
|
</Box>
|
|
308
326
|
|
|
309
|
-
<Box paddingX={2} justifyContent="space-between">
|
|
327
|
+
<Box paddingX={2} width={columns} justifyContent="space-between">
|
|
310
328
|
<Text dimColor>{"Ctrl+C exit"}</Text>
|
|
311
329
|
<Text dimColor>
|
|
312
330
|
{userCount} {userCount === 1 ? "message" : "messages"}
|