@mindstudio-ai/local-model-tunnel 0.4.0 → 0.4.1
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/README.md +27 -11
- package/dist/{chunk-44NXQXRB.js → chunk-KLOTDVWL.js} +4 -2
- package/dist/chunk-KLOTDVWL.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{tui-BW6XKMWK.js → tui-EAU7OA4X.js} +606 -363
- package/dist/tui-EAU7OA4X.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-44NXQXRB.js.map +0 -1
- package/dist/tui-BW6XKMWK.js.map +0 -1
|
@@ -20,19 +20,21 @@ import {
|
|
|
20
20
|
setUserId,
|
|
21
21
|
syncModels,
|
|
22
22
|
verifyApiKey
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-KLOTDVWL.js";
|
|
24
24
|
|
|
25
25
|
// src/tui/index.tsx
|
|
26
26
|
import { render } from "ink";
|
|
27
27
|
import { execFileSync, execSync as execSync2 } from "child_process";
|
|
28
28
|
|
|
29
29
|
// src/tui/App.tsx
|
|
30
|
-
import { useEffect as
|
|
30
|
+
import { useEffect as useEffect16, useCallback as useCallback10, useState as useState16, useRef as useRef9 } from "react";
|
|
31
31
|
import { Box as Box10, useApp, useStdout as useStdout7 } from "ink";
|
|
32
32
|
|
|
33
33
|
// src/tui/components/Header.tsx
|
|
34
|
+
import { useState, useEffect, useMemo } from "react";
|
|
34
35
|
import os from "os";
|
|
35
36
|
import { Box, Text } from "ink";
|
|
37
|
+
import chalk from "chalk";
|
|
36
38
|
import { createRequire } from "module";
|
|
37
39
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
38
40
|
var require2 = createRequire(import.meta.url);
|
|
@@ -46,6 +48,52 @@ var LogoString = ` .=+-. :++.
|
|
|
46
48
|
=@@@@@@@-.@@@@@@@#.-@@@@@@+
|
|
47
49
|
:@@@@@@: +@@@@@#. .@@@@@@:
|
|
48
50
|
.++: .-*-. .++:`;
|
|
51
|
+
function useActiveShimmerLogo(active) {
|
|
52
|
+
const [frame, setFrame] = useState(0);
|
|
53
|
+
const lines = useMemo(() => LogoString.split("\n"), []);
|
|
54
|
+
const totalChars = useMemo(() => {
|
|
55
|
+
let count = 0;
|
|
56
|
+
for (const line of lines) {
|
|
57
|
+
for (const ch of line) {
|
|
58
|
+
if (ch !== " " && ch !== " ") count++;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return count;
|
|
62
|
+
}, [lines]);
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (!active) return;
|
|
65
|
+
const interval = setInterval(() => {
|
|
66
|
+
setFrame((f) => f + 1);
|
|
67
|
+
}, 25);
|
|
68
|
+
return () => clearInterval(interval);
|
|
69
|
+
}, [active]);
|
|
70
|
+
return useMemo(() => {
|
|
71
|
+
if (!active) return null;
|
|
72
|
+
const waveLength = 20;
|
|
73
|
+
let charIdx = 0;
|
|
74
|
+
return lines.map((line) => {
|
|
75
|
+
let result = "";
|
|
76
|
+
for (let i = 0; i < line.length; i++) {
|
|
77
|
+
const ch = line[i];
|
|
78
|
+
if (ch === " " || ch === " ") {
|
|
79
|
+
result += ch;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const phase = (charIdx - frame * 0.5) / waveLength * Math.PI * 2;
|
|
83
|
+
const brightness = 0.65 + 0.35 * Math.sin(phase);
|
|
84
|
+
if (brightness >= 0.85) {
|
|
85
|
+
result += chalk.cyanBright(ch);
|
|
86
|
+
} else if (brightness >= 0.65) {
|
|
87
|
+
result += chalk.cyan(ch);
|
|
88
|
+
} else {
|
|
89
|
+
result += chalk.rgb(0, 140, 160)(ch);
|
|
90
|
+
}
|
|
91
|
+
charIdx++;
|
|
92
|
+
}
|
|
93
|
+
return result;
|
|
94
|
+
}).join("\n");
|
|
95
|
+
}, [active, frame, lines, totalChars]);
|
|
96
|
+
}
|
|
49
97
|
var getConnectionDisplay = (status) => {
|
|
50
98
|
switch (status) {
|
|
51
99
|
case "connected":
|
|
@@ -65,9 +113,11 @@ function Header({
|
|
|
65
113
|
environment,
|
|
66
114
|
configPath,
|
|
67
115
|
connectionError,
|
|
68
|
-
compact
|
|
116
|
+
compact,
|
|
117
|
+
hasActiveRequest
|
|
69
118
|
}) {
|
|
70
119
|
const { color: connectionColor, text: connectionText } = getConnectionDisplay(connection);
|
|
120
|
+
const shimmerLogo = useActiveShimmerLogo(!compact && !!hasActiveRequest);
|
|
71
121
|
return /* @__PURE__ */ jsxs(
|
|
72
122
|
Box,
|
|
73
123
|
{
|
|
@@ -79,7 +129,7 @@ function Header({
|
|
|
79
129
|
paddingY: 1,
|
|
80
130
|
width: "100%",
|
|
81
131
|
children: [
|
|
82
|
-
!compact && /* @__PURE__ */ jsx(Box, { paddingLeft: 3, children: /* @__PURE__ */ jsx(Text, { color: "cyan", children: LogoString }) }),
|
|
132
|
+
!compact && /* @__PURE__ */ jsx(Box, { paddingLeft: 3, children: shimmerLogo ? /* @__PURE__ */ jsx(Text, { children: shimmerLogo }) : /* @__PURE__ */ jsx(Text, { color: "cyan", children: LogoString }) }),
|
|
83
133
|
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginLeft: compact ? 0 : 4, children: [
|
|
84
134
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
85
135
|
/* @__PURE__ */ jsx(Text, { bold: true, color: "white", children: "MindStudio Local Tunnel" }),
|
|
@@ -92,10 +142,6 @@ function Header({
|
|
|
92
142
|
/* @__PURE__ */ jsx(Text, { color: "yellow", bold: true, children: "[LOCAL]" })
|
|
93
143
|
] })
|
|
94
144
|
] }),
|
|
95
|
-
!compact && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
96
|
-
"v",
|
|
97
|
-
pkg.version
|
|
98
|
-
] }),
|
|
99
145
|
/* @__PURE__ */ jsxs(Text, { color: connectionColor, children: [
|
|
100
146
|
"\u25CF ",
|
|
101
147
|
connectionText
|
|
@@ -104,6 +150,10 @@ function Header({
|
|
|
104
150
|
/* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
105
151
|
"Config: ",
|
|
106
152
|
configPath.replace(os.homedir(), "~")
|
|
153
|
+
] }),
|
|
154
|
+
!compact && /* @__PURE__ */ jsxs(Text, { color: "gray", children: [
|
|
155
|
+
"v",
|
|
156
|
+
pkg.version
|
|
107
157
|
] })
|
|
108
158
|
] })
|
|
109
159
|
]
|
|
@@ -112,18 +162,22 @@ function Header({
|
|
|
112
162
|
}
|
|
113
163
|
|
|
114
164
|
// src/tui/components/NavigationMenu.tsx
|
|
115
|
-
import { useState, useEffect } from "react";
|
|
165
|
+
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
116
166
|
import { Box as Box2, Text as Text2, useInput, useStdout } from "ink";
|
|
117
167
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
118
|
-
function NavigationMenu({
|
|
168
|
+
function NavigationMenu({
|
|
169
|
+
items,
|
|
170
|
+
onSelect,
|
|
171
|
+
title
|
|
172
|
+
}) {
|
|
119
173
|
const { stdout } = useStdout();
|
|
120
174
|
const compact = (stdout?.rows ?? 24) < 40;
|
|
121
175
|
const getDefaultIndex = () => {
|
|
122
176
|
const firstIdx = items.findIndex((i) => !i.disabled && !i.isSeparator);
|
|
123
177
|
return firstIdx >= 0 ? firstIdx : 0;
|
|
124
178
|
};
|
|
125
|
-
const [selectedIndex, setSelectedIndex] =
|
|
126
|
-
|
|
179
|
+
const [selectedIndex, setSelectedIndex] = useState2(getDefaultIndex);
|
|
180
|
+
useEffect2(() => {
|
|
127
181
|
setSelectedIndex(getDefaultIndex());
|
|
128
182
|
}, [items]);
|
|
129
183
|
const selectableItems = items.filter((i) => !i.isSeparator);
|
|
@@ -159,60 +213,98 @@ function NavigationMenu({ items, onSelect, title }) {
|
|
|
159
213
|
const hasBack = items.some((i) => i.id === "back");
|
|
160
214
|
if (compact) {
|
|
161
215
|
const selectedItem = items[selectedIndex];
|
|
162
|
-
return /* @__PURE__ */ jsx2(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
item
|
|
174
|
-
|
|
175
|
-
|
|
216
|
+
return /* @__PURE__ */ jsx2(
|
|
217
|
+
Box2,
|
|
218
|
+
{
|
|
219
|
+
flexDirection: "column",
|
|
220
|
+
paddingX: 1,
|
|
221
|
+
borderStyle: "single",
|
|
222
|
+
borderTop: true,
|
|
223
|
+
borderBottom: false,
|
|
224
|
+
borderLeft: false,
|
|
225
|
+
borderRight: false,
|
|
226
|
+
borderColor: "gray",
|
|
227
|
+
children: /* @__PURE__ */ jsx2(Box2, { height: 1, overflow: "hidden", gap: 1, children: items.map((item, index) => {
|
|
228
|
+
if (item.isSeparator) return null;
|
|
229
|
+
const isSelected = index === selectedIndex;
|
|
230
|
+
return /* @__PURE__ */ jsx2(
|
|
231
|
+
Text2,
|
|
232
|
+
{
|
|
233
|
+
color: item.disabled ? "gray" : isSelected ? "cyan" : "white",
|
|
234
|
+
bold: isSelected,
|
|
235
|
+
wrap: "truncate-end",
|
|
236
|
+
children: isSelected ? `\u276F ${item.label}` : ` ${item.label}`
|
|
237
|
+
},
|
|
238
|
+
item.id
|
|
239
|
+
);
|
|
240
|
+
}) })
|
|
241
|
+
}
|
|
242
|
+
);
|
|
176
243
|
}
|
|
177
|
-
const separatorExtraLines = items.filter(
|
|
244
|
+
const separatorExtraLines = items.filter(
|
|
245
|
+
(item, idx) => item.isSeparator && idx > 0
|
|
246
|
+
).length;
|
|
178
247
|
const menuHeight = items.length + 4 + separatorExtraLines;
|
|
179
|
-
return /* @__PURE__ */ jsxs2(
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
" "
|
|
199
|
-
item.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
248
|
+
return /* @__PURE__ */ jsxs2(
|
|
249
|
+
Box2,
|
|
250
|
+
{
|
|
251
|
+
flexDirection: "column",
|
|
252
|
+
paddingX: 1,
|
|
253
|
+
marginBottom: 1,
|
|
254
|
+
borderStyle: "single",
|
|
255
|
+
borderTop: true,
|
|
256
|
+
borderBottom: false,
|
|
257
|
+
borderLeft: false,
|
|
258
|
+
borderRight: false,
|
|
259
|
+
borderColor: "gray",
|
|
260
|
+
children: [
|
|
261
|
+
/* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { color: "gray", children: title ?? "Actions" }) }),
|
|
262
|
+
/* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: items.map((item, index) => {
|
|
263
|
+
if (item.isSeparator) {
|
|
264
|
+
return /* @__PURE__ */ jsx2(Box2, { marginTop: index > 0 ? 1 : 0, children: item.label ? /* @__PURE__ */ jsx2(Text2, { bold: true, color: item.color ?? "gray", wrap: "truncate-end", children: item.label }) : null }, item.id);
|
|
265
|
+
}
|
|
266
|
+
const isSelected = index === selectedIndex;
|
|
267
|
+
const prefix = isSelected ? "\u276F" : " ";
|
|
268
|
+
if (item.disabled) {
|
|
269
|
+
return /* @__PURE__ */ jsx2(Box2, { height: 1, overflow: "hidden", children: /* @__PURE__ */ jsxs2(Text2, { color: "gray", wrap: "truncate-end", children: [
|
|
270
|
+
prefix,
|
|
271
|
+
" ",
|
|
272
|
+
item.label,
|
|
273
|
+
item.disabledReason ? ` (${item.disabledReason})` : ""
|
|
274
|
+
] }) }, item.id);
|
|
275
|
+
}
|
|
276
|
+
return /* @__PURE__ */ jsxs2(Box2, { height: 1, overflow: "hidden", children: [
|
|
277
|
+
/* @__PURE__ */ jsxs2(
|
|
278
|
+
Text2,
|
|
279
|
+
{
|
|
280
|
+
color: isSelected ? "cyan" : "white",
|
|
281
|
+
bold: isSelected,
|
|
282
|
+
wrap: "truncate-end",
|
|
283
|
+
children: [
|
|
284
|
+
prefix,
|
|
285
|
+
" ",
|
|
286
|
+
item.label
|
|
287
|
+
]
|
|
288
|
+
}
|
|
289
|
+
),
|
|
290
|
+
isSelected && /* @__PURE__ */ jsxs2(Text2, { color: "gray", wrap: "truncate-end", children: [
|
|
291
|
+
" ",
|
|
292
|
+
"- ",
|
|
293
|
+
item.description
|
|
294
|
+
] })
|
|
295
|
+
] }, item.id);
|
|
296
|
+
}) }),
|
|
297
|
+
/* @__PURE__ */ jsx2(Box2, { marginTop: 1, height: 1, children: /* @__PURE__ */ jsx2(Text2, { color: "gray", wrap: "truncate-end", children: hasBack ? "Up/Down Navigate \u2022 Enter Select \u2022 q/Esc Back" : "Up/Down Navigate \u2022 Enter Select \u2022 q Quit" }) })
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
);
|
|
209
301
|
}
|
|
210
302
|
|
|
211
303
|
// src/tui/hooks/useConnection.ts
|
|
212
|
-
import { useState as
|
|
304
|
+
import { useState as useState3, useEffect as useEffect3, useCallback } from "react";
|
|
213
305
|
function useConnection() {
|
|
214
|
-
const [status, setStatus] =
|
|
215
|
-
const [error, setError] =
|
|
306
|
+
const [status, setStatus] = useState3("connecting");
|
|
307
|
+
const [error, setError] = useState3(null);
|
|
216
308
|
const environment = getEnvironment();
|
|
217
309
|
const connect = useCallback(async () => {
|
|
218
310
|
setStatus("connecting");
|
|
@@ -235,7 +327,7 @@ function useConnection() {
|
|
|
235
327
|
setError(err instanceof Error ? err.message : "Connection failed");
|
|
236
328
|
}
|
|
237
329
|
}, []);
|
|
238
|
-
|
|
330
|
+
useEffect3(() => {
|
|
239
331
|
connect();
|
|
240
332
|
}, [connect]);
|
|
241
333
|
return {
|
|
@@ -246,14 +338,65 @@ function useConnection() {
|
|
|
246
338
|
};
|
|
247
339
|
}
|
|
248
340
|
|
|
249
|
-
// src/tui/
|
|
250
|
-
import { useState as
|
|
251
|
-
function
|
|
252
|
-
const [
|
|
253
|
-
const [loading, setLoading] =
|
|
254
|
-
const [
|
|
341
|
+
// src/tui/interfaces/hooks/useEditorSessions.ts
|
|
342
|
+
import { useState as useState4, useEffect as useEffect4, useCallback as useCallback2, useRef } from "react";
|
|
343
|
+
function useEditorSessions() {
|
|
344
|
+
const [sessions, setSessions] = useState4([]);
|
|
345
|
+
const [loading, setLoading] = useState4(true);
|
|
346
|
+
const [error, setError] = useState4(null);
|
|
347
|
+
const [refreshStatus, setRefreshStatus] = useState4("idle");
|
|
255
348
|
const initialLoadDone = useRef(false);
|
|
349
|
+
const timerRef = useRef();
|
|
350
|
+
const pollRef = useRef();
|
|
256
351
|
const refresh = useCallback2(async () => {
|
|
352
|
+
if (!initialLoadDone.current) {
|
|
353
|
+
setLoading(true);
|
|
354
|
+
} else {
|
|
355
|
+
setRefreshStatus("refreshing");
|
|
356
|
+
}
|
|
357
|
+
setError(null);
|
|
358
|
+
try {
|
|
359
|
+
const data = await getEditorSessions();
|
|
360
|
+
setSessions(data);
|
|
361
|
+
initialLoadDone.current = true;
|
|
362
|
+
setRefreshStatus("refreshed");
|
|
363
|
+
clearTimeout(timerRef.current);
|
|
364
|
+
timerRef.current = setTimeout(() => setRefreshStatus("idle"), 1500);
|
|
365
|
+
} catch (err) {
|
|
366
|
+
setError(err instanceof Error ? err.message : "Failed to fetch sessions");
|
|
367
|
+
setRefreshStatus("idle");
|
|
368
|
+
} finally {
|
|
369
|
+
setLoading(false);
|
|
370
|
+
}
|
|
371
|
+
}, []);
|
|
372
|
+
useEffect4(() => {
|
|
373
|
+
refresh();
|
|
374
|
+
}, [refresh]);
|
|
375
|
+
useEffect4(() => {
|
|
376
|
+
pollRef.current = setInterval(async () => {
|
|
377
|
+
if (!initialLoadDone.current) return;
|
|
378
|
+
try {
|
|
379
|
+
const data = await getEditorSessions();
|
|
380
|
+
setSessions(data);
|
|
381
|
+
} catch {
|
|
382
|
+
}
|
|
383
|
+
}, 5e3);
|
|
384
|
+
return () => clearInterval(pollRef.current);
|
|
385
|
+
}, []);
|
|
386
|
+
useEffect4(() => {
|
|
387
|
+
return () => clearTimeout(timerRef.current);
|
|
388
|
+
}, []);
|
|
389
|
+
return { sessions, loading, error, refreshStatus, refresh };
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/tui/models/hooks/useSetupProviders.ts
|
|
393
|
+
import { useState as useState5, useEffect as useEffect5, useCallback as useCallback3, useRef as useRef2 } from "react";
|
|
394
|
+
function useSetupProviders() {
|
|
395
|
+
const [providers, setProviders] = useState5([]);
|
|
396
|
+
const [loading, setLoading] = useState5(true);
|
|
397
|
+
const [refreshing, setRefreshing] = useState5(false);
|
|
398
|
+
const initialLoadDone = useRef2(false);
|
|
399
|
+
const refresh = useCallback3(async () => {
|
|
257
400
|
if (!initialLoadDone.current) {
|
|
258
401
|
setLoading(true);
|
|
259
402
|
} else {
|
|
@@ -265,21 +408,21 @@ function useSetupProviders() {
|
|
|
265
408
|
setLoading(false);
|
|
266
409
|
setRefreshing(false);
|
|
267
410
|
}, []);
|
|
268
|
-
|
|
411
|
+
useEffect5(() => {
|
|
269
412
|
refresh();
|
|
270
413
|
}, [refresh]);
|
|
271
414
|
return { providers, loading, refreshing, refresh };
|
|
272
415
|
}
|
|
273
416
|
|
|
274
417
|
// src/tui/models/hooks/useModels.ts
|
|
275
|
-
import { useState as
|
|
418
|
+
import { useState as useState6, useEffect as useEffect6, useCallback as useCallback4, useRef as useRef3 } from "react";
|
|
276
419
|
function useModels() {
|
|
277
|
-
const [models, setModels] =
|
|
278
|
-
const [warnings, setWarnings] =
|
|
279
|
-
const [loading, setLoading] =
|
|
280
|
-
const [refreshing, setRefreshing] =
|
|
281
|
-
const initialLoadDone =
|
|
282
|
-
const refresh =
|
|
420
|
+
const [models, setModels] = useState6([]);
|
|
421
|
+
const [warnings, setWarnings] = useState6([]);
|
|
422
|
+
const [loading, setLoading] = useState6(true);
|
|
423
|
+
const [refreshing, setRefreshing] = useState6(false);
|
|
424
|
+
const initialLoadDone = useRef3(false);
|
|
425
|
+
const refresh = useCallback4(async () => {
|
|
283
426
|
if (!initialLoadDone.current) {
|
|
284
427
|
setLoading(true);
|
|
285
428
|
} else {
|
|
@@ -298,7 +441,7 @@ function useModels() {
|
|
|
298
441
|
setRefreshing(false);
|
|
299
442
|
}
|
|
300
443
|
}, []);
|
|
301
|
-
|
|
444
|
+
useEffect6(() => {
|
|
302
445
|
refresh();
|
|
303
446
|
}, [refresh]);
|
|
304
447
|
return {
|
|
@@ -311,11 +454,11 @@ function useModels() {
|
|
|
311
454
|
}
|
|
312
455
|
|
|
313
456
|
// src/tui/models/hooks/useRequests.ts
|
|
314
|
-
import { useState as
|
|
457
|
+
import { useState as useState7, useEffect as useEffect7, useCallback as useCallback5, useRef as useRef4 } from "react";
|
|
315
458
|
function useRequests(maxHistory = 50) {
|
|
316
|
-
const [requests, setRequests] =
|
|
317
|
-
const requestsRef =
|
|
318
|
-
|
|
459
|
+
const [requests, setRequests] = useState7([]);
|
|
460
|
+
const requestsRef = useRef4(/* @__PURE__ */ new Map());
|
|
461
|
+
useEffect7(() => {
|
|
319
462
|
const interval = setInterval(() => {
|
|
320
463
|
setRequests((prev) => {
|
|
321
464
|
const hasActive = prev.some((r) => r.status === "processing");
|
|
@@ -324,7 +467,7 @@ function useRequests(maxHistory = 50) {
|
|
|
324
467
|
}, 1e3);
|
|
325
468
|
return () => clearInterval(interval);
|
|
326
469
|
}, []);
|
|
327
|
-
|
|
470
|
+
useEffect7(() => {
|
|
328
471
|
const unsubStart = requestEvents.onStart((event) => {
|
|
329
472
|
const entry = {
|
|
330
473
|
id: event.id,
|
|
@@ -343,7 +486,9 @@ function useRequests(maxHistory = 50) {
|
|
|
343
486
|
...existing,
|
|
344
487
|
...event.content !== void 0 && { content: event.content },
|
|
345
488
|
...event.step !== void 0 && { step: event.step },
|
|
346
|
-
...event.totalSteps !== void 0 && {
|
|
489
|
+
...event.totalSteps !== void 0 && {
|
|
490
|
+
totalSteps: event.totalSteps
|
|
491
|
+
}
|
|
347
492
|
};
|
|
348
493
|
requestsRef.current.set(event.id, updated);
|
|
349
494
|
setRequests(
|
|
@@ -375,7 +520,7 @@ function useRequests(maxHistory = 50) {
|
|
|
375
520
|
};
|
|
376
521
|
}, [maxHistory]);
|
|
377
522
|
const activeCount = requests.filter((r) => r.status === "processing").length;
|
|
378
|
-
const clear =
|
|
523
|
+
const clear = useCallback5(() => {
|
|
379
524
|
requestsRef.current.clear();
|
|
380
525
|
setRequests([]);
|
|
381
526
|
}, []);
|
|
@@ -387,13 +532,11 @@ function useRequests(maxHistory = 50) {
|
|
|
387
532
|
}
|
|
388
533
|
|
|
389
534
|
// src/tui/models/hooks/useRegisteredModels.ts
|
|
390
|
-
import { useState as
|
|
535
|
+
import { useState as useState8, useEffect as useEffect8, useCallback as useCallback6 } from "react";
|
|
391
536
|
function useSyncedModels(connectionStatus) {
|
|
392
|
-
const [syncedNames, setSyncedNames] =
|
|
393
|
-
|
|
394
|
-
)
|
|
395
|
-
const [syncedModels, setSyncedModels] = useState6([]);
|
|
396
|
-
const refresh = useCallback5(async () => {
|
|
537
|
+
const [syncedNames, setSyncedNames] = useState8(/* @__PURE__ */ new Set());
|
|
538
|
+
const [syncedModels, setSyncedModels] = useState8([]);
|
|
539
|
+
const refresh = useCallback6(async () => {
|
|
397
540
|
if (connectionStatus !== "connected") {
|
|
398
541
|
setSyncedNames(/* @__PURE__ */ new Set());
|
|
399
542
|
setSyncedModels([]);
|
|
@@ -406,7 +549,7 @@ function useSyncedModels(connectionStatus) {
|
|
|
406
549
|
} catch {
|
|
407
550
|
}
|
|
408
551
|
}, [connectionStatus]);
|
|
409
|
-
|
|
552
|
+
useEffect8(() => {
|
|
410
553
|
refresh();
|
|
411
554
|
}, [refresh]);
|
|
412
555
|
return {
|
|
@@ -417,7 +560,7 @@ function useSyncedModels(connectionStatus) {
|
|
|
417
560
|
}
|
|
418
561
|
|
|
419
562
|
// src/tui/models/pages/DashboardPage.tsx
|
|
420
|
-
import { useMemo } from "react";
|
|
563
|
+
import { useMemo as useMemo2 } from "react";
|
|
421
564
|
import { Box as Box4, Text as Text4, useStdout as useStdout3 } from "ink";
|
|
422
565
|
import Spinner2 from "ink-spinner";
|
|
423
566
|
|
|
@@ -455,7 +598,10 @@ function snippetLine(content, maxWidth) {
|
|
|
455
598
|
if (flat.length <= maxWidth) return flat;
|
|
456
599
|
return "\u2026" + flat.slice(-(maxWidth - 1));
|
|
457
600
|
}
|
|
458
|
-
function RequestItem({
|
|
601
|
+
function RequestItem({
|
|
602
|
+
request,
|
|
603
|
+
width
|
|
604
|
+
}) {
|
|
459
605
|
const time = formatTime(request.startTime);
|
|
460
606
|
const typeLabel = getRequestTypeLabel(request.requestType);
|
|
461
607
|
const snippetIndent = " ";
|
|
@@ -470,13 +616,13 @@ function RequestItem({ request, width }) {
|
|
|
470
616
|
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
471
617
|
" ",
|
|
472
618
|
time,
|
|
473
|
-
"
|
|
619
|
+
" "
|
|
474
620
|
] }),
|
|
475
621
|
/* @__PURE__ */ jsx3(Text3, { color: "white", children: request.modelId }),
|
|
476
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "
|
|
622
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: " " }),
|
|
477
623
|
/* @__PURE__ */ jsx3(Text3, { color: typeLabel.color, children: typeLabel.label }),
|
|
478
624
|
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
479
|
-
"
|
|
625
|
+
" ",
|
|
480
626
|
formatDuration(elapsed),
|
|
481
627
|
"..."
|
|
482
628
|
] })
|
|
@@ -508,13 +654,13 @@ function RequestItem({ request, width }) {
|
|
|
508
654
|
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
509
655
|
" ",
|
|
510
656
|
time,
|
|
511
|
-
"
|
|
657
|
+
" "
|
|
512
658
|
] }),
|
|
513
659
|
/* @__PURE__ */ jsx3(Text3, { color: "white", children: request.modelId }),
|
|
514
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "
|
|
660
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: " " }),
|
|
515
661
|
/* @__PURE__ */ jsx3(Text3, { color: typeLabel.color, children: typeLabel.label }),
|
|
516
662
|
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
517
|
-
"
|
|
663
|
+
" ",
|
|
518
664
|
duration,
|
|
519
665
|
resultInfo
|
|
520
666
|
] })
|
|
@@ -530,18 +676,22 @@ function RequestItem({ request, width }) {
|
|
|
530
676
|
/* @__PURE__ */ jsxs3(Text3, { color: "gray", children: [
|
|
531
677
|
" ",
|
|
532
678
|
time,
|
|
533
|
-
"
|
|
679
|
+
" "
|
|
534
680
|
] }),
|
|
535
681
|
/* @__PURE__ */ jsx3(Text3, { color: "white", children: request.modelId }),
|
|
536
|
-
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: "
|
|
682
|
+
/* @__PURE__ */ jsx3(Text3, { color: "gray", children: " " }),
|
|
537
683
|
/* @__PURE__ */ jsx3(Text3, { color: typeLabel.color, children: typeLabel.label }),
|
|
538
684
|
/* @__PURE__ */ jsxs3(Text3, { color: "red", children: [
|
|
539
|
-
"
|
|
685
|
+
" ",
|
|
540
686
|
request.error || "Failed"
|
|
541
687
|
] })
|
|
542
688
|
] }) });
|
|
543
689
|
}
|
|
544
|
-
function RequestLog({
|
|
690
|
+
function RequestLog({
|
|
691
|
+
requests,
|
|
692
|
+
maxVisible = 8,
|
|
693
|
+
hasModels = true
|
|
694
|
+
}) {
|
|
545
695
|
const { stdout } = useStdout2();
|
|
546
696
|
const width = stdout?.columns ?? 80;
|
|
547
697
|
const activeRequests = requests.filter((r) => r.status === "processing");
|
|
@@ -615,6 +765,8 @@ function DashboardPage({
|
|
|
615
765
|
syncedNames,
|
|
616
766
|
modelsLoading,
|
|
617
767
|
syncStatus = "idle",
|
|
768
|
+
editorSessions,
|
|
769
|
+
editorsLoading,
|
|
618
770
|
onNavigate
|
|
619
771
|
}) {
|
|
620
772
|
const { stdout } = useStdout3();
|
|
@@ -629,11 +781,11 @@ function DashboardPage({
|
|
|
629
781
|
(name) => !allModelNames.has(name)
|
|
630
782
|
);
|
|
631
783
|
const syncDescription = syncStatus === "syncing" ? "Syncing..." : syncStatus === "synced" ? "\u2713 Synced" : "Re-detect providers and sync models to MindStudio";
|
|
632
|
-
const menuItems =
|
|
784
|
+
const menuItems = useMemo2(() => {
|
|
633
785
|
return [
|
|
634
786
|
{
|
|
635
787
|
id: "interfaces",
|
|
636
|
-
label: "Connect to
|
|
788
|
+
label: "Connect to Agent",
|
|
637
789
|
description: "Connect your local editor to a MindStudio interface or script"
|
|
638
790
|
},
|
|
639
791
|
{
|
|
@@ -663,16 +815,25 @@ function DashboardPage({
|
|
|
663
815
|
const headerLines = compactHeader ? 7 : 14;
|
|
664
816
|
const providerContentLines = providersLoading ? 1 : installedProviders.length === 0 ? 2 : installedProviders.length;
|
|
665
817
|
const providersLines = 3 + providerContentLines;
|
|
818
|
+
const editorsContentLines = editorsLoading ? 1 : editorSessions.length === 0 ? 1 : editorSessions.length;
|
|
819
|
+
const editorsLines = 3 + editorsContentLines;
|
|
666
820
|
const modelContentLines = modelsLoading ? 1 : models.length === 0 && unavailableSynced.length === 0 && modelWarnings.length === 0 ? 2 : models.length + modelWarnings.length + (unavailableSynced.length > 0 ? 1 + unavailableSynced.length : 0);
|
|
667
821
|
const modelsLines = 3 + modelContentLines;
|
|
668
822
|
const requestLogOverhead = 3;
|
|
669
823
|
const compactMenu = termHeight + 4 < 40;
|
|
670
824
|
const menuLines = compactMenu ? 2 : menuItems.length + 6;
|
|
671
|
-
const usedLines = headerLines + providersLines + modelsLines + requestLogOverhead + menuLines;
|
|
825
|
+
const usedLines = headerLines + providersLines + editorsLines + modelsLines + requestLogOverhead + menuLines;
|
|
672
826
|
const maxVisible = Math.max(3, termHeight - usedLines);
|
|
673
827
|
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", flexGrow: 1, children: [
|
|
674
828
|
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
675
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "white", underline: true, children: "
|
|
829
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "white", underline: true, children: "Open Agents" }),
|
|
830
|
+
editorsLoading ? /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
|
|
831
|
+
/* @__PURE__ */ jsx4(Text4, { color: "cyan", children: /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }) }),
|
|
832
|
+
/* @__PURE__ */ jsx4(Text4, { children: " Loading editor sessions..." })
|
|
833
|
+
] }) : editorSessions.length === 0 ? /* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(Text4, { color: "gray", children: "Agents you are editing in the MindStudio IDE will appear here." }) }) : /* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginTop: 1, children: editorSessions.map((session) => /* @__PURE__ */ jsx4(Box4, { children: /* @__PURE__ */ jsx4(Text4, { color: "white", children: session.appName }) }, session.appId)) })
|
|
834
|
+
] }),
|
|
835
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
836
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "white", underline: true, children: "AI Model Providers" }),
|
|
676
837
|
providersLoading ? /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
|
|
677
838
|
/* @__PURE__ */ jsx4(Text4, { color: "cyan", children: /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }) }),
|
|
678
839
|
/* @__PURE__ */ jsx4(Text4, { children: " Detecting providers..." })
|
|
@@ -691,7 +852,7 @@ function DashboardPage({
|
|
|
691
852
|
}) })
|
|
692
853
|
] }),
|
|
693
854
|
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
694
|
-
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "white", underline: true, children: "Models" }),
|
|
855
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "white", underline: true, children: "Local Models" }),
|
|
695
856
|
modelsLoading ? /* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
|
|
696
857
|
/* @__PURE__ */ jsx4(Text4, { color: "cyan", children: /* @__PURE__ */ jsx4(Spinner2, { type: "dots" }) }),
|
|
697
858
|
/* @__PURE__ */ jsx4(Text4, { children: " Discovering models..." })
|
|
@@ -748,18 +909,18 @@ function DashboardPage({
|
|
|
748
909
|
}
|
|
749
910
|
|
|
750
911
|
// src/tui/models/pages/SetupPage.tsx
|
|
751
|
-
import { useState as
|
|
912
|
+
import { useState as useState9, useMemo as useMemo4, useEffect as useEffect9 } from "react";
|
|
752
913
|
import { Box as Box5, Text as Text6, useInput as useInput2, useStdout as useStdout5 } from "ink";
|
|
753
914
|
import Spinner3 from "ink-spinner";
|
|
754
915
|
|
|
755
916
|
// src/tui/components/MarkdownText.tsx
|
|
756
|
-
import { useMemo as
|
|
917
|
+
import { useMemo as useMemo3 } from "react";
|
|
757
918
|
import { Text as Text5, useStdout as useStdout4 } from "ink";
|
|
758
|
-
import
|
|
919
|
+
import chalk2 from "chalk";
|
|
759
920
|
import { marked } from "marked";
|
|
760
921
|
import { markedTerminal } from "marked-terminal";
|
|
761
922
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
762
|
-
var codeStyle =
|
|
923
|
+
var codeStyle = chalk2.cyan;
|
|
763
924
|
var identity = (s) => s;
|
|
764
925
|
function renderMarkdown(content, width) {
|
|
765
926
|
marked.use(
|
|
@@ -793,7 +954,7 @@ function ProviderDetailView({
|
|
|
793
954
|
provider,
|
|
794
955
|
onBack
|
|
795
956
|
}) {
|
|
796
|
-
const [scrollOffset, setScrollOffset] =
|
|
957
|
+
const [scrollOffset, setScrollOffset] = useState9(0);
|
|
797
958
|
const { stdout } = useStdout5();
|
|
798
959
|
const termHeight = (stdout?.rows ?? 24) - 4;
|
|
799
960
|
const headerHeight = 14;
|
|
@@ -801,7 +962,7 @@ function ProviderDetailView({
|
|
|
801
962
|
const contentPadding = 2;
|
|
802
963
|
const viewHeight = termHeight - headerHeight - footerLines - contentPadding;
|
|
803
964
|
const contentWidth = (stdout?.columns ?? 80) - 4;
|
|
804
|
-
const renderedLines =
|
|
965
|
+
const renderedLines = useMemo4(() => {
|
|
805
966
|
const rendered = renderMarkdown(provider.readme, contentWidth);
|
|
806
967
|
return rendered.split("\n");
|
|
807
968
|
}, [provider.readme, contentWidth]);
|
|
@@ -818,7 +979,7 @@ function ProviderDetailView({
|
|
|
818
979
|
}
|
|
819
980
|
});
|
|
820
981
|
const visibleContent = renderedLines.slice(scrollOffset, scrollOffset + viewHeight).join("\n");
|
|
821
|
-
const scrollbar =
|
|
982
|
+
const scrollbar = useMemo4(() => {
|
|
822
983
|
if (maxScroll === 0) return null;
|
|
823
984
|
const thumbSize = Math.max(
|
|
824
985
|
1,
|
|
@@ -888,27 +1049,27 @@ function ProviderDetailView({
|
|
|
888
1049
|
}
|
|
889
1050
|
function SetupPage({ onBack }) {
|
|
890
1051
|
const { providers, loading } = useSetupProviders();
|
|
891
|
-
const [selectedProvider, setSelectedProvider] =
|
|
892
|
-
const running =
|
|
1052
|
+
const [selectedProvider, setSelectedProvider] = useState9(null);
|
|
1053
|
+
const running = useMemo4(
|
|
893
1054
|
() => providers.filter((p) => p.status.running),
|
|
894
1055
|
[providers]
|
|
895
1056
|
);
|
|
896
|
-
const installed =
|
|
1057
|
+
const installed = useMemo4(
|
|
897
1058
|
() => providers.filter((p) => p.status.installed && !p.status.running),
|
|
898
1059
|
[providers]
|
|
899
1060
|
);
|
|
900
|
-
const notInstalled =
|
|
1061
|
+
const notInstalled = useMemo4(
|
|
901
1062
|
() => providers.filter((p) => !p.status.installed),
|
|
902
1063
|
[providers]
|
|
903
1064
|
);
|
|
904
|
-
const allProviders =
|
|
1065
|
+
const allProviders = useMemo4(
|
|
905
1066
|
() => [...running, ...installed, ...notInstalled],
|
|
906
1067
|
[running, installed, notInstalled]
|
|
907
1068
|
);
|
|
908
1069
|
const totalItems = allProviders.length + 1;
|
|
909
1070
|
const backIndex = allProviders.length;
|
|
910
|
-
const [cursorIndex, setCursorIndex] =
|
|
911
|
-
|
|
1071
|
+
const [cursorIndex, setCursorIndex] = useState9(0);
|
|
1072
|
+
useEffect9(() => {
|
|
912
1073
|
setCursorIndex(0);
|
|
913
1074
|
}, [allProviders.length]);
|
|
914
1075
|
useInput2((input, key) => {
|
|
@@ -1088,51 +1249,11 @@ function SetupPage({ onBack }) {
|
|
|
1088
1249
|
}
|
|
1089
1250
|
|
|
1090
1251
|
// src/tui/interfaces/pages/InterfacesPage.tsx
|
|
1091
|
-
import { useState as
|
|
1252
|
+
import { useState as useState13, useMemo as useMemo6, useEffect as useEffect13, useRef as useRef7 } from "react";
|
|
1092
1253
|
import { Box as Box8, Text as Text9, useInput as useInput5 } from "ink";
|
|
1093
|
-
import Spinner5 from "ink-spinner";
|
|
1094
|
-
|
|
1095
|
-
// src/tui/interfaces/hooks/useEditorSessions.ts
|
|
1096
|
-
import { useState as useState8, useEffect as useEffect8, useCallback as useCallback6, useRef as useRef4 } from "react";
|
|
1097
|
-
function useEditorSessions() {
|
|
1098
|
-
const [sessions, setSessions] = useState8([]);
|
|
1099
|
-
const [loading, setLoading] = useState8(true);
|
|
1100
|
-
const [error, setError] = useState8(null);
|
|
1101
|
-
const [refreshStatus, setRefreshStatus] = useState8("idle");
|
|
1102
|
-
const initialLoadDone = useRef4(false);
|
|
1103
|
-
const timerRef = useRef4();
|
|
1104
|
-
const refresh = useCallback6(async () => {
|
|
1105
|
-
if (!initialLoadDone.current) {
|
|
1106
|
-
setLoading(true);
|
|
1107
|
-
} else {
|
|
1108
|
-
setRefreshStatus("refreshing");
|
|
1109
|
-
}
|
|
1110
|
-
setError(null);
|
|
1111
|
-
try {
|
|
1112
|
-
const data = await getEditorSessions();
|
|
1113
|
-
setSessions(data);
|
|
1114
|
-
initialLoadDone.current = true;
|
|
1115
|
-
setRefreshStatus("refreshed");
|
|
1116
|
-
clearTimeout(timerRef.current);
|
|
1117
|
-
timerRef.current = setTimeout(() => setRefreshStatus("idle"), 1500);
|
|
1118
|
-
} catch (err) {
|
|
1119
|
-
setError(err instanceof Error ? err.message : "Failed to fetch sessions");
|
|
1120
|
-
setRefreshStatus("idle");
|
|
1121
|
-
} finally {
|
|
1122
|
-
setLoading(false);
|
|
1123
|
-
}
|
|
1124
|
-
}, []);
|
|
1125
|
-
useEffect8(() => {
|
|
1126
|
-
refresh();
|
|
1127
|
-
}, [refresh]);
|
|
1128
|
-
useEffect8(() => {
|
|
1129
|
-
return () => clearTimeout(timerRef.current);
|
|
1130
|
-
}, []);
|
|
1131
|
-
return { sessions, loading, error, refreshStatus, refresh };
|
|
1132
|
-
}
|
|
1133
1254
|
|
|
1134
1255
|
// src/tui/interfaces/hooks/useLocalInterface.ts
|
|
1135
|
-
import { useState as
|
|
1256
|
+
import { useState as useState10, useCallback as useCallback7, useRef as useRef5, useEffect as useEffect10 } from "react";
|
|
1136
1257
|
import { spawn } from "child_process";
|
|
1137
1258
|
import crypto from "crypto";
|
|
1138
1259
|
import fs from "fs";
|
|
@@ -1148,7 +1269,7 @@ function useLocalInterface({
|
|
|
1148
1269
|
sessionId
|
|
1149
1270
|
}) {
|
|
1150
1271
|
const key = `${appId}:${stepId}`;
|
|
1151
|
-
const [hasLocalCopy, setHasLocalCopy] =
|
|
1272
|
+
const [hasLocalCopy, setHasLocalCopy] = useState10(() => {
|
|
1152
1273
|
const existing = getLocalInterfacePath(key);
|
|
1153
1274
|
if (!existing) return false;
|
|
1154
1275
|
try {
|
|
@@ -1157,13 +1278,13 @@ function useLocalInterface({
|
|
|
1157
1278
|
return false;
|
|
1158
1279
|
}
|
|
1159
1280
|
});
|
|
1160
|
-
const [phase, setPhase] =
|
|
1161
|
-
const [outputLines, setOutputLines] =
|
|
1162
|
-
const [errorMessage, setErrorMessage] =
|
|
1281
|
+
const [phase, setPhase] = useState10("idle");
|
|
1282
|
+
const [outputLines, setOutputLines] = useState10([]);
|
|
1283
|
+
const [errorMessage, setErrorMessage] = useState10(null);
|
|
1163
1284
|
const processRef = useRef5(null);
|
|
1164
1285
|
const mountedRef = useRef5(true);
|
|
1165
1286
|
const stoppedRef = useRef5(false);
|
|
1166
|
-
|
|
1287
|
+
useEffect10(() => {
|
|
1167
1288
|
mountedRef.current = true;
|
|
1168
1289
|
return () => {
|
|
1169
1290
|
mountedRef.current = false;
|
|
@@ -1222,7 +1343,17 @@ function useLocalInterface({
|
|
|
1222
1343
|
if (mode === "script") {
|
|
1223
1344
|
env.MINDSTUDIO_API_KEY = getApiKey() ?? "";
|
|
1224
1345
|
return {
|
|
1225
|
-
args: [
|
|
1346
|
+
args: [
|
|
1347
|
+
"run",
|
|
1348
|
+
"dev:local",
|
|
1349
|
+
"--",
|
|
1350
|
+
"--app",
|
|
1351
|
+
appId,
|
|
1352
|
+
"--workflow",
|
|
1353
|
+
workflowId,
|
|
1354
|
+
"--step",
|
|
1355
|
+
stepId
|
|
1356
|
+
],
|
|
1226
1357
|
env
|
|
1227
1358
|
};
|
|
1228
1359
|
}
|
|
@@ -1290,14 +1421,21 @@ function useLocalInterface({
|
|
|
1290
1421
|
} catch (err) {
|
|
1291
1422
|
if (mountedRef.current) {
|
|
1292
1423
|
setPhase("error");
|
|
1293
|
-
setErrorMessage(
|
|
1294
|
-
err instanceof Error ? err.message : "Unknown error"
|
|
1295
|
-
);
|
|
1424
|
+
setErrorMessage(err instanceof Error ? err.message : "Unknown error");
|
|
1296
1425
|
}
|
|
1297
1426
|
}
|
|
1298
1427
|
};
|
|
1299
1428
|
run();
|
|
1300
|
-
}, [
|
|
1429
|
+
}, [
|
|
1430
|
+
key,
|
|
1431
|
+
mode,
|
|
1432
|
+
appId,
|
|
1433
|
+
stepId,
|
|
1434
|
+
workflowId,
|
|
1435
|
+
sessionId,
|
|
1436
|
+
appendOutput,
|
|
1437
|
+
runCommand
|
|
1438
|
+
]);
|
|
1301
1439
|
const stop = useCallback7(() => {
|
|
1302
1440
|
stoppedRef.current = true;
|
|
1303
1441
|
if (processRef.current) {
|
|
@@ -1324,9 +1462,7 @@ function useLocalInterface({
|
|
|
1324
1462
|
setHasLocalCopy(false);
|
|
1325
1463
|
appendOutput("Deleted successfully.");
|
|
1326
1464
|
} catch (err) {
|
|
1327
|
-
setErrorMessage(
|
|
1328
|
-
err instanceof Error ? err.message : "Failed to delete"
|
|
1329
|
-
);
|
|
1465
|
+
setErrorMessage(err instanceof Error ? err.message : "Failed to delete");
|
|
1330
1466
|
}
|
|
1331
1467
|
setPhase("idle");
|
|
1332
1468
|
}, [key, appendOutput]);
|
|
@@ -1343,7 +1479,7 @@ function useLocalInterface({
|
|
|
1343
1479
|
}
|
|
1344
1480
|
|
|
1345
1481
|
// src/tui/interfaces/pages/InterfaceSessionView.tsx
|
|
1346
|
-
import { useState as
|
|
1482
|
+
import { useState as useState11, useEffect as useEffect11 } from "react";
|
|
1347
1483
|
import { Box as Box6, Text as Text7, useInput as useInput3 } from "ink";
|
|
1348
1484
|
import os2 from "os";
|
|
1349
1485
|
import open from "open";
|
|
@@ -1364,8 +1500,8 @@ function InterfaceSessionView({
|
|
|
1364
1500
|
menuItems.push({ id: "delete", label: "Delete Local Copy" });
|
|
1365
1501
|
}
|
|
1366
1502
|
menuItems.push({ id: "back", label: "Back" });
|
|
1367
|
-
const [cursorIndex, setCursorIndex] =
|
|
1368
|
-
|
|
1503
|
+
const [cursorIndex, setCursorIndex] = useState11(0);
|
|
1504
|
+
useEffect11(() => {
|
|
1369
1505
|
setCursorIndex(0);
|
|
1370
1506
|
}, [hasLocalCopy]);
|
|
1371
1507
|
useInput3((input, key) => {
|
|
@@ -1447,7 +1583,7 @@ function InterfaceSessionView({
|
|
|
1447
1583
|
}
|
|
1448
1584
|
|
|
1449
1585
|
// src/tui/interfaces/pages/InterfaceRunningView.tsx
|
|
1450
|
-
import { useState as
|
|
1586
|
+
import { useState as useState12, useMemo as useMemo5, useRef as useRef6, useEffect as useEffect12 } from "react";
|
|
1451
1587
|
import { Box as Box7, Text as Text8, useInput as useInput4, useStdout as useStdout6 } from "ink";
|
|
1452
1588
|
import { execSync } from "child_process";
|
|
1453
1589
|
import os3 from "os";
|
|
@@ -1473,13 +1609,21 @@ function getPhaseLabel(phase) {
|
|
|
1473
1609
|
case "cloning":
|
|
1474
1610
|
return { text: "Cloning scaffold...", color: "cyan", showSpinner: true };
|
|
1475
1611
|
case "installing":
|
|
1476
|
-
return {
|
|
1612
|
+
return {
|
|
1613
|
+
text: "Installing dependencies...",
|
|
1614
|
+
color: "cyan",
|
|
1615
|
+
showSpinner: true
|
|
1616
|
+
};
|
|
1477
1617
|
case "running":
|
|
1478
1618
|
return { text: "Dev server running", color: "green", showSpinner: true };
|
|
1479
1619
|
case "error":
|
|
1480
1620
|
return { text: "Error", color: "red", showSpinner: false };
|
|
1481
1621
|
case "deleting":
|
|
1482
|
-
return {
|
|
1622
|
+
return {
|
|
1623
|
+
text: "Deleting local copy...",
|
|
1624
|
+
color: "yellow",
|
|
1625
|
+
showSpinner: true
|
|
1626
|
+
};
|
|
1483
1627
|
default:
|
|
1484
1628
|
return { text: "Idle", color: "gray", showSpinner: false };
|
|
1485
1629
|
}
|
|
@@ -1497,20 +1641,28 @@ function InterfaceRunningView({
|
|
|
1497
1641
|
const termHeight = (stdout?.rows ?? 24) - 4;
|
|
1498
1642
|
const isActive = phase === "cloning" || phase === "installing" || phase === "running" || phase === "deleting";
|
|
1499
1643
|
const displayPath = localPath?.replace(os3.homedir(), "~");
|
|
1500
|
-
const menuItems =
|
|
1644
|
+
const menuItems = useMemo5(() => {
|
|
1501
1645
|
const items = [];
|
|
1502
1646
|
if (isActive && displayPath) {
|
|
1503
|
-
items.push({
|
|
1504
|
-
|
|
1647
|
+
items.push({
|
|
1648
|
+
id: "claude",
|
|
1649
|
+
label: "Copy Claude Code Command",
|
|
1650
|
+
copyValue: `cd ${displayPath} && claude`
|
|
1651
|
+
});
|
|
1652
|
+
items.push({
|
|
1653
|
+
id: "codex",
|
|
1654
|
+
label: "Copy Codex Command",
|
|
1655
|
+
copyValue: `cd ${displayPath} && codex`
|
|
1656
|
+
});
|
|
1505
1657
|
items.push({ id: "reveal", label: "Open Folder" });
|
|
1506
1658
|
}
|
|
1507
1659
|
items.push({ id: "action", label: isActive ? "Stop" : "Back" });
|
|
1508
1660
|
return items;
|
|
1509
1661
|
}, [isActive, displayPath]);
|
|
1510
|
-
const [cursorIndex, setCursorIndex] =
|
|
1511
|
-
const [copiedId, setCopiedId] =
|
|
1662
|
+
const [cursorIndex, setCursorIndex] = useState12(0);
|
|
1663
|
+
const [copiedId, setCopiedId] = useState12(null);
|
|
1512
1664
|
const copiedTimerRef = useRef6();
|
|
1513
|
-
|
|
1665
|
+
useEffect12(() => {
|
|
1514
1666
|
return () => clearTimeout(copiedTimerRef.current);
|
|
1515
1667
|
}, []);
|
|
1516
1668
|
const headerHeight = 14;
|
|
@@ -1590,14 +1742,15 @@ function InterfaceRunningView({
|
|
|
1590
1742
|
"\u2022",
|
|
1591
1743
|
" Enter Select ",
|
|
1592
1744
|
"\u2022",
|
|
1593
|
-
" q/Esc
|
|
1745
|
+
" q/Esc",
|
|
1746
|
+
" ",
|
|
1594
1747
|
isActive ? "Stop" : "Back"
|
|
1595
1748
|
] }) })
|
|
1596
1749
|
] }) });
|
|
1597
1750
|
}
|
|
1598
1751
|
|
|
1599
1752
|
// src/tui/interfaces/pages/InterfacesPage.tsx
|
|
1600
|
-
import {
|
|
1753
|
+
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1601
1754
|
function getSessionStatus(item) {
|
|
1602
1755
|
if (item.kind === "script") return "running";
|
|
1603
1756
|
const status = item.step.spaEditorSession?.status;
|
|
@@ -1640,10 +1793,7 @@ function formatCount(interfaces, scripts) {
|
|
|
1640
1793
|
}
|
|
1641
1794
|
return parts.join(", ");
|
|
1642
1795
|
}
|
|
1643
|
-
function OfflineView({
|
|
1644
|
-
item,
|
|
1645
|
-
onBack
|
|
1646
|
-
}) {
|
|
1796
|
+
function OfflineView({ item, onBack }) {
|
|
1647
1797
|
useInput5((input, key) => {
|
|
1648
1798
|
if (input === "q" || key.escape || key.return) {
|
|
1649
1799
|
onBack();
|
|
@@ -1673,8 +1823,8 @@ function AgentListView({
|
|
|
1673
1823
|
const refreshIndex = sessions.length;
|
|
1674
1824
|
const backIndex = sessions.length + 1;
|
|
1675
1825
|
const totalItems = sessions.length + 2;
|
|
1676
|
-
const [cursorIndex, setCursorIndex] =
|
|
1677
|
-
|
|
1826
|
+
const [cursorIndex, setCursorIndex] = useState13(0);
|
|
1827
|
+
useEffect13(() => {
|
|
1678
1828
|
setCursorIndex(sessions.length > 0 ? 0 : backIndex);
|
|
1679
1829
|
}, [sessions.length, backIndex]);
|
|
1680
1830
|
useInput5((input, key) => {
|
|
@@ -1698,35 +1848,48 @@ function AgentListView({
|
|
|
1698
1848
|
});
|
|
1699
1849
|
return /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
1700
1850
|
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", underline: true, children: "Choose an Agent" }),
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
/* @__PURE__ */ jsx9(Text9, { color: "gray", children: "Open an app in MindStudio's editor to see sessions here." })
|
|
1704
|
-
] }) : /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginTop: 1, children: sessions.map((session, i) => {
|
|
1851
|
+
/* @__PURE__ */ jsx9(Text9, { color: "gray", children: "Don't see your agent? Make sure it's open in the MindStudio editor." }),
|
|
1852
|
+
sessions.length === 0 ? /* @__PURE__ */ jsx9(Box8, { marginTop: 1, flexDirection: "column", children: /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "No active editor sessions." }) }) : /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginTop: 1, children: sessions.map((session, i) => {
|
|
1705
1853
|
const isSelected = i === cursorIndex;
|
|
1706
1854
|
const stats = formatCount(
|
|
1707
1855
|
session.customInterfaceSteps.length,
|
|
1708
1856
|
session.scriptSteps.length
|
|
1709
1857
|
);
|
|
1710
|
-
return /* @__PURE__ */ jsxs8(
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1858
|
+
return /* @__PURE__ */ jsxs8(
|
|
1859
|
+
Box8,
|
|
1860
|
+
{
|
|
1861
|
+
flexDirection: "column",
|
|
1862
|
+
marginTop: i > 0 ? 1 : 0,
|
|
1863
|
+
children: [
|
|
1864
|
+
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
1865
|
+
/* @__PURE__ */ jsxs8(
|
|
1866
|
+
Text9,
|
|
1867
|
+
{
|
|
1868
|
+
color: isSelected ? "cyan" : "white",
|
|
1869
|
+
bold: isSelected,
|
|
1870
|
+
children: [
|
|
1871
|
+
isSelected ? "\u276F" : " ",
|
|
1872
|
+
" ",
|
|
1873
|
+
session.appName
|
|
1874
|
+
]
|
|
1875
|
+
}
|
|
1876
|
+
),
|
|
1877
|
+
isSelected && /* @__PURE__ */ jsx9(Text9, { color: "gray", children: " - Connect to this Agent" })
|
|
1878
|
+
] }),
|
|
1879
|
+
/* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
|
|
1880
|
+
" ",
|
|
1881
|
+
"https://app.mindstudio.ai/agents/",
|
|
1882
|
+
session.appId,
|
|
1883
|
+
"/edit"
|
|
1884
|
+
] }),
|
|
1885
|
+
stats !== "" && /* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
|
|
1886
|
+
" ",
|
|
1887
|
+
stats
|
|
1888
|
+
] })
|
|
1889
|
+
]
|
|
1890
|
+
},
|
|
1891
|
+
session.appId
|
|
1892
|
+
);
|
|
1730
1893
|
}) }),
|
|
1731
1894
|
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
1732
1895
|
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
@@ -1774,11 +1937,8 @@ function AgentDetailView({
|
|
|
1774
1937
|
onRefresh,
|
|
1775
1938
|
refreshStatus
|
|
1776
1939
|
}) {
|
|
1777
|
-
const [offlineItem, setOfflineItem] =
|
|
1778
|
-
|
|
1779
|
-
onRefresh();
|
|
1780
|
-
}, []);
|
|
1781
|
-
const interfaces = useMemo5(
|
|
1940
|
+
const [offlineItem, setOfflineItem] = useState13(null);
|
|
1941
|
+
const interfaces = useMemo6(
|
|
1782
1942
|
() => session.customInterfaceSteps.map((step) => ({
|
|
1783
1943
|
kind: "interface",
|
|
1784
1944
|
appId: session.appId,
|
|
@@ -1787,7 +1947,7 @@ function AgentDetailView({
|
|
|
1787
1947
|
})),
|
|
1788
1948
|
[session]
|
|
1789
1949
|
);
|
|
1790
|
-
const scripts =
|
|
1950
|
+
const scripts = useMemo6(
|
|
1791
1951
|
() => session.scriptSteps.map((step) => ({
|
|
1792
1952
|
kind: "script",
|
|
1793
1953
|
appId: session.appId,
|
|
@@ -1796,15 +1956,15 @@ function AgentDetailView({
|
|
|
1796
1956
|
})),
|
|
1797
1957
|
[session]
|
|
1798
1958
|
);
|
|
1799
|
-
const allItems =
|
|
1959
|
+
const allItems = useMemo6(
|
|
1800
1960
|
() => [...interfaces, ...scripts],
|
|
1801
1961
|
[interfaces, scripts]
|
|
1802
1962
|
);
|
|
1803
1963
|
const refreshIndex = allItems.length;
|
|
1804
1964
|
const backIndex = allItems.length + 1;
|
|
1805
1965
|
const totalItems = allItems.length + 2;
|
|
1806
|
-
const [cursorIndex, setCursorIndex] =
|
|
1807
|
-
|
|
1966
|
+
const [cursorIndex, setCursorIndex] = useState13(0);
|
|
1967
|
+
useEffect13(() => {
|
|
1808
1968
|
setCursorIndex(0);
|
|
1809
1969
|
}, [allItems.length]);
|
|
1810
1970
|
useInput5((input, key) => {
|
|
@@ -1840,48 +2000,83 @@ function AgentDetailView({
|
|
|
1840
2000
|
const scriptsOffset = interfaces.length;
|
|
1841
2001
|
return /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", flexGrow: 1, children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", paddingX: 1, marginTop: 1, children: [
|
|
1842
2002
|
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", underline: true, children: session.appName }),
|
|
2003
|
+
/* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
|
|
2004
|
+
"https://app.mindstudio.ai/agents/",
|
|
2005
|
+
session.appId,
|
|
2006
|
+
"/edit"
|
|
2007
|
+
] }),
|
|
1843
2008
|
/* @__PURE__ */ jsx9(Text9, { color: "gray", children: "Select an interface or script to connect your local editor." }),
|
|
1844
2009
|
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
2010
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", children: "Interfaces" }),
|
|
2011
|
+
interfaces.length > 0 ? /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginTop: 1, children: interfaces.map((item, i) => {
|
|
2012
|
+
const isSelected = i === cursorIndex;
|
|
2013
|
+
const status = getSessionStatus(item);
|
|
2014
|
+
const statusLabel = getStatusLabel(status);
|
|
2015
|
+
return /* @__PURE__ */ jsxs8(
|
|
2016
|
+
Box8,
|
|
2017
|
+
{
|
|
2018
|
+
flexDirection: "column",
|
|
2019
|
+
marginTop: i > 0 ? 1 : 0,
|
|
2020
|
+
children: [
|
|
2021
|
+
/* @__PURE__ */ jsxs8(
|
|
2022
|
+
Text9,
|
|
2023
|
+
{
|
|
2024
|
+
color: isSelected ? "cyan" : "white",
|
|
2025
|
+
bold: isSelected,
|
|
2026
|
+
children: [
|
|
2027
|
+
isSelected ? "\u276F" : " ",
|
|
2028
|
+
" ",
|
|
2029
|
+
item.step.workflowName,
|
|
2030
|
+
" -",
|
|
2031
|
+
" ",
|
|
2032
|
+
item.step.displayName
|
|
2033
|
+
]
|
|
2034
|
+
}
|
|
2035
|
+
),
|
|
2036
|
+
/* @__PURE__ */ jsx9(Box8, { children: /* @__PURE__ */ jsxs8(Text9, { color: statusLabel.color, children: [
|
|
2037
|
+
" ",
|
|
2038
|
+
statusLabel.text
|
|
2039
|
+
] }) })
|
|
2040
|
+
]
|
|
2041
|
+
},
|
|
2042
|
+
`${item.step.workflowId}:${item.step.stepId}`
|
|
2043
|
+
);
|
|
2044
|
+
}) }) : /* @__PURE__ */ jsx9(Text9, { color: "gray", children: " No interfaces in this agent." }),
|
|
2045
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
2046
|
+
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", children: "Scripts" }),
|
|
2047
|
+
scripts.length > 0 ? /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginTop: 1, children: scripts.map((item, i) => {
|
|
1869
2048
|
const index = scriptsOffset + i;
|
|
1870
2049
|
const isSelected = index === cursorIndex;
|
|
1871
|
-
return /* @__PURE__ */ jsxs8(
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
2050
|
+
return /* @__PURE__ */ jsxs8(
|
|
2051
|
+
Box8,
|
|
2052
|
+
{
|
|
2053
|
+
flexDirection: "column",
|
|
2054
|
+
marginTop: i > 0 ? 1 : 0,
|
|
2055
|
+
children: [
|
|
2056
|
+
/* @__PURE__ */ jsxs8(
|
|
2057
|
+
Text9,
|
|
2058
|
+
{
|
|
2059
|
+
color: isSelected ? "cyan" : "white",
|
|
2060
|
+
bold: isSelected,
|
|
2061
|
+
children: [
|
|
2062
|
+
isSelected ? "\u276F" : " ",
|
|
2063
|
+
" ",
|
|
2064
|
+
item.step.workflowName,
|
|
2065
|
+
" -",
|
|
2066
|
+
" ",
|
|
2067
|
+
item.step.displayName
|
|
2068
|
+
]
|
|
2069
|
+
}
|
|
2070
|
+
),
|
|
2071
|
+
/* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
|
|
2072
|
+
" ",
|
|
2073
|
+
item.step.entryFile
|
|
2074
|
+
] })
|
|
2075
|
+
]
|
|
2076
|
+
},
|
|
2077
|
+
`${item.step.workflowId}:${item.step.stepId}`
|
|
2078
|
+
);
|
|
2079
|
+
}) }) : /* @__PURE__ */ jsx9(Text9, { color: "gray", children: " No scripts in this agent." })
|
|
1885
2080
|
] }),
|
|
1886
2081
|
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: 1, children: [
|
|
1887
2082
|
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
@@ -1952,7 +2147,7 @@ function LocalDevView({
|
|
|
1952
2147
|
const name = `${item.step.workflowName} - ${item.step.displayName}`;
|
|
1953
2148
|
const isActive = phase === "cloning" || phase === "installing" || phase === "running" || phase === "deleting";
|
|
1954
2149
|
const wasActiveRef = useRef7(false);
|
|
1955
|
-
|
|
2150
|
+
useEffect13(() => {
|
|
1956
2151
|
if (isActive) {
|
|
1957
2152
|
wasActiveRef.current = true;
|
|
1958
2153
|
} else if (wasActiveRef.current && phase === "idle") {
|
|
@@ -1986,33 +2181,16 @@ function LocalDevView({
|
|
|
1986
2181
|
}
|
|
1987
2182
|
);
|
|
1988
2183
|
}
|
|
1989
|
-
function InterfacesPage({
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
/* @__PURE__ */ jsx9(Text9, { color: "cyan", children: /* @__PURE__ */ jsx9(Spinner5, { type: "dots" }) }),
|
|
1998
|
-
/* @__PURE__ */ jsx9(Text9, { children: " Loading editor sessions..." })
|
|
1999
|
-
] })
|
|
2000
|
-
] });
|
|
2001
|
-
}
|
|
2002
|
-
if (error) {
|
|
2003
|
-
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", flexGrow: 1, paddingX: 1, marginTop: 1, children: [
|
|
2004
|
-
/* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", underline: true, children: "Choose an Agent" }),
|
|
2005
|
-
/* @__PURE__ */ jsx9(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { color: "red", children: error }) })
|
|
2006
|
-
] });
|
|
2007
|
-
}
|
|
2184
|
+
function InterfacesPage({
|
|
2185
|
+
onBack,
|
|
2186
|
+
sessions,
|
|
2187
|
+
refreshStatus,
|
|
2188
|
+
refresh
|
|
2189
|
+
}) {
|
|
2190
|
+
const [selectedAppId, setSelectedAppId] = useState13(null);
|
|
2191
|
+
const [selectedItem, setSelectedItem] = useState13(null);
|
|
2008
2192
|
if (selectedItem) {
|
|
2009
|
-
return /* @__PURE__ */ jsx9(
|
|
2010
|
-
LocalDevView,
|
|
2011
|
-
{
|
|
2012
|
-
item: selectedItem,
|
|
2013
|
-
onBack: () => setSelectedItem(null)
|
|
2014
|
-
}
|
|
2015
|
-
);
|
|
2193
|
+
return /* @__PURE__ */ jsx9(LocalDevView, { item: selectedItem, onBack: () => setSelectedItem(null) });
|
|
2016
2194
|
}
|
|
2017
2195
|
if (selectedAppId) {
|
|
2018
2196
|
const session = sessions.find((s) => s.appId === selectedAppId);
|
|
@@ -2044,23 +2222,23 @@ function InterfacesPage({ onBack }) {
|
|
|
2044
2222
|
}
|
|
2045
2223
|
|
|
2046
2224
|
// src/tui/pages/OnboardingPage.tsx
|
|
2047
|
-
import { useEffect as
|
|
2225
|
+
import { useEffect as useEffect15, useCallback as useCallback9, useState as useState15, useMemo as useMemo7 } from "react";
|
|
2048
2226
|
import { Box as Box9, Text as Text10, useInput as useInput6 } from "ink";
|
|
2049
|
-
import
|
|
2050
|
-
import
|
|
2227
|
+
import Spinner5 from "ink-spinner";
|
|
2228
|
+
import chalk3 from "chalk";
|
|
2051
2229
|
|
|
2052
2230
|
// src/tui/hooks/useAuth.ts
|
|
2053
|
-
import { useState as
|
|
2231
|
+
import { useState as useState14, useCallback as useCallback8, useRef as useRef8, useEffect as useEffect14 } from "react";
|
|
2054
2232
|
import open3 from "open";
|
|
2055
2233
|
var POLL_INTERVAL = 2e3;
|
|
2056
2234
|
var MAX_ATTEMPTS = 30;
|
|
2057
2235
|
function useAuth() {
|
|
2058
|
-
const [status, setStatus] =
|
|
2059
|
-
const [authUrl, setAuthUrl] =
|
|
2060
|
-
const [timeRemaining, setTimeRemaining] =
|
|
2236
|
+
const [status, setStatus] = useState14("idle");
|
|
2237
|
+
const [authUrl, setAuthUrl] = useState14(null);
|
|
2238
|
+
const [timeRemaining, setTimeRemaining] = useState14(0);
|
|
2061
2239
|
const cancelledRef = useRef8(false);
|
|
2062
2240
|
const timerRef = useRef8(null);
|
|
2063
|
-
|
|
2241
|
+
useEffect14(() => {
|
|
2064
2242
|
return () => {
|
|
2065
2243
|
cancelledRef.current = true;
|
|
2066
2244
|
if (timerRef.current) clearInterval(timerRef.current);
|
|
@@ -2137,12 +2315,12 @@ function useAuth() {
|
|
|
2137
2315
|
}
|
|
2138
2316
|
|
|
2139
2317
|
// src/tui/pages/OnboardingPage.tsx
|
|
2140
|
-
import { Fragment as
|
|
2318
|
+
import { Fragment as Fragment4, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2141
2319
|
var SHIMMER_SPEED = 35;
|
|
2142
2320
|
function useShimmerLogo() {
|
|
2143
|
-
const [frame, setFrame] =
|
|
2144
|
-
const lines =
|
|
2145
|
-
const totalChars =
|
|
2321
|
+
const [frame, setFrame] = useState15(0);
|
|
2322
|
+
const lines = useMemo7(() => LogoString.split("\n"), []);
|
|
2323
|
+
const totalChars = useMemo7(() => {
|
|
2146
2324
|
let count = 0;
|
|
2147
2325
|
for (const line of lines) {
|
|
2148
2326
|
for (const ch of line) {
|
|
@@ -2152,13 +2330,13 @@ function useShimmerLogo() {
|
|
|
2152
2330
|
return count;
|
|
2153
2331
|
}, [lines]);
|
|
2154
2332
|
const cycleLength = totalChars + 40;
|
|
2155
|
-
|
|
2333
|
+
useEffect15(() => {
|
|
2156
2334
|
const interval = setInterval(() => {
|
|
2157
2335
|
setFrame((f) => (f + 1) % cycleLength);
|
|
2158
2336
|
}, SHIMMER_SPEED);
|
|
2159
2337
|
return () => clearInterval(interval);
|
|
2160
2338
|
}, [cycleLength]);
|
|
2161
|
-
return
|
|
2339
|
+
return useMemo7(() => {
|
|
2162
2340
|
const sweepPos = frame;
|
|
2163
2341
|
const holdEnd = totalChars + 20;
|
|
2164
2342
|
let charIdx = 0;
|
|
@@ -2182,13 +2360,13 @@ function useShimmerLogo() {
|
|
|
2182
2360
|
brightness = Math.max(0.1, 1 - fadeProgress);
|
|
2183
2361
|
}
|
|
2184
2362
|
if (brightness >= 0.9) {
|
|
2185
|
-
result +=
|
|
2363
|
+
result += chalk3.cyanBright.bold(ch);
|
|
2186
2364
|
} else if (brightness >= 0.6) {
|
|
2187
|
-
result +=
|
|
2365
|
+
result += chalk3.cyan(ch);
|
|
2188
2366
|
} else if (brightness >= 0.3) {
|
|
2189
|
-
result +=
|
|
2367
|
+
result += chalk3.rgb(0, 100, 120)(ch);
|
|
2190
2368
|
} else {
|
|
2191
|
-
result +=
|
|
2369
|
+
result += chalk3.rgb(0, 50, 60)(ch);
|
|
2192
2370
|
}
|
|
2193
2371
|
charIdx++;
|
|
2194
2372
|
}
|
|
@@ -2205,13 +2383,13 @@ function OnboardingPage({ onComplete }) {
|
|
|
2205
2383
|
cancel: cancelAuth
|
|
2206
2384
|
} = useAuth();
|
|
2207
2385
|
const shimmerLogo = useShimmerLogo();
|
|
2208
|
-
|
|
2386
|
+
useEffect15(() => {
|
|
2209
2387
|
if (authStatus === "success") {
|
|
2210
2388
|
const timer = setTimeout(() => onComplete(), 1500);
|
|
2211
2389
|
return () => clearTimeout(timer);
|
|
2212
2390
|
}
|
|
2213
2391
|
}, [authStatus, onComplete]);
|
|
2214
|
-
|
|
2392
|
+
useEffect15(() => {
|
|
2215
2393
|
return () => cancelAuth();
|
|
2216
2394
|
}, []);
|
|
2217
2395
|
const handleAction = useCallback9(() => {
|
|
@@ -2230,17 +2408,17 @@ function OnboardingPage({ onComplete }) {
|
|
|
2230
2408
|
/* @__PURE__ */ jsx10(Text10, { children: shimmerLogo }),
|
|
2231
2409
|
/* @__PURE__ */ jsx10(Box9, { flexDirection: "column", alignItems: "center", marginTop: 2, children: /* @__PURE__ */ jsx10(Text10, { bold: true, color: "white", children: "MindStudio Local Tunnel" }) }),
|
|
2232
2410
|
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", alignItems: "center", children: [
|
|
2233
|
-
authStatus === "idle" && /* @__PURE__ */ jsxs9(
|
|
2411
|
+
authStatus === "idle" && /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2234
2412
|
/* @__PURE__ */ jsx10(Text10, { color: "gray", children: "Connect your MindStudio account to get started." }),
|
|
2235
2413
|
/* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: "cyan", bold: true, children: "Press any key to Connect Account" }) })
|
|
2236
2414
|
] }),
|
|
2237
|
-
(authStatus === "expired" || authStatus === "timeout") && /* @__PURE__ */ jsxs9(
|
|
2415
|
+
(authStatus === "expired" || authStatus === "timeout") && /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2238
2416
|
/* @__PURE__ */ jsx10(Text10, { color: "red", children: authStatus === "expired" ? "Authorization expired." : "Authorization timed out." }),
|
|
2239
2417
|
/* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: "cyan", bold: true, children: "Press any key to Try Again" }) })
|
|
2240
2418
|
] }),
|
|
2241
|
-
authStatus === "waiting" && /* @__PURE__ */ jsxs9(
|
|
2419
|
+
authStatus === "waiting" && /* @__PURE__ */ jsxs9(Fragment4, { children: [
|
|
2242
2420
|
/* @__PURE__ */ jsxs9(Box9, { children: [
|
|
2243
|
-
/* @__PURE__ */ jsx10(Text10, { color: "cyan", children: /* @__PURE__ */ jsx10(
|
|
2421
|
+
/* @__PURE__ */ jsx10(Text10, { color: "cyan", children: /* @__PURE__ */ jsx10(Spinner5, { type: "dots" }) }),
|
|
2244
2422
|
/* @__PURE__ */ jsxs9(Text10, { children: [
|
|
2245
2423
|
" ",
|
|
2246
2424
|
"Waiting for browser authorization... (",
|
|
@@ -2264,7 +2442,7 @@ function OnboardingPage({ onComplete }) {
|
|
|
2264
2442
|
}
|
|
2265
2443
|
|
|
2266
2444
|
// src/tui/App.tsx
|
|
2267
|
-
import { Fragment as
|
|
2445
|
+
import { Fragment as Fragment5, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2268
2446
|
var MODEL_TYPE_MAP = {
|
|
2269
2447
|
text: "llm_chat",
|
|
2270
2448
|
image: "image_generation",
|
|
@@ -2279,6 +2457,7 @@ function App({ runner }) {
|
|
|
2279
2457
|
error: connectionError,
|
|
2280
2458
|
retry: retryConnection
|
|
2281
2459
|
} = useConnection();
|
|
2460
|
+
const editorSessions = useEditorSessions();
|
|
2282
2461
|
const {
|
|
2283
2462
|
providers,
|
|
2284
2463
|
loading: providersLoading,
|
|
@@ -2290,37 +2469,37 @@ function App({ runner }) {
|
|
|
2290
2469
|
loading: modelsLoading,
|
|
2291
2470
|
refresh: refreshModels
|
|
2292
2471
|
} = useModels();
|
|
2293
|
-
const { requests } = useRequests();
|
|
2472
|
+
const { requests, activeCount: activeRequestCount } = useRequests();
|
|
2294
2473
|
const {
|
|
2295
2474
|
syncedNames,
|
|
2296
2475
|
syncedModels,
|
|
2297
2476
|
refresh: refreshSynced
|
|
2298
2477
|
} = useSyncedModels(connectionStatus);
|
|
2299
2478
|
const shouldOnboard = getApiKey() === void 0 || getUserId() === void 0;
|
|
2300
|
-
const [page, setPage] =
|
|
2479
|
+
const [page, setPage] = useState16(
|
|
2301
2480
|
shouldOnboard ? "onboarding" : "dashboard"
|
|
2302
2481
|
);
|
|
2303
|
-
const [syncStatus, setSyncStatus] =
|
|
2482
|
+
const [syncStatus, setSyncStatus] = useState16(
|
|
2304
2483
|
"idle"
|
|
2305
2484
|
);
|
|
2306
|
-
const syncTimerRef = useRef9();
|
|
2485
|
+
const syncTimerRef = useRef9(void 0);
|
|
2307
2486
|
const lastSyncPayloadRef = useRef9("");
|
|
2308
|
-
|
|
2487
|
+
useEffect16(() => {
|
|
2309
2488
|
if (connectionStatus === "not_authenticated") {
|
|
2310
2489
|
setPage("onboarding");
|
|
2311
2490
|
}
|
|
2312
2491
|
}, [connectionStatus]);
|
|
2313
|
-
|
|
2492
|
+
useEffect16(() => {
|
|
2314
2493
|
if (page === "dashboard") {
|
|
2315
2494
|
refreshAll();
|
|
2316
2495
|
}
|
|
2317
2496
|
}, [page]);
|
|
2318
|
-
|
|
2497
|
+
useEffect16(() => {
|
|
2319
2498
|
if (connectionStatus === "connected" && syncedModels.length > 0) {
|
|
2320
2499
|
runner.start(syncedModels);
|
|
2321
2500
|
}
|
|
2322
2501
|
}, [connectionStatus, syncedModels, runner]);
|
|
2323
|
-
|
|
2502
|
+
useEffect16(() => () => runner.stop(), [runner]);
|
|
2324
2503
|
const refreshAll = useCallback10(
|
|
2325
2504
|
async (silent = false) => {
|
|
2326
2505
|
if (!silent) setSyncStatus("syncing");
|
|
@@ -2351,7 +2530,7 @@ function App({ runner }) {
|
|
|
2351
2530
|
},
|
|
2352
2531
|
[refreshProviders, refreshModels, refreshSynced]
|
|
2353
2532
|
);
|
|
2354
|
-
|
|
2533
|
+
useEffect16(() => {
|
|
2355
2534
|
if (connectionStatus !== "connected" || page !== "dashboard") return;
|
|
2356
2535
|
const interval = setInterval(() => refreshAll(true), 1500);
|
|
2357
2536
|
return () => clearInterval(interval);
|
|
@@ -2400,11 +2579,11 @@ function App({ runner }) {
|
|
|
2400
2579
|
},
|
|
2401
2580
|
[handleNavigate]
|
|
2402
2581
|
);
|
|
2403
|
-
const [termSize, setTermSize] =
|
|
2582
|
+
const [termSize, setTermSize] = useState16({
|
|
2404
2583
|
rows: stdout?.rows ?? 24,
|
|
2405
2584
|
columns: stdout?.columns ?? 80
|
|
2406
2585
|
});
|
|
2407
|
-
|
|
2586
|
+
useEffect16(() => {
|
|
2408
2587
|
if (!stdout) return;
|
|
2409
2588
|
const onResize = () => {
|
|
2410
2589
|
stdout.write("\x1B[2J\x1B[H");
|
|
@@ -2417,7 +2596,7 @@ function App({ runner }) {
|
|
|
2417
2596
|
}, [stdout]);
|
|
2418
2597
|
const termHeight = termSize.rows - 4;
|
|
2419
2598
|
const compactHeader = termSize.rows <= 45 || termSize.columns <= 90;
|
|
2420
|
-
return /* @__PURE__ */ jsx11(Box10, { flexDirection: "column", height: termHeight, overflow: "hidden", children: page === "onboarding" ? /* @__PURE__ */ jsx11(OnboardingPage, { onComplete: handleOnboardingComplete }) : /* @__PURE__ */ jsxs10(
|
|
2599
|
+
return /* @__PURE__ */ jsx11(Box10, { flexDirection: "column", height: termHeight, overflow: "hidden", children: page === "onboarding" ? /* @__PURE__ */ jsx11(OnboardingPage, { onComplete: handleOnboardingComplete }) : /* @__PURE__ */ jsxs10(Fragment5, { children: [
|
|
2421
2600
|
/* @__PURE__ */ jsx11(
|
|
2422
2601
|
Header,
|
|
2423
2602
|
{
|
|
@@ -2425,7 +2604,8 @@ function App({ runner }) {
|
|
|
2425
2604
|
environment,
|
|
2426
2605
|
configPath: getConfigPath(),
|
|
2427
2606
|
connectionError,
|
|
2428
|
-
compact: compactHeader
|
|
2607
|
+
compact: compactHeader,
|
|
2608
|
+
hasActiveRequest: activeRequestCount > 0
|
|
2429
2609
|
}
|
|
2430
2610
|
),
|
|
2431
2611
|
page === "dashboard" && /* @__PURE__ */ jsx11(
|
|
@@ -2439,6 +2619,8 @@ function App({ runner }) {
|
|
|
2439
2619
|
syncedNames,
|
|
2440
2620
|
modelsLoading,
|
|
2441
2621
|
syncStatus,
|
|
2622
|
+
editorSessions: editorSessions.sessions,
|
|
2623
|
+
editorsLoading: editorSessions.loading,
|
|
2442
2624
|
onNavigate: handleNavigate
|
|
2443
2625
|
}
|
|
2444
2626
|
),
|
|
@@ -2446,7 +2628,10 @@ function App({ runner }) {
|
|
|
2446
2628
|
page === "interfaces" && /* @__PURE__ */ jsx11(
|
|
2447
2629
|
InterfacesPage,
|
|
2448
2630
|
{
|
|
2449
|
-
onBack: () => setPage("dashboard")
|
|
2631
|
+
onBack: () => setPage("dashboard"),
|
|
2632
|
+
sessions: editorSessions.sessions,
|
|
2633
|
+
refreshStatus: editorSessions.refreshStatus,
|
|
2634
|
+
refresh: editorSessions.refresh
|
|
2450
2635
|
}
|
|
2451
2636
|
),
|
|
2452
2637
|
page !== "dashboard" && page !== "setup" && page !== "interfaces" && /* @__PURE__ */ jsx11(Box10, { flexGrow: 1 }),
|
|
@@ -2500,38 +2685,99 @@ async function checkForUpdate() {
|
|
|
2500
2685
|
}
|
|
2501
2686
|
|
|
2502
2687
|
// src/tui/components/UpdatePrompt.tsx
|
|
2503
|
-
import {
|
|
2688
|
+
import { useState as useState17, useEffect as useEffect17, useMemo as useMemo8 } from "react";
|
|
2689
|
+
import { Box as Box11, Text as Text11, useInput as useInput7, useStdout as useStdout8 } from "ink";
|
|
2690
|
+
import chalk4 from "chalk";
|
|
2504
2691
|
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2692
|
+
var SHIMMER_SPEED2 = 35;
|
|
2693
|
+
function useShimmerLogo2() {
|
|
2694
|
+
const [frame, setFrame] = useState17(0);
|
|
2695
|
+
const lines = useMemo8(() => LogoString.split("\n"), []);
|
|
2696
|
+
const totalChars = useMemo8(() => {
|
|
2697
|
+
let count = 0;
|
|
2698
|
+
for (const line of lines) {
|
|
2699
|
+
for (const ch of line) {
|
|
2700
|
+
if (ch !== " " && ch !== " ") count++;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
return count;
|
|
2704
|
+
}, [lines]);
|
|
2705
|
+
const cycleLength = totalChars + 40;
|
|
2706
|
+
useEffect17(() => {
|
|
2707
|
+
const interval = setInterval(() => {
|
|
2708
|
+
setFrame((f) => (f + 1) % cycleLength);
|
|
2709
|
+
}, SHIMMER_SPEED2);
|
|
2710
|
+
return () => clearInterval(interval);
|
|
2711
|
+
}, [cycleLength]);
|
|
2712
|
+
return useMemo8(() => {
|
|
2713
|
+
const sweepPos = frame;
|
|
2714
|
+
const holdEnd = totalChars + 20;
|
|
2715
|
+
let charIdx = 0;
|
|
2716
|
+
return lines.map((line) => {
|
|
2717
|
+
let result = "";
|
|
2718
|
+
for (let i = 0; i < line.length; i++) {
|
|
2719
|
+
const ch = line[i];
|
|
2720
|
+
if (ch === " " || ch === " ") {
|
|
2721
|
+
result += ch;
|
|
2722
|
+
continue;
|
|
2723
|
+
}
|
|
2724
|
+
let brightness;
|
|
2725
|
+
if (sweepPos <= totalChars) {
|
|
2726
|
+
const lag = charIdx;
|
|
2727
|
+
const t = sweepPos - lag;
|
|
2728
|
+
brightness = t <= 0 ? 0.1 : Math.min(1, t / 8);
|
|
2729
|
+
} else if (sweepPos <= holdEnd) {
|
|
2730
|
+
brightness = 1;
|
|
2731
|
+
} else {
|
|
2732
|
+
const fadeProgress = (sweepPos - holdEnd) / (cycleLength - holdEnd);
|
|
2733
|
+
brightness = Math.max(0.1, 1 - fadeProgress);
|
|
2734
|
+
}
|
|
2735
|
+
if (brightness >= 0.9) {
|
|
2736
|
+
result += chalk4.cyanBright.bold(ch);
|
|
2737
|
+
} else if (brightness >= 0.6) {
|
|
2738
|
+
result += chalk4.cyan(ch);
|
|
2739
|
+
} else if (brightness >= 0.3) {
|
|
2740
|
+
result += chalk4.rgb(0, 100, 120)(ch);
|
|
2741
|
+
} else {
|
|
2742
|
+
result += chalk4.rgb(0, 50, 60)(ch);
|
|
2743
|
+
}
|
|
2744
|
+
charIdx++;
|
|
2745
|
+
}
|
|
2746
|
+
return result;
|
|
2747
|
+
}).join("\n");
|
|
2748
|
+
}, [frame, lines, totalChars, cycleLength]);
|
|
2749
|
+
}
|
|
2505
2750
|
function UpdatePrompt({
|
|
2506
2751
|
currentVersion,
|
|
2507
2752
|
latestVersion,
|
|
2508
2753
|
onChoice
|
|
2509
2754
|
}) {
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
onChoice(false);
|
|
2515
|
-
}
|
|
2755
|
+
const { stdout } = useStdout8();
|
|
2756
|
+
const shimmerLogo = useShimmerLogo2();
|
|
2757
|
+
useInput7(() => {
|
|
2758
|
+
onChoice(true);
|
|
2516
2759
|
});
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2760
|
+
const termHeight = (stdout?.rows ?? 24) - 4;
|
|
2761
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", height: termHeight, children: [
|
|
2762
|
+
/* @__PURE__ */ jsx12(Box11, { flexGrow: 1 }),
|
|
2763
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "center", children: [
|
|
2764
|
+
/* @__PURE__ */ jsx12(Text11, { children: shimmerLogo }),
|
|
2765
|
+
/* @__PURE__ */ jsx12(Box11, { flexDirection: "column", alignItems: "center", marginTop: 2, children: /* @__PURE__ */ jsx12(Text11, { bold: true, color: "white", children: "MindStudio Local Tunnel" }) }),
|
|
2766
|
+
/* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", alignItems: "center", children: [
|
|
2767
|
+
/* @__PURE__ */ jsxs11(Text11, { color: "gray", children: [
|
|
2768
|
+
"Update required ",
|
|
2769
|
+
"\u2022",
|
|
2770
|
+
" v",
|
|
2771
|
+
currentVersion,
|
|
2772
|
+
" ",
|
|
2773
|
+
"\u2192",
|
|
2774
|
+
" v",
|
|
2775
|
+
latestVersion
|
|
2776
|
+
] }),
|
|
2777
|
+
/* @__PURE__ */ jsx12(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text11, { color: "cyan", bold: true, children: "Press any key to update" }) })
|
|
2528
2778
|
] })
|
|
2529
2779
|
] }),
|
|
2530
|
-
/* @__PURE__ */ jsx12(Box11, {
|
|
2531
|
-
"Press ",
|
|
2532
|
-
/* @__PURE__ */ jsx12(Text11, { bold: true, color: "cyan", children: "y" }),
|
|
2533
|
-
" to update, any other key to skip"
|
|
2534
|
-
] }) })
|
|
2780
|
+
/* @__PURE__ */ jsx12(Box11, { flexGrow: 1 })
|
|
2535
2781
|
] });
|
|
2536
2782
|
}
|
|
2537
2783
|
|
|
@@ -2581,16 +2827,13 @@ async function startTUI() {
|
|
|
2581
2827
|
console.clear();
|
|
2582
2828
|
}
|
|
2583
2829
|
const runner = new TunnelRunner();
|
|
2584
|
-
const { waitUntilExit } = render(
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
exitOnCtrlC: true
|
|
2588
|
-
}
|
|
2589
|
-
);
|
|
2830
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx13(App, { runner }), {
|
|
2831
|
+
exitOnCtrlC: true
|
|
2832
|
+
});
|
|
2590
2833
|
await waitUntilExit();
|
|
2591
2834
|
runner.stop();
|
|
2592
2835
|
}
|
|
2593
2836
|
export {
|
|
2594
2837
|
startTUI
|
|
2595
2838
|
};
|
|
2596
|
-
//# sourceMappingURL=tui-
|
|
2839
|
+
//# sourceMappingURL=tui-EAU7OA4X.js.map
|