casabot 1.1.11 → 1.1.13
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/cli/braille-logo.d.ts +2 -0
- package/dist/cli/braille-logo.js +59 -0
- package/dist/cli/index.js +4 -9
- package/dist/tui/app.js +5 -17
- package/package.json +2 -2
- package/src/cli/braille-logo.ts +72 -0
- package/src/cli/index.ts +4 -12
- package/src/tui/app.tsx +8 -40
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Jimp, intToRGBA } from "jimp";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
const BRAILLE_BASE = 0x2800;
|
|
4
|
+
const BRAILLE_MAP = [
|
|
5
|
+
[0x01, 0x08],
|
|
6
|
+
[0x02, 0x10],
|
|
7
|
+
[0x04, 0x20],
|
|
8
|
+
[0x40, 0x80],
|
|
9
|
+
];
|
|
10
|
+
export async function renderBrailleLogo(logoPath, maxWidth) {
|
|
11
|
+
const image = await Jimp.read(logoPath);
|
|
12
|
+
const targetPixelWidth = maxWidth * 2;
|
|
13
|
+
image.resize({ w: targetPixelWidth });
|
|
14
|
+
const { width, height } = image.bitmap;
|
|
15
|
+
const lines = [];
|
|
16
|
+
for (let y = 0; y < height; y += 4) {
|
|
17
|
+
let line = "";
|
|
18
|
+
for (let x = 0; x < width; x += 2) {
|
|
19
|
+
let pattern = 0;
|
|
20
|
+
let rSum = 0;
|
|
21
|
+
let gSum = 0;
|
|
22
|
+
let bSum = 0;
|
|
23
|
+
let onCount = 0;
|
|
24
|
+
for (let row = 0; row < 4; row++) {
|
|
25
|
+
for (let col = 0; col < 2; col++) {
|
|
26
|
+
const px = x + col;
|
|
27
|
+
const py = y + row;
|
|
28
|
+
if (px >= width || py >= height)
|
|
29
|
+
continue;
|
|
30
|
+
const { r, g, b, a } = intToRGBA(image.getPixelColor(px, py));
|
|
31
|
+
const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
32
|
+
if (a > 20 && brightness > 30) {
|
|
33
|
+
pattern |= BRAILLE_MAP[row][col];
|
|
34
|
+
rSum += r;
|
|
35
|
+
gSum += g;
|
|
36
|
+
bSum += b;
|
|
37
|
+
onCount++;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (onCount > 0) {
|
|
42
|
+
const ch = String.fromCharCode(BRAILLE_BASE + pattern);
|
|
43
|
+
const avgR = Math.round(rSum / onCount);
|
|
44
|
+
const avgG = Math.round(gSum / onCount);
|
|
45
|
+
const avgB = Math.round(bSum / onCount);
|
|
46
|
+
line += chalk.rgb(avgR, avgG, avgB)(ch);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
line += " ";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
lines.push(line);
|
|
53
|
+
}
|
|
54
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
|
|
55
|
+
lines.pop();
|
|
56
|
+
}
|
|
57
|
+
return lines.join("\n");
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=braille-logo.js.map
|
package/dist/cli/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from "module";
|
|
3
2
|
import { fileURLToPath } from "url";
|
|
4
3
|
import { dirname, join } from "path";
|
|
5
4
|
import { Command } from "commander";
|
|
@@ -9,18 +8,14 @@ import { loadSkills } from "../skills/loader.js";
|
|
|
9
8
|
import { createConversation } from "../history/store.js";
|
|
10
9
|
import { startTUI } from "../tui/app.js";
|
|
11
10
|
import { setupWizard } from "./setup.js";
|
|
11
|
+
import { renderBrailleLogo } from "./braille-logo.js";
|
|
12
12
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
13
|
async function displayLogo() {
|
|
14
14
|
try {
|
|
15
|
-
const require = createRequire(import.meta.url);
|
|
16
|
-
const asciify = require("asciify-image");
|
|
17
15
|
const logoPath = join(__dirname, "..", "..", "Logo2.png");
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
color: true,
|
|
22
|
-
});
|
|
23
|
-
console.log(ascii);
|
|
16
|
+
const maxWidth = Math.min(process.stdout.columns || 80, 160);
|
|
17
|
+
const art = await renderBrailleLogo(logoPath, maxWidth);
|
|
18
|
+
console.log(art);
|
|
24
19
|
console.log("");
|
|
25
20
|
}
|
|
26
21
|
catch {
|
package/dist/tui/app.js
CHANGED
|
@@ -38,9 +38,6 @@ function getPreview(conv, maxLen = 50) {
|
|
|
38
38
|
function HRule({ columns }) {
|
|
39
39
|
return (_jsx(Box, { paddingX: 1, width: columns, children: _jsx(Text, { dimColor: true, children: "─".repeat(Math.max(columns - 4, 1)) }) }));
|
|
40
40
|
}
|
|
41
|
-
function HeaderBlock({ columns }) {
|
|
42
|
-
return (_jsxs(Box, { flexDirection: "column", paddingTop: 1, width: columns, children: [_jsx(Box, { paddingX: 2, children: _jsx(Gradient, { colors: [BRAND_RED, BRAND_BLUE], 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 })] }));
|
|
43
|
-
}
|
|
44
41
|
function UserMessageView({ content, columns }) {
|
|
45
42
|
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, marginTop: 1, width: columns, children: [_jsx(Text, { color: BRAND_RED, bold: true, children: "▶ You" }), _jsx(Box, { marginLeft: 2, width: Math.max(columns - 6, 10), children: _jsx(Text, { wrap: "wrap", children: content }) })] }));
|
|
46
43
|
}
|
|
@@ -228,23 +225,14 @@ function App({ provider, conversation: initialConversation, skills, }) {
|
|
|
228
225
|
});
|
|
229
226
|
const userCount = messages.filter((m) => m.role === "user").length;
|
|
230
227
|
const convId = conversationRef.current.id;
|
|
231
|
-
const items = useMemo(() =>
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
type: "message",
|
|
236
|
-
message: msg,
|
|
237
|
-
})),
|
|
238
|
-
], [messages, convId]);
|
|
228
|
+
const items = useMemo(() => messages.map((msg, i) => ({
|
|
229
|
+
key: `${convId}-msg-${i}`,
|
|
230
|
+
message: msg,
|
|
231
|
+
})), [messages, convId]);
|
|
239
232
|
if (mode === "history") {
|
|
240
233
|
return (_jsx(HistoryBrowser, { columns: columns, currentId: conversationRef.current.id, onSelect: handleHistorySelect, onBack: () => setMode("chat") }));
|
|
241
234
|
}
|
|
242
|
-
return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Static, { items: items, children: (item) => {
|
|
243
|
-
if (item.type === "header") {
|
|
244
|
-
return (_jsx(Box, { flexDirection: "column", width: columns, children: _jsx(HeaderBlock, { columns: columns }) }, item.key));
|
|
245
|
-
}
|
|
246
|
-
return (_jsx(Box, { flexDirection: "column", width: columns, children: _jsx(MessageView, { message: item.message, columns: columns }) }, item.key));
|
|
247
|
-
} }), 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" : BRAND_BLUE, paddingX: 1, width: Math.max(columns - 2, 10), overflow: "hidden", children: [_jsx(Text, { color: BRAND_BLUE, bold: true, children: "❯ " }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: (val) => {
|
|
235
|
+
return (_jsxs(Box, { flexDirection: "column", width: columns, children: [_jsx(Static, { items: items, children: (item) => (_jsx(Box, { flexDirection: "column", width: columns, children: _jsx(MessageView, { message: item.message, columns: columns }) }, item.key)) }), 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" : BRAND_BLUE, paddingX: 1, width: Math.max(columns - 2, 10), overflow: "hidden", children: [_jsx(Text, { color: BRAND_BLUE, bold: true, children: "❯ " }), _jsx(TextInput, { value: input, onChange: setInput, onSubmit: (val) => {
|
|
248
236
|
handleSubmit(val).catch(() => { });
|
|
249
237
|
}, placeholder: "Type your message\u2026", focus: !isProcessing, showCursor: true })] }) }), _jsxs(Box, { paddingX: 2, width: columns, justifyContent: "space-between", children: [_jsx(Text, { dimColor: true, children: isProcessing
|
|
250
238
|
? "ESC / Ctrl+C cancel"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "casabot",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.13",
|
|
4
4
|
"description": "CasAbot — Skill-driven multi-agent orchestrator system",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
"license": "Apache-2.0",
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@anthropic-ai/sdk": "^0.52.0",
|
|
31
|
-
"asciify-image": "^0.1.10",
|
|
32
31
|
"chalk": "^5.4.1",
|
|
33
32
|
"commander": "^13.1.0",
|
|
34
33
|
"gray-matter": "^4.0.3",
|
|
@@ -36,6 +35,7 @@
|
|
|
36
35
|
"ink-gradient": "^4.0.0",
|
|
37
36
|
"ink-spinner": "^5.0.0",
|
|
38
37
|
"ink-text-input": "^6.0.0",
|
|
38
|
+
"jimp": "^1.6.0",
|
|
39
39
|
"marked": "^15.0.12",
|
|
40
40
|
"marked-terminal": "^7.3.0",
|
|
41
41
|
"openai": "^5.1.0",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Jimp, intToRGBA } from "jimp";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
|
|
4
|
+
const BRAILLE_BASE = 0x2800;
|
|
5
|
+
|
|
6
|
+
const BRAILLE_MAP = [
|
|
7
|
+
[0x01, 0x08],
|
|
8
|
+
[0x02, 0x10],
|
|
9
|
+
[0x04, 0x20],
|
|
10
|
+
[0x40, 0x80],
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
export async function renderBrailleLogo(
|
|
14
|
+
logoPath: string,
|
|
15
|
+
maxWidth: number,
|
|
16
|
+
): Promise<string> {
|
|
17
|
+
const image = await Jimp.read(logoPath);
|
|
18
|
+
const targetPixelWidth = maxWidth * 2;
|
|
19
|
+
image.resize({ w: targetPixelWidth });
|
|
20
|
+
|
|
21
|
+
const { width, height } = image.bitmap;
|
|
22
|
+
const lines: string[] = [];
|
|
23
|
+
|
|
24
|
+
for (let y = 0; y < height; y += 4) {
|
|
25
|
+
let line = "";
|
|
26
|
+
|
|
27
|
+
for (let x = 0; x < width; x += 2) {
|
|
28
|
+
let pattern = 0;
|
|
29
|
+
let rSum = 0;
|
|
30
|
+
let gSum = 0;
|
|
31
|
+
let bSum = 0;
|
|
32
|
+
let onCount = 0;
|
|
33
|
+
|
|
34
|
+
for (let row = 0; row < 4; row++) {
|
|
35
|
+
for (let col = 0; col < 2; col++) {
|
|
36
|
+
const px = x + col;
|
|
37
|
+
const py = y + row;
|
|
38
|
+
if (px >= width || py >= height) continue;
|
|
39
|
+
|
|
40
|
+
const { r, g, b, a } = intToRGBA(image.getPixelColor(px, py));
|
|
41
|
+
const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
42
|
+
|
|
43
|
+
if (a > 20 && brightness > 30) {
|
|
44
|
+
pattern |= BRAILLE_MAP[row][col];
|
|
45
|
+
rSum += r;
|
|
46
|
+
gSum += g;
|
|
47
|
+
bSum += b;
|
|
48
|
+
onCount++;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (onCount > 0) {
|
|
54
|
+
const ch = String.fromCharCode(BRAILLE_BASE + pattern);
|
|
55
|
+
const avgR = Math.round(rSum / onCount);
|
|
56
|
+
const avgG = Math.round(gSum / onCount);
|
|
57
|
+
const avgB = Math.round(bSum / onCount);
|
|
58
|
+
line += chalk.rgb(avgR, avgG, avgB)(ch);
|
|
59
|
+
} else {
|
|
60
|
+
line += " ";
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
lines.push(line);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
while (lines.length > 0 && lines[lines.length - 1].trim() === "") {
|
|
68
|
+
lines.pop();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return lines.join("\n");
|
|
72
|
+
}
|
package/src/cli/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { createRequire } from "module";
|
|
4
3
|
import { fileURLToPath } from "url";
|
|
5
4
|
import { dirname, join } from "path";
|
|
6
5
|
import { Command } from "commander";
|
|
@@ -10,23 +9,16 @@ import { loadSkills } from "../skills/loader.js";
|
|
|
10
9
|
import { createConversation } from "../history/store.js";
|
|
11
10
|
import { startTUI } from "../tui/app.js";
|
|
12
11
|
import { setupWizard } from "./setup.js";
|
|
12
|
+
import { renderBrailleLogo } from "./braille-logo.js";
|
|
13
13
|
|
|
14
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
15
15
|
|
|
16
16
|
async function displayLogo(): Promise<void> {
|
|
17
17
|
try {
|
|
18
|
-
const require = createRequire(import.meta.url);
|
|
19
|
-
const asciify = require("asciify-image") as (
|
|
20
|
-
path: string,
|
|
21
|
-
opts: Record<string, unknown>,
|
|
22
|
-
) => Promise<string>;
|
|
23
18
|
const logoPath = join(__dirname, "..", "..", "Logo2.png");
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
color: true,
|
|
28
|
-
});
|
|
29
|
-
console.log(ascii);
|
|
19
|
+
const maxWidth = Math.min(process.stdout.columns || 80, 160);
|
|
20
|
+
const art = await renderBrailleLogo(logoPath, maxWidth);
|
|
21
|
+
console.log(art);
|
|
30
22
|
console.log("");
|
|
31
23
|
} catch {
|
|
32
24
|
// Logo display is non-critical; silently skip on failure
|
package/src/tui/app.tsx
CHANGED
|
@@ -56,24 +56,6 @@ function HRule({ columns }: { columns: number }): React.ReactElement {
|
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
function HeaderBlock({ columns }: { columns: number }): React.ReactElement {
|
|
60
|
-
return (
|
|
61
|
-
<Box flexDirection="column" paddingTop={1} width={columns}>
|
|
62
|
-
<Box paddingX={2}>
|
|
63
|
-
<Gradient colors={[BRAND_RED, BRAND_BLUE]}>
|
|
64
|
-
<Text bold>{"✦ CasAbot"}</Text>
|
|
65
|
-
</Gradient>
|
|
66
|
-
</Box>
|
|
67
|
-
<Box paddingX={2}>
|
|
68
|
-
<Text wrap="wrap" dimColor>
|
|
69
|
-
{"Cassiopeia A — Freely creates everything, like a supernova explosion."}
|
|
70
|
-
</Text>
|
|
71
|
-
</Box>
|
|
72
|
-
<HRule columns={columns} />
|
|
73
|
-
</Box>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
59
|
function UserMessageView({ content, columns }: { content: string; columns: number }): React.ReactElement {
|
|
78
60
|
return (
|
|
79
61
|
<Box flexDirection="column" paddingX={2} marginTop={1} width={columns}>
|
|
@@ -364,9 +346,7 @@ function HistoryBrowser({
|
|
|
364
346
|
);
|
|
365
347
|
}
|
|
366
348
|
|
|
367
|
-
type DisplayItem =
|
|
368
|
-
| { key: string; type: "header" }
|
|
369
|
-
| { key: string; type: "message"; message: Message };
|
|
349
|
+
type DisplayItem = { key: string; message: Message };
|
|
370
350
|
|
|
371
351
|
type AppMode = "chat" | "history";
|
|
372
352
|
|
|
@@ -498,16 +478,13 @@ function App({
|
|
|
498
478
|
const convId = conversationRef.current.id;
|
|
499
479
|
|
|
500
480
|
const items = useMemo(
|
|
501
|
-
(): DisplayItem[] =>
|
|
502
|
-
|
|
503
|
-
...messages.map(
|
|
481
|
+
(): DisplayItem[] =>
|
|
482
|
+
messages.map(
|
|
504
483
|
(msg, i): DisplayItem => ({
|
|
505
484
|
key: `${convId}-msg-${i}`,
|
|
506
|
-
type: "message",
|
|
507
485
|
message: msg,
|
|
508
486
|
}),
|
|
509
487
|
),
|
|
510
|
-
],
|
|
511
488
|
[messages, convId],
|
|
512
489
|
);
|
|
513
490
|
|
|
@@ -525,20 +502,11 @@ function App({
|
|
|
525
502
|
return (
|
|
526
503
|
<Box flexDirection="column" width={columns}>
|
|
527
504
|
<Static items={items}>
|
|
528
|
-
{(item) =>
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
</Box>
|
|
534
|
-
);
|
|
535
|
-
}
|
|
536
|
-
return (
|
|
537
|
-
<Box key={item.key} flexDirection="column" width={columns}>
|
|
538
|
-
<MessageView message={item.message} columns={columns} />
|
|
539
|
-
</Box>
|
|
540
|
-
);
|
|
541
|
-
}}
|
|
505
|
+
{(item) => (
|
|
506
|
+
<Box key={item.key} flexDirection="column" width={columns}>
|
|
507
|
+
<MessageView message={item.message} columns={columns} />
|
|
508
|
+
</Box>
|
|
509
|
+
)}
|
|
542
510
|
</Static>
|
|
543
511
|
|
|
544
512
|
{messages.length === 0 && !isProcessing && <WelcomeHint columns={columns} />}
|