@satori-sh/cli 0.0.30 → 0.0.31
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 +13 -11
- package/dist/ui-4LVANHF6.js +2678 -0
- package/package.json +1 -1
- package/dist/ui-OEY6KRG2.js +0 -264
package/package.json
CHANGED
package/dist/ui-OEY6KRG2.js
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
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
|
-
import { jsx, jsxs } from "solid-js/h/jsx-runtime";
|
|
18
|
-
async function runInteractiveApp({
|
|
19
|
-
initialPrompt,
|
|
20
|
-
options,
|
|
21
|
-
processUserInput,
|
|
22
|
-
infoLine,
|
|
23
|
-
infoDisplay
|
|
24
|
-
}) {
|
|
25
|
-
const logo = await loadLogo();
|
|
26
|
-
console.log(` ${logo}`);
|
|
27
|
-
const rows = process.stdout.rows ?? 24;
|
|
28
|
-
const logoHeight = logo.endsWith("\n") ? logo.slice(0, -1).split("\n").length : logo.split("\n").length;
|
|
29
|
-
const splitHeight = Math.max(1, rows - logoHeight - 1);
|
|
30
|
-
render(
|
|
31
|
-
() => /* @__PURE__ */ jsx(
|
|
32
|
-
App,
|
|
33
|
-
{
|
|
34
|
-
initialPrompt,
|
|
35
|
-
options,
|
|
36
|
-
processUserInput,
|
|
37
|
-
infoLine,
|
|
38
|
-
infoDisplay
|
|
39
|
-
}
|
|
40
|
-
),
|
|
41
|
-
{
|
|
42
|
-
useAlternateScreen: false,
|
|
43
|
-
exitOnCtrlC: true,
|
|
44
|
-
useMouse: true,
|
|
45
|
-
enableMouseMovement: true,
|
|
46
|
-
experimental_splitHeight: splitHeight
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
function App({ initialPrompt, options, processUserInput, infoLine, infoDisplay }) {
|
|
51
|
-
const renderer = useRenderer();
|
|
52
|
-
const dimensions = useTerminalDimensions();
|
|
53
|
-
const [messages, setMessages] = createSignal([]);
|
|
54
|
-
const [inputValue, setInputValue] = createSignal("");
|
|
55
|
-
const [showIntro, setShowIntro] = createSignal(true);
|
|
56
|
-
const [isFullScreen, setIsFullScreen] = createSignal(false);
|
|
57
|
-
const [spinnerFrame, setSpinnerFrame] = createSignal(0);
|
|
58
|
-
const [isLoading, setIsLoading] = createSignal(false);
|
|
59
|
-
const promptFg = "#00ffff";
|
|
60
|
-
const responseFg = "#ffffff";
|
|
61
|
-
const promptBg = "#2b2b2b";
|
|
62
|
-
let inputRef;
|
|
63
|
-
let currentMemoryId = options.memoryId;
|
|
64
|
-
let messageId = 0;
|
|
65
|
-
const usageText = infoDisplay?.usageLine ?? infoLine ?? "";
|
|
66
|
-
const versionText = infoDisplay?.versionLine ?? "";
|
|
67
|
-
const modelText = infoDisplay?.modelLine ?? "";
|
|
68
|
-
const appendMessage = (role, text) => {
|
|
69
|
-
setMessages((prev) => [...prev, { id: messageId++, role, text }]);
|
|
70
|
-
};
|
|
71
|
-
const exitApp = () => {
|
|
72
|
-
renderer.destroy();
|
|
73
|
-
process.exit(0);
|
|
74
|
-
};
|
|
75
|
-
const submitPrompt = async (raw) => {
|
|
76
|
-
const trimmed = raw.trim();
|
|
77
|
-
if (!trimmed) return;
|
|
78
|
-
if (trimmed.toLowerCase() === "exit" || trimmed.toLowerCase() === "quit") {
|
|
79
|
-
exitApp();
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (showIntro()) {
|
|
83
|
-
setShowIntro(false);
|
|
84
|
-
}
|
|
85
|
-
if (!isFullScreen()) {
|
|
86
|
-
setIsFullScreen(true);
|
|
87
|
-
}
|
|
88
|
-
setInputValue("");
|
|
89
|
-
if (inputRef) {
|
|
90
|
-
inputRef.value = "";
|
|
91
|
-
}
|
|
92
|
-
appendMessage("prompt", trimmed);
|
|
93
|
-
try {
|
|
94
|
-
setIsLoading(true);
|
|
95
|
-
const result = await processUserInput(trimmed, { ...options, memoryId: currentMemoryId }, "tui");
|
|
96
|
-
currentMemoryId = result.memoryId;
|
|
97
|
-
appendMessage("response", result.response);
|
|
98
|
-
if (result.instruction) {
|
|
99
|
-
appendMessage("response", result.instruction);
|
|
100
|
-
}
|
|
101
|
-
} catch (error) {
|
|
102
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
103
|
-
appendMessage("response", `Error: ${message}`);
|
|
104
|
-
} finally {
|
|
105
|
-
setIsLoading(false);
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
onMount(async () => {
|
|
109
|
-
const spinner = cliSpinners.dots;
|
|
110
|
-
const timer = setInterval(() => {
|
|
111
|
-
if (isLoading()) {
|
|
112
|
-
setSpinnerFrame((prev) => (prev + 1) % spinner.frames.length);
|
|
113
|
-
}
|
|
114
|
-
}, spinner.interval);
|
|
115
|
-
onCleanup(() => clearInterval(timer));
|
|
116
|
-
if (initialPrompt) {
|
|
117
|
-
await submitPrompt(initialPrompt);
|
|
118
|
-
}
|
|
119
|
-
if (inputRef) {
|
|
120
|
-
inputRef.focus();
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
const inputBoxWidth = () => Math.max(1, Math.round(dimensions().width * 0.6));
|
|
124
|
-
const inputBoxLeft = () => Math.max(0, Math.round(dimensions().width * 0.15));
|
|
125
|
-
const inputBoxHeight = () => isFullScreen() ? 7 : 14;
|
|
126
|
-
const inputBoxTop = () => isFullScreen() ? Math.max(1, dimensions().height - inputBoxHeight() - 2) : Math.max(1, Math.round(dimensions().height * 0.666));
|
|
127
|
-
const messagesTop = () => 1;
|
|
128
|
-
const messagesHeight = () => Math.max(1, inputBoxTop() - messagesTop() - 1);
|
|
129
|
-
const messagesWidth = () => Math.min(dimensions().width - 2, inputBoxWidth() + 10);
|
|
130
|
-
const messagesLeft = () => Math.max(1, inputBoxLeft() - 5);
|
|
131
|
-
return /* @__PURE__ */ jsxs("box", { width: "100%", height: "100%", flexDirection: "column", children: [
|
|
132
|
-
/* @__PURE__ */ jsx(
|
|
133
|
-
"scrollbox",
|
|
134
|
-
{
|
|
135
|
-
id: "messages",
|
|
136
|
-
width: messagesWidth(),
|
|
137
|
-
height: messagesHeight(),
|
|
138
|
-
position: "absolute",
|
|
139
|
-
left: messagesLeft(),
|
|
140
|
-
top: messagesTop(),
|
|
141
|
-
paddingLeft: 1,
|
|
142
|
-
paddingRight: 1,
|
|
143
|
-
focused: true,
|
|
144
|
-
stickyScroll: true,
|
|
145
|
-
stickyStart: "bottom",
|
|
146
|
-
children: /* @__PURE__ */ jsx("box", { width: "100%", flexDirection: "column", children: /* @__PURE__ */ jsx(For, { each: messages(), children: (message) => /* @__PURE__ */ jsx(
|
|
147
|
-
"box",
|
|
148
|
-
{
|
|
149
|
-
width: "100%",
|
|
150
|
-
flexDirection: "row",
|
|
151
|
-
justifyContent: message.role === "prompt" ? "flex-start" : "flex-end",
|
|
152
|
-
marginBottom: 1,
|
|
153
|
-
children: /* @__PURE__ */ jsx(
|
|
154
|
-
"box",
|
|
155
|
-
{
|
|
156
|
-
paddingLeft: 1,
|
|
157
|
-
paddingRight: 1,
|
|
158
|
-
paddingTop: 1,
|
|
159
|
-
paddingBottom: 1,
|
|
160
|
-
backgroundColor: message.role === "prompt" ? promptBg : void 0,
|
|
161
|
-
children: /* @__PURE__ */ jsx(
|
|
162
|
-
"text",
|
|
163
|
-
{
|
|
164
|
-
fg: message.role === "prompt" ? promptFg : responseFg,
|
|
165
|
-
width: "100%",
|
|
166
|
-
wrapMode: "word",
|
|
167
|
-
selectable: false,
|
|
168
|
-
children: message.text
|
|
169
|
-
}
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
)
|
|
173
|
-
}
|
|
174
|
-
) }) })
|
|
175
|
-
}
|
|
176
|
-
),
|
|
177
|
-
/* @__PURE__ */ jsxs(
|
|
178
|
-
"box",
|
|
179
|
-
{
|
|
180
|
-
id: "input-box",
|
|
181
|
-
width: inputBoxWidth(),
|
|
182
|
-
height: inputBoxHeight(),
|
|
183
|
-
position: "absolute",
|
|
184
|
-
left: inputBoxLeft(),
|
|
185
|
-
top: inputBoxTop(),
|
|
186
|
-
paddingLeft: 1,
|
|
187
|
-
paddingRight: 1,
|
|
188
|
-
paddingTop: 1,
|
|
189
|
-
flexDirection: "column",
|
|
190
|
-
children: [
|
|
191
|
-
/* @__PURE__ */ jsx(For, { each: !isFullScreen() && showIntro() ? [
|
|
192
|
-
"Use Satori just like you would use ChatGPT.",
|
|
193
|
-
"Except, it stores your conversations in a long term memory.",
|
|
194
|
-
"The memories you store here can be accessed through the SDK."
|
|
195
|
-
] : [], children: (line) => /* @__PURE__ */ jsx("text", { fg: "cyan", children: line }) }),
|
|
196
|
-
/* @__PURE__ */ jsxs(
|
|
197
|
-
"box",
|
|
198
|
-
{
|
|
199
|
-
id: "input-box",
|
|
200
|
-
width: inputBoxWidth(),
|
|
201
|
-
height: 5,
|
|
202
|
-
backgroundColor: "#1a1a1a",
|
|
203
|
-
flexDirection: "column",
|
|
204
|
-
justifyContent: "center",
|
|
205
|
-
children: [
|
|
206
|
-
/* @__PURE__ */ jsx(
|
|
207
|
-
"input",
|
|
208
|
-
{
|
|
209
|
-
id: "input",
|
|
210
|
-
width: "100%",
|
|
211
|
-
height: 1,
|
|
212
|
-
placeholder: "Type a message and press Enter...",
|
|
213
|
-
focusedBackgroundColor: "#1a1a1a",
|
|
214
|
-
onInput: (value) => setInputValue(value),
|
|
215
|
-
onSubmit: () => submitPrompt(inputValue()),
|
|
216
|
-
ref: (r) => {
|
|
217
|
-
inputRef = r;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
),
|
|
221
|
-
/* @__PURE__ */ jsx("box", { flexDirection: "row", flexShrink: 0, paddingTop: 1, children: /* @__PURE__ */ jsx("text", { fg: "#ffffff", children: modelText }) })
|
|
222
|
-
]
|
|
223
|
-
}
|
|
224
|
-
)
|
|
225
|
-
]
|
|
226
|
-
}
|
|
227
|
-
),
|
|
228
|
-
/* @__PURE__ */ jsx(Show, { when: isLoading(), children: /* @__PURE__ */ jsx(
|
|
229
|
-
"box",
|
|
230
|
-
{
|
|
231
|
-
id: "spinner",
|
|
232
|
-
position: "absolute",
|
|
233
|
-
left: inputBoxLeft(),
|
|
234
|
-
top: inputBoxTop() + inputBoxHeight(),
|
|
235
|
-
paddingLeft: 1,
|
|
236
|
-
children: /* @__PURE__ */ jsx("text", { fg: "#00ffff", children: cliSpinners.dots.frames[spinnerFrame()] })
|
|
237
|
-
}
|
|
238
|
-
) }),
|
|
239
|
-
/* @__PURE__ */ jsxs(
|
|
240
|
-
"box",
|
|
241
|
-
{
|
|
242
|
-
id: "footer",
|
|
243
|
-
width: dimensions().width,
|
|
244
|
-
height: 1,
|
|
245
|
-
position: "absolute",
|
|
246
|
-
bottom: 0,
|
|
247
|
-
left: 0,
|
|
248
|
-
backgroundColor: "#000000",
|
|
249
|
-
paddingLeft: 1,
|
|
250
|
-
paddingRight: 1,
|
|
251
|
-
flexDirection: "row",
|
|
252
|
-
justifyContent: "space-between",
|
|
253
|
-
alignItems: "center",
|
|
254
|
-
children: [
|
|
255
|
-
/* @__PURE__ */ jsx("text", { fg: "#00ffff", wrapMode: "none", width: "100%", children: usageText }),
|
|
256
|
-
/* @__PURE__ */ jsx("box", { flexShrink: 0, paddingLeft: 1, children: /* @__PURE__ */ jsx("text", { fg: "#00ffff", children: versionText }) })
|
|
257
|
-
]
|
|
258
|
-
}
|
|
259
|
-
)
|
|
260
|
-
] });
|
|
261
|
-
}
|
|
262
|
-
export {
|
|
263
|
-
runInteractiveApp
|
|
264
|
-
};
|