@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.
@@ -20,19 +20,21 @@ import {
20
20
  setUserId,
21
21
  syncModels,
22
22
  verifyApiKey
23
- } from "./chunk-44NXQXRB.js";
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 useEffect15, useCallback as useCallback10, useState as useState15, useRef as useRef9 } from "react";
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({ items, onSelect, title }) {
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] = useState(getDefaultIndex);
126
- useEffect(() => {
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(Box2, { flexDirection: "column", paddingX: 1, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: "gray", children: /* @__PURE__ */ jsx2(Box2, { height: 1, overflow: "hidden", gap: 1, children: items.map((item, index) => {
163
- if (item.isSeparator) return null;
164
- const isSelected = index === selectedIndex;
165
- return /* @__PURE__ */ jsx2(
166
- Text2,
167
- {
168
- color: item.disabled ? "gray" : isSelected ? "cyan" : "white",
169
- bold: isSelected,
170
- wrap: "truncate-end",
171
- children: isSelected ? `\u276F ${item.label}` : ` ${item.label}`
172
- },
173
- item.id
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((item, idx) => item.isSeparator && idx > 0).length;
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(Box2, { flexDirection: "column", paddingX: 1, marginBottom: 1, borderStyle: "single", borderTop: true, borderBottom: false, borderLeft: false, borderRight: false, borderColor: "gray", children: [
180
- /* @__PURE__ */ jsx2(Box2, { marginTop: 1, children: /* @__PURE__ */ jsx2(Text2, { color: "gray", children: title ?? "Actions" }) }),
181
- /* @__PURE__ */ jsx2(Box2, { flexDirection: "column", children: items.map((item, index) => {
182
- if (item.isSeparator) {
183
- 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);
184
- }
185
- const isSelected = index === selectedIndex;
186
- const prefix = isSelected ? "\u276F" : " ";
187
- if (item.disabled) {
188
- return /* @__PURE__ */ jsx2(Box2, { height: 1, overflow: "hidden", children: /* @__PURE__ */ jsxs2(Text2, { color: "gray", wrap: "truncate-end", children: [
189
- prefix,
190
- " ",
191
- item.label,
192
- item.disabledReason ? ` (${item.disabledReason})` : ""
193
- ] }) }, item.id);
194
- }
195
- return /* @__PURE__ */ jsxs2(Box2, { height: 1, overflow: "hidden", children: [
196
- /* @__PURE__ */ jsxs2(Text2, { color: isSelected ? "cyan" : "white", bold: isSelected, wrap: "truncate-end", children: [
197
- prefix,
198
- " ",
199
- item.label
200
- ] }),
201
- isSelected && /* @__PURE__ */ jsxs2(Text2, { color: "gray", wrap: "truncate-end", children: [
202
- " - ",
203
- item.description
204
- ] })
205
- ] }, item.id);
206
- }) }),
207
- /* @__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" }) })
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 useState2, useEffect as useEffect2, useCallback } from "react";
304
+ import { useState as useState3, useEffect as useEffect3, useCallback } from "react";
213
305
  function useConnection() {
214
- const [status, setStatus] = useState2("connecting");
215
- const [error, setError] = useState2(null);
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
- useEffect2(() => {
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/models/hooks/useSetupProviders.ts
250
- import { useState as useState3, useEffect as useEffect3, useCallback as useCallback2, useRef } from "react";
251
- function useSetupProviders() {
252
- const [providers, setProviders] = useState3([]);
253
- const [loading, setLoading] = useState3(true);
254
- const [refreshing, setRefreshing] = useState3(false);
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
- useEffect3(() => {
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 useState4, useEffect as useEffect4, useCallback as useCallback3, useRef as useRef2 } from "react";
418
+ import { useState as useState6, useEffect as useEffect6, useCallback as useCallback4, useRef as useRef3 } from "react";
276
419
  function useModels() {
277
- const [models, setModels] = useState4([]);
278
- const [warnings, setWarnings] = useState4([]);
279
- const [loading, setLoading] = useState4(true);
280
- const [refreshing, setRefreshing] = useState4(false);
281
- const initialLoadDone = useRef2(false);
282
- const refresh = useCallback3(async () => {
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
- useEffect4(() => {
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 useState5, useEffect as useEffect5, useCallback as useCallback4, useRef as useRef3 } from "react";
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] = useState5([]);
317
- const requestsRef = useRef3(/* @__PURE__ */ new Map());
318
- useEffect5(() => {
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
- useEffect5(() => {
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 && { totalSteps: event.totalSteps }
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 = useCallback4(() => {
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 useState6, useEffect as useEffect6, useCallback as useCallback5 } from "react";
535
+ import { useState as useState8, useEffect as useEffect8, useCallback as useCallback6 } from "react";
391
536
  function useSyncedModels(connectionStatus) {
392
- const [syncedNames, setSyncedNames] = useState6(
393
- /* @__PURE__ */ new Set()
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
- useEffect6(() => {
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({ request, width }) {
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({ requests, maxVisible = 8, hasModels = true }) {
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 = useMemo(() => {
784
+ const menuItems = useMemo2(() => {
633
785
  return [
634
786
  {
635
787
  id: "interfaces",
636
- label: "Connect to IDE",
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: "Providers" }),
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 useState7, useMemo as useMemo3, useEffect as useEffect7 } from "react";
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 useMemo2 } from "react";
917
+ import { useMemo as useMemo3 } from "react";
757
918
  import { Text as Text5, useStdout as useStdout4 } from "ink";
758
- import chalk from "chalk";
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 = chalk.cyan;
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] = useState7(0);
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 = useMemo3(() => {
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 = useMemo3(() => {
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] = useState7(null);
892
- const running = useMemo3(
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 = useMemo3(
1057
+ const installed = useMemo4(
897
1058
  () => providers.filter((p) => p.status.installed && !p.status.running),
898
1059
  [providers]
899
1060
  );
900
- const notInstalled = useMemo3(
1061
+ const notInstalled = useMemo4(
901
1062
  () => providers.filter((p) => !p.status.installed),
902
1063
  [providers]
903
1064
  );
904
- const allProviders = useMemo3(
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] = useState7(0);
911
- useEffect7(() => {
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 useState12, useMemo as useMemo5, useEffect as useEffect12, useRef as useRef7 } from "react";
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 useState9, useCallback as useCallback7, useRef as useRef5, useEffect as useEffect9 } from "react";
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] = useState9(() => {
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] = useState9("idle");
1161
- const [outputLines, setOutputLines] = useState9([]);
1162
- const [errorMessage, setErrorMessage] = useState9(null);
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
- useEffect9(() => {
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: ["run", "dev:local", "--", "--app", appId, "--workflow", workflowId, "--step", stepId],
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
- }, [key, mode, appId, stepId, workflowId, sessionId, appendOutput, runCommand]);
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 useState10, useEffect as useEffect10 } from "react";
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] = useState10(0);
1368
- useEffect10(() => {
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 useState11, useMemo as useMemo4, useRef as useRef6, useEffect as useEffect11 } from "react";
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 { text: "Installing dependencies...", color: "cyan", showSpinner: true };
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 { text: "Deleting local copy...", color: "yellow", showSpinner: true };
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 = useMemo4(() => {
1644
+ const menuItems = useMemo5(() => {
1501
1645
  const items = [];
1502
1646
  if (isActive && displayPath) {
1503
- items.push({ id: "claude", label: "Copy Claude Code Command", copyValue: `cd ${displayPath} && claude` });
1504
- items.push({ id: "codex", label: "Copy Codex Command", copyValue: `cd ${displayPath} && codex` });
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] = useState11(0);
1511
- const [copiedId, setCopiedId] = useState11(null);
1662
+ const [cursorIndex, setCursorIndex] = useState12(0);
1663
+ const [copiedId, setCopiedId] = useState12(null);
1512
1664
  const copiedTimerRef = useRef6();
1513
- useEffect11(() => {
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 { Fragment as Fragment4, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
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] = useState12(0);
1677
- useEffect12(() => {
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
- sessions.length === 0 ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, flexDirection: "column", children: [
1702
- /* @__PURE__ */ jsx9(Text9, { color: "yellow", children: "No active editor sessions." }),
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(Box8, { flexDirection: "column", marginTop: i > 0 ? 1 : 0, children: [
1711
- /* @__PURE__ */ jsxs8(Box8, { children: [
1712
- /* @__PURE__ */ jsxs8(Text9, { color: isSelected ? "cyan" : "white", bold: isSelected, children: [
1713
- isSelected ? "\u276F" : " ",
1714
- " ",
1715
- session.appName
1716
- ] }),
1717
- isSelected && /* @__PURE__ */ jsx9(Text9, { color: "gray", children: " - Connect to this Agent" })
1718
- ] }),
1719
- /* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
1720
- " ",
1721
- "https://app.mindstudio.ai/agents/",
1722
- session.appId,
1723
- "/edit"
1724
- ] }),
1725
- /* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
1726
- " ",
1727
- stats
1728
- ] })
1729
- ] }, session.appId);
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] = useState12(null);
1778
- useEffect12(() => {
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 = useMemo5(
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 = useMemo5(
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] = useState12(0);
1807
- useEffect12(() => {
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
- interfaces.length > 0 && /* @__PURE__ */ jsxs8(Fragment4, { children: [
1846
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", underline: true, children: "Interfaces" }),
1847
- /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginTop: 1, children: interfaces.map((item, i) => {
1848
- const isSelected = i === cursorIndex;
1849
- const status = getSessionStatus(item);
1850
- const statusLabel = getStatusLabel(status);
1851
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: i > 0 ? 1 : 0, children: [
1852
- /* @__PURE__ */ jsxs8(Text9, { color: isSelected ? "cyan" : "white", bold: isSelected, children: [
1853
- isSelected ? "\u276F" : " ",
1854
- " ",
1855
- item.step.workflowName,
1856
- " - ",
1857
- item.step.displayName
1858
- ] }),
1859
- /* @__PURE__ */ jsx9(Box8, { children: /* @__PURE__ */ jsxs8(Text9, { color: statusLabel.color, children: [
1860
- " ",
1861
- statusLabel.text
1862
- ] }) })
1863
- ] }, `${item.step.workflowId}:${item.step.stepId}`);
1864
- }) })
1865
- ] }),
1866
- scripts.length > 0 && /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", marginTop: interfaces.length > 0 ? 1 : 0, children: [
1867
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", underline: true, children: "Scripts" }),
1868
- /* @__PURE__ */ jsx9(Box8, { flexDirection: "column", marginTop: 1, children: scripts.map((item, i) => {
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(Box8, { flexDirection: "column", marginTop: i > 0 ? 1 : 0, children: [
1872
- /* @__PURE__ */ jsxs8(Text9, { color: isSelected ? "cyan" : "white", bold: isSelected, children: [
1873
- isSelected ? "\u276F" : " ",
1874
- " ",
1875
- item.step.workflowName,
1876
- " - ",
1877
- item.step.displayName
1878
- ] }),
1879
- /* @__PURE__ */ jsxs8(Text9, { color: "gray", children: [
1880
- " ",
1881
- item.step.entryFile
1882
- ] })
1883
- ] }, `${item.step.workflowId}:${item.step.stepId}`);
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
- useEffect12(() => {
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({ onBack }) {
1990
- const { sessions, loading, error, refreshStatus, refresh } = useEditorSessions();
1991
- const [selectedAppId, setSelectedAppId] = useState12(null);
1992
- const [selectedItem, setSelectedItem] = useState12(null);
1993
- if (loading) {
1994
- return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", flexGrow: 1, paddingX: 1, marginTop: 1, children: [
1995
- /* @__PURE__ */ jsx9(Text9, { bold: true, color: "white", underline: true, children: "Choose an Agent" }),
1996
- /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
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 useEffect14, useCallback as useCallback9, useState as useState14, useMemo as useMemo6 } from "react";
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 Spinner6 from "ink-spinner";
2050
- import chalk2 from "chalk";
2227
+ import Spinner5 from "ink-spinner";
2228
+ import chalk3 from "chalk";
2051
2229
 
2052
2230
  // src/tui/hooks/useAuth.ts
2053
- import { useState as useState13, useCallback as useCallback8, useRef as useRef8, useEffect as useEffect13 } from "react";
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] = useState13("idle");
2059
- const [authUrl, setAuthUrl] = useState13(null);
2060
- const [timeRemaining, setTimeRemaining] = useState13(0);
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
- useEffect13(() => {
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 Fragment5, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
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] = useState14(0);
2144
- const lines = useMemo6(() => LogoString.split("\n"), []);
2145
- const totalChars = useMemo6(() => {
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
- useEffect14(() => {
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 useMemo6(() => {
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 += chalk2.cyanBright.bold(ch);
2363
+ result += chalk3.cyanBright.bold(ch);
2186
2364
  } else if (brightness >= 0.6) {
2187
- result += chalk2.cyan(ch);
2365
+ result += chalk3.cyan(ch);
2188
2366
  } else if (brightness >= 0.3) {
2189
- result += chalk2.rgb(0, 100, 120)(ch);
2367
+ result += chalk3.rgb(0, 100, 120)(ch);
2190
2368
  } else {
2191
- result += chalk2.rgb(0, 50, 60)(ch);
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
- useEffect14(() => {
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
- useEffect14(() => {
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(Fragment5, { children: [
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(Fragment5, { children: [
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(Fragment5, { children: [
2419
+ authStatus === "waiting" && /* @__PURE__ */ jsxs9(Fragment4, { children: [
2242
2420
  /* @__PURE__ */ jsxs9(Box9, { children: [
2243
- /* @__PURE__ */ jsx10(Text10, { color: "cyan", children: /* @__PURE__ */ jsx10(Spinner6, { type: "dots" }) }),
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 Fragment6, jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
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] = useState15(
2479
+ const [page, setPage] = useState16(
2301
2480
  shouldOnboard ? "onboarding" : "dashboard"
2302
2481
  );
2303
- const [syncStatus, setSyncStatus] = useState15(
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
- useEffect15(() => {
2487
+ useEffect16(() => {
2309
2488
  if (connectionStatus === "not_authenticated") {
2310
2489
  setPage("onboarding");
2311
2490
  }
2312
2491
  }, [connectionStatus]);
2313
- useEffect15(() => {
2492
+ useEffect16(() => {
2314
2493
  if (page === "dashboard") {
2315
2494
  refreshAll();
2316
2495
  }
2317
2496
  }, [page]);
2318
- useEffect15(() => {
2497
+ useEffect16(() => {
2319
2498
  if (connectionStatus === "connected" && syncedModels.length > 0) {
2320
2499
  runner.start(syncedModels);
2321
2500
  }
2322
2501
  }, [connectionStatus, syncedModels, runner]);
2323
- useEffect15(() => () => runner.stop(), [runner]);
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
- useEffect15(() => {
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] = useState15({
2582
+ const [termSize, setTermSize] = useState16({
2404
2583
  rows: stdout?.rows ?? 24,
2405
2584
  columns: stdout?.columns ?? 80
2406
2585
  });
2407
- useEffect15(() => {
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(Fragment6, { children: [
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 { Box as Box11, Text as Text11, useInput as useInput7 } from "ink";
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
- useInput7((input) => {
2511
- if (input.toLowerCase() === "y") {
2512
- onChoice(true);
2513
- } else {
2514
- onChoice(false);
2515
- }
2755
+ const { stdout } = useStdout8();
2756
+ const shimmerLogo = useShimmerLogo2();
2757
+ useInput7(() => {
2758
+ onChoice(true);
2516
2759
  });
2517
- return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", paddingY: 1, paddingX: 2, children: [
2518
- /* @__PURE__ */ jsxs11(Text11, { children: [
2519
- /* @__PURE__ */ jsx12(Text11, { color: "yellow", bold: true, children: "Update available:" }),
2520
- /* @__PURE__ */ jsxs11(Text11, { children: [
2521
- " ",
2522
- "v",
2523
- currentVersion,
2524
- " ",
2525
- "\u2192",
2526
- " v",
2527
- latestVersion
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, { marginTop: 1, children: /* @__PURE__ */ jsxs11(Text11, { children: [
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
- /* @__PURE__ */ jsx13(App, { runner }),
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-BW6XKMWK.js.map
2839
+ //# sourceMappingURL=tui-EAU7OA4X.js.map