@satori-sh/cli 0.0.14 → 0.0.16
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/index.js +8 -255
- package/dist/ui-AFMM6JTQ.js +252 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import { readFileSync, realpathSync } from "fs";
|
|
6
6
|
import { execFile } from "child_process";
|
|
7
|
-
import { dirname
|
|
8
|
-
import { fileURLToPath
|
|
7
|
+
import { dirname, join as join2 } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
|
|
11
11
|
// src/config.ts
|
|
@@ -227,256 +227,6 @@ ${memoryText}`
|
|
|
227
227
|
return [systemMessage, ...messages];
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
-
// src/ui.tsx
|
|
231
|
-
import { render, useRenderer, useTerminalDimensions } from "@opentui/solid";
|
|
232
|
-
import { For, Show, createSignal, onMount, onCleanup } from "solid-js";
|
|
233
|
-
import cliSpinners from "cli-spinners";
|
|
234
|
-
|
|
235
|
-
// src/logo.ts
|
|
236
|
-
import { dirname, join as join2 } from "path";
|
|
237
|
-
import { fileURLToPath } from "url";
|
|
238
|
-
async function loadLogo() {
|
|
239
|
-
const { default: fs } = await import("fs");
|
|
240
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
241
|
-
const logoPath = join2(__dirname, "..", "logos", "satori.ans");
|
|
242
|
-
return fs.readFileSync(logoPath, "utf8");
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// src/ui.tsx
|
|
246
|
-
async function runInteractiveApp({
|
|
247
|
-
initialPrompt,
|
|
248
|
-
options,
|
|
249
|
-
processUserInput,
|
|
250
|
-
infoLine,
|
|
251
|
-
infoDisplay
|
|
252
|
-
}) {
|
|
253
|
-
const logo = await loadLogo();
|
|
254
|
-
console.log(` ${logo}`);
|
|
255
|
-
const rows = process.stdout.rows ?? 24;
|
|
256
|
-
const logoHeight = logo.endsWith("\n") ? logo.slice(0, -1).split("\n").length : logo.split("\n").length;
|
|
257
|
-
const splitHeight = Math.max(1, rows - logoHeight - 1);
|
|
258
|
-
render(
|
|
259
|
-
() => /* @__PURE__ */ React.createElement(
|
|
260
|
-
App,
|
|
261
|
-
{
|
|
262
|
-
initialPrompt,
|
|
263
|
-
options,
|
|
264
|
-
processUserInput,
|
|
265
|
-
infoLine,
|
|
266
|
-
infoDisplay
|
|
267
|
-
}
|
|
268
|
-
),
|
|
269
|
-
{
|
|
270
|
-
useAlternateScreen: false,
|
|
271
|
-
exitOnCtrlC: true,
|
|
272
|
-
useMouse: true,
|
|
273
|
-
enableMouseMovement: true,
|
|
274
|
-
experimental_splitHeight: splitHeight
|
|
275
|
-
}
|
|
276
|
-
);
|
|
277
|
-
}
|
|
278
|
-
function App({ initialPrompt, options, processUserInput, infoLine, infoDisplay }) {
|
|
279
|
-
const renderer = useRenderer();
|
|
280
|
-
const dimensions = useTerminalDimensions();
|
|
281
|
-
const [messages, setMessages] = createSignal([]);
|
|
282
|
-
const [inputValue, setInputValue] = createSignal("");
|
|
283
|
-
const [showIntro, setShowIntro] = createSignal(true);
|
|
284
|
-
const [isFullScreen, setIsFullScreen] = createSignal(false);
|
|
285
|
-
const [spinnerFrame, setSpinnerFrame] = createSignal(0);
|
|
286
|
-
const [isLoading, setIsLoading] = createSignal(false);
|
|
287
|
-
const promptFg = "#00ffff";
|
|
288
|
-
const responseFg = "#ffffff";
|
|
289
|
-
const promptBg = "#2b2b2b";
|
|
290
|
-
let inputRef;
|
|
291
|
-
let currentMemoryId = options.memoryId;
|
|
292
|
-
let messageId = 0;
|
|
293
|
-
const usageText = infoDisplay?.usageLine ?? infoLine ?? "";
|
|
294
|
-
const versionText = infoDisplay?.versionLine ?? "";
|
|
295
|
-
const modelText = infoDisplay?.modelLine ?? "";
|
|
296
|
-
const appendMessage = (role, text) => {
|
|
297
|
-
setMessages((prev) => [...prev, { id: messageId++, role, text }]);
|
|
298
|
-
};
|
|
299
|
-
const exitApp = () => {
|
|
300
|
-
renderer.destroy();
|
|
301
|
-
process.exit(0);
|
|
302
|
-
};
|
|
303
|
-
const submitPrompt = async (raw) => {
|
|
304
|
-
const trimmed = raw.trim();
|
|
305
|
-
if (!trimmed) return;
|
|
306
|
-
if (trimmed.toLowerCase() === "exit" || trimmed.toLowerCase() === "quit") {
|
|
307
|
-
exitApp();
|
|
308
|
-
return;
|
|
309
|
-
}
|
|
310
|
-
if (showIntro()) {
|
|
311
|
-
setShowIntro(false);
|
|
312
|
-
}
|
|
313
|
-
if (!isFullScreen()) {
|
|
314
|
-
setIsFullScreen(true);
|
|
315
|
-
}
|
|
316
|
-
setInputValue("");
|
|
317
|
-
if (inputRef) {
|
|
318
|
-
inputRef.value = "";
|
|
319
|
-
}
|
|
320
|
-
appendMessage("prompt", trimmed);
|
|
321
|
-
try {
|
|
322
|
-
setIsLoading(true);
|
|
323
|
-
const result = await processUserInput(trimmed, { ...options, memoryId: currentMemoryId }, "tui");
|
|
324
|
-
currentMemoryId = result.memoryId;
|
|
325
|
-
appendMessage("response", result.response);
|
|
326
|
-
if (result.instruction) {
|
|
327
|
-
appendMessage("response", result.instruction);
|
|
328
|
-
}
|
|
329
|
-
} catch (error) {
|
|
330
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
331
|
-
appendMessage("response", `Error: ${message}`);
|
|
332
|
-
} finally {
|
|
333
|
-
setIsLoading(false);
|
|
334
|
-
}
|
|
335
|
-
};
|
|
336
|
-
onMount(async () => {
|
|
337
|
-
const spinner = cliSpinners.dots;
|
|
338
|
-
const timer = setInterval(() => {
|
|
339
|
-
if (isLoading()) {
|
|
340
|
-
setSpinnerFrame((prev) => (prev + 1) % spinner.frames.length);
|
|
341
|
-
}
|
|
342
|
-
}, spinner.interval);
|
|
343
|
-
onCleanup(() => clearInterval(timer));
|
|
344
|
-
if (initialPrompt) {
|
|
345
|
-
await submitPrompt(initialPrompt);
|
|
346
|
-
}
|
|
347
|
-
if (inputRef) {
|
|
348
|
-
inputRef.focus();
|
|
349
|
-
}
|
|
350
|
-
});
|
|
351
|
-
const inputBoxWidth = () => Math.max(1, Math.round(dimensions().width * 0.6));
|
|
352
|
-
const inputBoxLeft = () => Math.max(0, Math.round(dimensions().width * 0.15));
|
|
353
|
-
const inputBoxHeight = () => isFullScreen() ? 7 : 14;
|
|
354
|
-
const inputBoxTop = () => isFullScreen() ? Math.max(1, dimensions().height - inputBoxHeight() - 2) : Math.max(1, Math.round(dimensions().height * 0.666));
|
|
355
|
-
const messagesTop = () => 1;
|
|
356
|
-
const messagesHeight = () => Math.max(1, inputBoxTop() - messagesTop() - 1);
|
|
357
|
-
const messagesWidth = () => Math.min(dimensions().width - 2, inputBoxWidth() + 10);
|
|
358
|
-
const messagesLeft = () => Math.max(1, inputBoxLeft() - 5);
|
|
359
|
-
return /* @__PURE__ */ React.createElement("box", { width: "100%", height: "100%", flexDirection: "column" }, /* @__PURE__ */ React.createElement(
|
|
360
|
-
"scrollbox",
|
|
361
|
-
{
|
|
362
|
-
id: "messages",
|
|
363
|
-
width: messagesWidth(),
|
|
364
|
-
height: messagesHeight(),
|
|
365
|
-
position: "absolute",
|
|
366
|
-
left: messagesLeft(),
|
|
367
|
-
top: messagesTop(),
|
|
368
|
-
paddingLeft: 1,
|
|
369
|
-
paddingRight: 1,
|
|
370
|
-
focused: true,
|
|
371
|
-
stickyScroll: true,
|
|
372
|
-
stickyStart: "bottom"
|
|
373
|
-
},
|
|
374
|
-
/* @__PURE__ */ React.createElement("box", { width: "100%", flexDirection: "column" }, /* @__PURE__ */ React.createElement(For, { each: messages() }, (message) => /* @__PURE__ */ React.createElement(
|
|
375
|
-
"box",
|
|
376
|
-
{
|
|
377
|
-
width: "100%",
|
|
378
|
-
flexDirection: "row",
|
|
379
|
-
justifyContent: message.role === "prompt" ? "flex-start" : "flex-end",
|
|
380
|
-
marginBottom: 1
|
|
381
|
-
},
|
|
382
|
-
/* @__PURE__ */ React.createElement(
|
|
383
|
-
"box",
|
|
384
|
-
{
|
|
385
|
-
paddingLeft: 1,
|
|
386
|
-
paddingRight: 1,
|
|
387
|
-
paddingTop: 1,
|
|
388
|
-
paddingBottom: 1,
|
|
389
|
-
backgroundColor: message.role === "prompt" ? promptBg : void 0
|
|
390
|
-
},
|
|
391
|
-
/* @__PURE__ */ React.createElement(
|
|
392
|
-
"text",
|
|
393
|
-
{
|
|
394
|
-
fg: message.role === "prompt" ? promptFg : responseFg,
|
|
395
|
-
width: "100%",
|
|
396
|
-
wrapMode: "word",
|
|
397
|
-
selectable: false
|
|
398
|
-
},
|
|
399
|
-
message.text
|
|
400
|
-
)
|
|
401
|
-
)
|
|
402
|
-
)))
|
|
403
|
-
), /* @__PURE__ */ React.createElement(
|
|
404
|
-
"box",
|
|
405
|
-
{
|
|
406
|
-
id: "input-box",
|
|
407
|
-
width: inputBoxWidth(),
|
|
408
|
-
height: inputBoxHeight(),
|
|
409
|
-
position: "absolute",
|
|
410
|
-
left: inputBoxLeft(),
|
|
411
|
-
top: inputBoxTop(),
|
|
412
|
-
paddingLeft: 1,
|
|
413
|
-
paddingRight: 1,
|
|
414
|
-
paddingTop: 1,
|
|
415
|
-
flexDirection: "column"
|
|
416
|
-
},
|
|
417
|
-
/* @__PURE__ */ React.createElement(For, { each: !isFullScreen() && showIntro() ? [
|
|
418
|
-
"Use Satori just like you would use ChatGPT.",
|
|
419
|
-
"Except, it stores your conversations in a long term memory.",
|
|
420
|
-
"The memories you store here can be accessed through the SDK."
|
|
421
|
-
] : [] }, (line) => /* @__PURE__ */ React.createElement("text", { fg: "cyan" }, line)),
|
|
422
|
-
/* @__PURE__ */ React.createElement(
|
|
423
|
-
"box",
|
|
424
|
-
{
|
|
425
|
-
id: "input-box",
|
|
426
|
-
width: inputBoxWidth(),
|
|
427
|
-
height: 5,
|
|
428
|
-
backgroundColor: "#1a1a1a",
|
|
429
|
-
flexDirection: "column",
|
|
430
|
-
justifyContent: "center"
|
|
431
|
-
},
|
|
432
|
-
/* @__PURE__ */ React.createElement(
|
|
433
|
-
"input",
|
|
434
|
-
{
|
|
435
|
-
id: "input",
|
|
436
|
-
width: "100%",
|
|
437
|
-
height: 1,
|
|
438
|
-
placeholder: "Type a message and press Enter...",
|
|
439
|
-
focusedBackgroundColor: "#1a1a1a",
|
|
440
|
-
onInput: (value) => setInputValue(value),
|
|
441
|
-
onSubmit: () => submitPrompt(inputValue()),
|
|
442
|
-
ref: (r) => {
|
|
443
|
-
inputRef = r;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
),
|
|
447
|
-
/* @__PURE__ */ React.createElement("box", { flexDirection: "row", flexShrink: 0, paddingTop: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#ffffff" }, modelText))
|
|
448
|
-
)
|
|
449
|
-
), /* @__PURE__ */ React.createElement(Show, { when: isLoading() }, /* @__PURE__ */ React.createElement(
|
|
450
|
-
"box",
|
|
451
|
-
{
|
|
452
|
-
id: "spinner",
|
|
453
|
-
position: "absolute",
|
|
454
|
-
left: inputBoxLeft(),
|
|
455
|
-
top: inputBoxTop() + inputBoxHeight(),
|
|
456
|
-
paddingLeft: 1
|
|
457
|
-
},
|
|
458
|
-
/* @__PURE__ */ React.createElement("text", { fg: "#00ffff" }, cliSpinners.dots.frames[spinnerFrame()])
|
|
459
|
-
)), /* @__PURE__ */ React.createElement(
|
|
460
|
-
"box",
|
|
461
|
-
{
|
|
462
|
-
id: "footer",
|
|
463
|
-
width: dimensions().width,
|
|
464
|
-
height: 1,
|
|
465
|
-
position: "absolute",
|
|
466
|
-
bottom: 0,
|
|
467
|
-
left: 0,
|
|
468
|
-
backgroundColor: "#000000",
|
|
469
|
-
paddingLeft: 1,
|
|
470
|
-
paddingRight: 1,
|
|
471
|
-
flexDirection: "row",
|
|
472
|
-
justifyContent: "space-between",
|
|
473
|
-
alignItems: "center"
|
|
474
|
-
},
|
|
475
|
-
/* @__PURE__ */ React.createElement("text", { fg: "#00ffff", wrapMode: "none", width: "100%" }, usageText),
|
|
476
|
-
/* @__PURE__ */ React.createElement("box", { flexShrink: 0, paddingLeft: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#00ffff" }, versionText))
|
|
477
|
-
));
|
|
478
|
-
}
|
|
479
|
-
|
|
480
230
|
// src/index.ts
|
|
481
231
|
async function main() {
|
|
482
232
|
const argv = process.argv.slice(2);
|
|
@@ -494,8 +244,8 @@ async function main() {
|
|
|
494
244
|
program.option("--memory-id <id>", "Memory ID for scoping");
|
|
495
245
|
const DEFAULT_LLM_MODEL = "gpt-4o";
|
|
496
246
|
const getCliVersion = () => {
|
|
497
|
-
const __dirname =
|
|
498
|
-
const packagePath =
|
|
247
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
248
|
+
const packagePath = join2(__dirname, "..", "package.json");
|
|
499
249
|
const raw = readFileSync(packagePath, "utf8");
|
|
500
250
|
const data = JSON.parse(raw);
|
|
501
251
|
return data.version ?? "unknown";
|
|
@@ -583,6 +333,9 @@ ${instruction}`);
|
|
|
583
333
|
return;
|
|
584
334
|
}
|
|
585
335
|
const info = await getInfoDisplay();
|
|
336
|
+
const { runInteractiveApp } = await import("./ui-AFMM6JTQ.js").catch(() => {
|
|
337
|
+
throw new Error("Interactive mode requires Bun. Run `bunx @satori-sh/cli`.");
|
|
338
|
+
});
|
|
586
339
|
await runInteractiveApp({
|
|
587
340
|
initialPrompt,
|
|
588
341
|
options,
|
|
@@ -649,7 +402,7 @@ ${instruction}`);
|
|
|
649
402
|
program.parse();
|
|
650
403
|
}
|
|
651
404
|
var entryPath = process.argv[1] ? realpathSync(process.argv[1]) : "";
|
|
652
|
-
var modulePath = realpathSync(
|
|
405
|
+
var modulePath = realpathSync(fileURLToPath(import.meta.url));
|
|
653
406
|
if (entryPath === modulePath) {
|
|
654
407
|
main();
|
|
655
408
|
}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// src/ui.tsx
|
|
2
|
+
import { render, useRenderer, useTerminalDimensions } from "@opentui/solid";
|
|
3
|
+
import { For, Show, createSignal, onMount, onCleanup } from "solid-js";
|
|
4
|
+
import cliSpinners from "cli-spinners";
|
|
5
|
+
|
|
6
|
+
// src/logo.ts
|
|
7
|
+
import { dirname, join } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
async function loadLogo() {
|
|
10
|
+
const { default: fs } = await import("fs");
|
|
11
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const logoPath = join(__dirname, "..", "logos", "satori.ans");
|
|
13
|
+
return fs.readFileSync(logoPath, "utf8");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/ui.tsx
|
|
17
|
+
async function runInteractiveApp({
|
|
18
|
+
initialPrompt,
|
|
19
|
+
options,
|
|
20
|
+
processUserInput,
|
|
21
|
+
infoLine,
|
|
22
|
+
infoDisplay
|
|
23
|
+
}) {
|
|
24
|
+
const logo = await loadLogo();
|
|
25
|
+
console.log(` ${logo}`);
|
|
26
|
+
const rows = process.stdout.rows ?? 24;
|
|
27
|
+
const logoHeight = logo.endsWith("\n") ? logo.slice(0, -1).split("\n").length : logo.split("\n").length;
|
|
28
|
+
const splitHeight = Math.max(1, rows - logoHeight - 1);
|
|
29
|
+
render(
|
|
30
|
+
() => /* @__PURE__ */ React.createElement(
|
|
31
|
+
App,
|
|
32
|
+
{
|
|
33
|
+
initialPrompt,
|
|
34
|
+
options,
|
|
35
|
+
processUserInput,
|
|
36
|
+
infoLine,
|
|
37
|
+
infoDisplay
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
{
|
|
41
|
+
useAlternateScreen: false,
|
|
42
|
+
exitOnCtrlC: true,
|
|
43
|
+
useMouse: true,
|
|
44
|
+
enableMouseMovement: true,
|
|
45
|
+
experimental_splitHeight: splitHeight
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
function App({ initialPrompt, options, processUserInput, infoLine, infoDisplay }) {
|
|
50
|
+
const renderer = useRenderer();
|
|
51
|
+
const dimensions = useTerminalDimensions();
|
|
52
|
+
const [messages, setMessages] = createSignal([]);
|
|
53
|
+
const [inputValue, setInputValue] = createSignal("");
|
|
54
|
+
const [showIntro, setShowIntro] = createSignal(true);
|
|
55
|
+
const [isFullScreen, setIsFullScreen] = createSignal(false);
|
|
56
|
+
const [spinnerFrame, setSpinnerFrame] = createSignal(0);
|
|
57
|
+
const [isLoading, setIsLoading] = createSignal(false);
|
|
58
|
+
const promptFg = "#00ffff";
|
|
59
|
+
const responseFg = "#ffffff";
|
|
60
|
+
const promptBg = "#2b2b2b";
|
|
61
|
+
let inputRef;
|
|
62
|
+
let currentMemoryId = options.memoryId;
|
|
63
|
+
let messageId = 0;
|
|
64
|
+
const usageText = infoDisplay?.usageLine ?? infoLine ?? "";
|
|
65
|
+
const versionText = infoDisplay?.versionLine ?? "";
|
|
66
|
+
const modelText = infoDisplay?.modelLine ?? "";
|
|
67
|
+
const appendMessage = (role, text) => {
|
|
68
|
+
setMessages((prev) => [...prev, { id: messageId++, role, text }]);
|
|
69
|
+
};
|
|
70
|
+
const exitApp = () => {
|
|
71
|
+
renderer.destroy();
|
|
72
|
+
process.exit(0);
|
|
73
|
+
};
|
|
74
|
+
const submitPrompt = async (raw) => {
|
|
75
|
+
const trimmed = raw.trim();
|
|
76
|
+
if (!trimmed) return;
|
|
77
|
+
if (trimmed.toLowerCase() === "exit" || trimmed.toLowerCase() === "quit") {
|
|
78
|
+
exitApp();
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (showIntro()) {
|
|
82
|
+
setShowIntro(false);
|
|
83
|
+
}
|
|
84
|
+
if (!isFullScreen()) {
|
|
85
|
+
setIsFullScreen(true);
|
|
86
|
+
}
|
|
87
|
+
setInputValue("");
|
|
88
|
+
if (inputRef) {
|
|
89
|
+
inputRef.value = "";
|
|
90
|
+
}
|
|
91
|
+
appendMessage("prompt", trimmed);
|
|
92
|
+
try {
|
|
93
|
+
setIsLoading(true);
|
|
94
|
+
const result = await processUserInput(trimmed, { ...options, memoryId: currentMemoryId }, "tui");
|
|
95
|
+
currentMemoryId = result.memoryId;
|
|
96
|
+
appendMessage("response", result.response);
|
|
97
|
+
if (result.instruction) {
|
|
98
|
+
appendMessage("response", result.instruction);
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
102
|
+
appendMessage("response", `Error: ${message}`);
|
|
103
|
+
} finally {
|
|
104
|
+
setIsLoading(false);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
onMount(async () => {
|
|
108
|
+
const spinner = cliSpinners.dots;
|
|
109
|
+
const timer = setInterval(() => {
|
|
110
|
+
if (isLoading()) {
|
|
111
|
+
setSpinnerFrame((prev) => (prev + 1) % spinner.frames.length);
|
|
112
|
+
}
|
|
113
|
+
}, spinner.interval);
|
|
114
|
+
onCleanup(() => clearInterval(timer));
|
|
115
|
+
if (initialPrompt) {
|
|
116
|
+
await submitPrompt(initialPrompt);
|
|
117
|
+
}
|
|
118
|
+
if (inputRef) {
|
|
119
|
+
inputRef.focus();
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
const inputBoxWidth = () => Math.max(1, Math.round(dimensions().width * 0.6));
|
|
123
|
+
const inputBoxLeft = () => Math.max(0, Math.round(dimensions().width * 0.15));
|
|
124
|
+
const inputBoxHeight = () => isFullScreen() ? 7 : 14;
|
|
125
|
+
const inputBoxTop = () => isFullScreen() ? Math.max(1, dimensions().height - inputBoxHeight() - 2) : Math.max(1, Math.round(dimensions().height * 0.666));
|
|
126
|
+
const messagesTop = () => 1;
|
|
127
|
+
const messagesHeight = () => Math.max(1, inputBoxTop() - messagesTop() - 1);
|
|
128
|
+
const messagesWidth = () => Math.min(dimensions().width - 2, inputBoxWidth() + 10);
|
|
129
|
+
const messagesLeft = () => Math.max(1, inputBoxLeft() - 5);
|
|
130
|
+
return /* @__PURE__ */ React.createElement("box", { width: "100%", height: "100%", flexDirection: "column" }, /* @__PURE__ */ React.createElement(
|
|
131
|
+
"scrollbox",
|
|
132
|
+
{
|
|
133
|
+
id: "messages",
|
|
134
|
+
width: messagesWidth(),
|
|
135
|
+
height: messagesHeight(),
|
|
136
|
+
position: "absolute",
|
|
137
|
+
left: messagesLeft(),
|
|
138
|
+
top: messagesTop(),
|
|
139
|
+
paddingLeft: 1,
|
|
140
|
+
paddingRight: 1,
|
|
141
|
+
focused: true,
|
|
142
|
+
stickyScroll: true,
|
|
143
|
+
stickyStart: "bottom"
|
|
144
|
+
},
|
|
145
|
+
/* @__PURE__ */ React.createElement("box", { width: "100%", flexDirection: "column" }, /* @__PURE__ */ React.createElement(For, { each: messages() }, (message) => /* @__PURE__ */ React.createElement(
|
|
146
|
+
"box",
|
|
147
|
+
{
|
|
148
|
+
width: "100%",
|
|
149
|
+
flexDirection: "row",
|
|
150
|
+
justifyContent: message.role === "prompt" ? "flex-start" : "flex-end",
|
|
151
|
+
marginBottom: 1
|
|
152
|
+
},
|
|
153
|
+
/* @__PURE__ */ React.createElement(
|
|
154
|
+
"box",
|
|
155
|
+
{
|
|
156
|
+
paddingLeft: 1,
|
|
157
|
+
paddingRight: 1,
|
|
158
|
+
paddingTop: 1,
|
|
159
|
+
paddingBottom: 1,
|
|
160
|
+
backgroundColor: message.role === "prompt" ? promptBg : void 0
|
|
161
|
+
},
|
|
162
|
+
/* @__PURE__ */ React.createElement(
|
|
163
|
+
"text",
|
|
164
|
+
{
|
|
165
|
+
fg: message.role === "prompt" ? promptFg : responseFg,
|
|
166
|
+
width: "100%",
|
|
167
|
+
wrapMode: "word",
|
|
168
|
+
selectable: false
|
|
169
|
+
},
|
|
170
|
+
message.text
|
|
171
|
+
)
|
|
172
|
+
)
|
|
173
|
+
)))
|
|
174
|
+
), /* @__PURE__ */ React.createElement(
|
|
175
|
+
"box",
|
|
176
|
+
{
|
|
177
|
+
id: "input-box",
|
|
178
|
+
width: inputBoxWidth(),
|
|
179
|
+
height: inputBoxHeight(),
|
|
180
|
+
position: "absolute",
|
|
181
|
+
left: inputBoxLeft(),
|
|
182
|
+
top: inputBoxTop(),
|
|
183
|
+
paddingLeft: 1,
|
|
184
|
+
paddingRight: 1,
|
|
185
|
+
paddingTop: 1,
|
|
186
|
+
flexDirection: "column"
|
|
187
|
+
},
|
|
188
|
+
/* @__PURE__ */ React.createElement(For, { each: !isFullScreen() && showIntro() ? [
|
|
189
|
+
"Use Satori just like you would use ChatGPT.",
|
|
190
|
+
"Except, it stores your conversations in a long term memory.",
|
|
191
|
+
"The memories you store here can be accessed through the SDK."
|
|
192
|
+
] : [] }, (line) => /* @__PURE__ */ React.createElement("text", { fg: "cyan" }, line)),
|
|
193
|
+
/* @__PURE__ */ React.createElement(
|
|
194
|
+
"box",
|
|
195
|
+
{
|
|
196
|
+
id: "input-box",
|
|
197
|
+
width: inputBoxWidth(),
|
|
198
|
+
height: 5,
|
|
199
|
+
backgroundColor: "#1a1a1a",
|
|
200
|
+
flexDirection: "column",
|
|
201
|
+
justifyContent: "center"
|
|
202
|
+
},
|
|
203
|
+
/* @__PURE__ */ React.createElement(
|
|
204
|
+
"input",
|
|
205
|
+
{
|
|
206
|
+
id: "input",
|
|
207
|
+
width: "100%",
|
|
208
|
+
height: 1,
|
|
209
|
+
placeholder: "Type a message and press Enter...",
|
|
210
|
+
focusedBackgroundColor: "#1a1a1a",
|
|
211
|
+
onInput: (value) => setInputValue(value),
|
|
212
|
+
onSubmit: () => submitPrompt(inputValue()),
|
|
213
|
+
ref: (r) => {
|
|
214
|
+
inputRef = r;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
),
|
|
218
|
+
/* @__PURE__ */ React.createElement("box", { flexDirection: "row", flexShrink: 0, paddingTop: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#ffffff" }, modelText))
|
|
219
|
+
)
|
|
220
|
+
), /* @__PURE__ */ React.createElement(Show, { when: isLoading() }, /* @__PURE__ */ React.createElement(
|
|
221
|
+
"box",
|
|
222
|
+
{
|
|
223
|
+
id: "spinner",
|
|
224
|
+
position: "absolute",
|
|
225
|
+
left: inputBoxLeft(),
|
|
226
|
+
top: inputBoxTop() + inputBoxHeight(),
|
|
227
|
+
paddingLeft: 1
|
|
228
|
+
},
|
|
229
|
+
/* @__PURE__ */ React.createElement("text", { fg: "#00ffff" }, cliSpinners.dots.frames[spinnerFrame()])
|
|
230
|
+
)), /* @__PURE__ */ React.createElement(
|
|
231
|
+
"box",
|
|
232
|
+
{
|
|
233
|
+
id: "footer",
|
|
234
|
+
width: dimensions().width,
|
|
235
|
+
height: 1,
|
|
236
|
+
position: "absolute",
|
|
237
|
+
bottom: 0,
|
|
238
|
+
left: 0,
|
|
239
|
+
backgroundColor: "#000000",
|
|
240
|
+
paddingLeft: 1,
|
|
241
|
+
paddingRight: 1,
|
|
242
|
+
flexDirection: "row",
|
|
243
|
+
justifyContent: "space-between",
|
|
244
|
+
alignItems: "center"
|
|
245
|
+
},
|
|
246
|
+
/* @__PURE__ */ React.createElement("text", { fg: "#00ffff", wrapMode: "none", width: "100%" }, usageText),
|
|
247
|
+
/* @__PURE__ */ React.createElement("box", { flexShrink: 0, paddingLeft: 1 }, /* @__PURE__ */ React.createElement("text", { fg: "#00ffff" }, versionText))
|
|
248
|
+
));
|
|
249
|
+
}
|
|
250
|
+
export {
|
|
251
|
+
runInteractiveApp
|
|
252
|
+
};
|