bertrand 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/run-screen.js +507 -146
- package/package.json +1 -1
package/dist/run-screen.js
CHANGED
|
@@ -19,8 +19,8 @@ import { writeFileSync } from "fs";
|
|
|
19
19
|
import { render } from "@orchetron/storm";
|
|
20
20
|
|
|
21
21
|
// src/tui/screens/launch/index.tsx
|
|
22
|
-
import { useMemo as useMemo2, useState as
|
|
23
|
-
import { Box as
|
|
22
|
+
import { useMemo as useMemo2, useState as useState3 } from "react";
|
|
23
|
+
import { Box as Box5, Text as Text6, useTui } from "@orchetron/storm";
|
|
24
24
|
|
|
25
25
|
// src/tui/components/app-details.tsx
|
|
26
26
|
import { Box, Text } from "@orchetron/storm";
|
|
@@ -70,9 +70,178 @@ function Logo() {
|
|
|
70
70
|
}, undefined, false, undefined, this);
|
|
71
71
|
}
|
|
72
72
|
// src/tui/components/picker.tsx
|
|
73
|
-
import { useMemo, useState } from "react";
|
|
74
|
-
import { Box as
|
|
73
|
+
import { useMemo, useState as useState2 } from "react";
|
|
74
|
+
import { Box as Box4, Text as Text4, useGhostText, useInput as useInput2 } from "@orchetron/storm";
|
|
75
|
+
|
|
76
|
+
// src/tui/components/text-field.tsx
|
|
77
|
+
import { useEffect, useRef, useState } from "react";
|
|
78
|
+
import {
|
|
79
|
+
Box as Box3,
|
|
80
|
+
Text as Text3,
|
|
81
|
+
useInput,
|
|
82
|
+
useInterval,
|
|
83
|
+
usePaste
|
|
84
|
+
} from "@orchetron/storm";
|
|
75
85
|
import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
|
|
86
|
+
var bracketedPasteEnabled = false;
|
|
87
|
+
function ensureBracketedPaste() {
|
|
88
|
+
if (bracketedPasteEnabled)
|
|
89
|
+
return;
|
|
90
|
+
bracketedPasteEnabled = true;
|
|
91
|
+
process.stdout.write("\x1B[?2004h");
|
|
92
|
+
process.once("exit", () => {
|
|
93
|
+
process.stdout.write("\x1B[?2004l");
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function TextField({
|
|
97
|
+
value,
|
|
98
|
+
onChange,
|
|
99
|
+
onSubmit,
|
|
100
|
+
isFocused = true,
|
|
101
|
+
placeholder,
|
|
102
|
+
placeholderColor = "gray",
|
|
103
|
+
color,
|
|
104
|
+
ghost,
|
|
105
|
+
blink = true
|
|
106
|
+
}) {
|
|
107
|
+
const [cursor, setCursor] = useState(value.length);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
ensureBracketedPaste();
|
|
110
|
+
}, []);
|
|
111
|
+
const lastWrittenRef = useRef(value);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (lastWrittenRef.current !== value) {
|
|
114
|
+
lastWrittenRef.current = value;
|
|
115
|
+
setCursor(value.length);
|
|
116
|
+
}
|
|
117
|
+
}, [value]);
|
|
118
|
+
const [caretOn, setCaretOn] = useState(true);
|
|
119
|
+
useInterval(() => setCaretOn((c) => !c), 500, {
|
|
120
|
+
active: isFocused && blink
|
|
121
|
+
});
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
setCaretOn(true);
|
|
124
|
+
}, [value, cursor]);
|
|
125
|
+
const apply = (newValue, newCursor) => {
|
|
126
|
+
lastWrittenRef.current = newValue;
|
|
127
|
+
onChange(newValue);
|
|
128
|
+
setCursor(newCursor);
|
|
129
|
+
};
|
|
130
|
+
usePaste((text) => {
|
|
131
|
+
if (!isFocused)
|
|
132
|
+
return;
|
|
133
|
+
const sanitized = text.replace(/\r?\n/g, " ");
|
|
134
|
+
if (!sanitized)
|
|
135
|
+
return;
|
|
136
|
+
apply(value.slice(0, cursor) + sanitized + value.slice(cursor), cursor + sanitized.length);
|
|
137
|
+
}, { isActive: isFocused });
|
|
138
|
+
useInput((e) => {
|
|
139
|
+
if (!isFocused)
|
|
140
|
+
return;
|
|
141
|
+
if (e.consumed)
|
|
142
|
+
return;
|
|
143
|
+
if (e.key === "tab" || e.key === "escape" || e.key === "up" || e.key === "down") {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (e.key === "return") {
|
|
147
|
+
onSubmit?.(value);
|
|
148
|
+
e.consumed = true;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if (e.key === "backspace") {
|
|
152
|
+
if (cursor > 0) {
|
|
153
|
+
apply(value.slice(0, cursor - 1) + value.slice(cursor), cursor - 1);
|
|
154
|
+
}
|
|
155
|
+
e.consumed = true;
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (e.key === "delete") {
|
|
159
|
+
if (cursor < value.length) {
|
|
160
|
+
apply(value.slice(0, cursor) + value.slice(cursor + 1), cursor);
|
|
161
|
+
}
|
|
162
|
+
e.consumed = true;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (e.key === "left") {
|
|
166
|
+
if (cursor > 0) {
|
|
167
|
+
setCursor(cursor - 1);
|
|
168
|
+
e.consumed = true;
|
|
169
|
+
}
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (e.key === "right") {
|
|
173
|
+
if (cursor < value.length) {
|
|
174
|
+
setCursor(cursor + 1);
|
|
175
|
+
e.consumed = true;
|
|
176
|
+
}
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
if (e.key === "home") {
|
|
180
|
+
setCursor(0);
|
|
181
|
+
e.consumed = true;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
if (e.key === "end") {
|
|
185
|
+
setCursor(value.length);
|
|
186
|
+
e.consumed = true;
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (e.char && !e.ctrl && !e.meta) {
|
|
190
|
+
apply(value.slice(0, cursor) + e.char + value.slice(cursor), cursor + e.char.length);
|
|
191
|
+
e.consumed = true;
|
|
192
|
+
}
|
|
193
|
+
}, { isActive: isFocused, priority: 1 });
|
|
194
|
+
const showCaret = isFocused && (!blink || caretOn);
|
|
195
|
+
if (value.length === 0) {
|
|
196
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
197
|
+
flexDirection: "row",
|
|
198
|
+
children: [
|
|
199
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
200
|
+
inverse: showCaret,
|
|
201
|
+
color,
|
|
202
|
+
children: " "
|
|
203
|
+
}, undefined, false, undefined, this),
|
|
204
|
+
placeholder && /* @__PURE__ */ jsxDEV3(Text3, {
|
|
205
|
+
color: placeholderColor,
|
|
206
|
+
dim: true,
|
|
207
|
+
children: placeholder
|
|
208
|
+
}, undefined, false, undefined, this),
|
|
209
|
+
ghost && /* @__PURE__ */ jsxDEV3(Text3, {
|
|
210
|
+
dim: true,
|
|
211
|
+
children: ghost
|
|
212
|
+
}, undefined, false, undefined, this)
|
|
213
|
+
]
|
|
214
|
+
}, undefined, true, undefined, this);
|
|
215
|
+
}
|
|
216
|
+
const before = value.slice(0, cursor);
|
|
217
|
+
const atCursor = value.slice(cursor, cursor + 1) || " ";
|
|
218
|
+
const after = value.slice(cursor + 1);
|
|
219
|
+
return /* @__PURE__ */ jsxDEV3(Box3, {
|
|
220
|
+
flexDirection: "row",
|
|
221
|
+
children: [
|
|
222
|
+
before && /* @__PURE__ */ jsxDEV3(Text3, {
|
|
223
|
+
color,
|
|
224
|
+
children: before
|
|
225
|
+
}, undefined, false, undefined, this),
|
|
226
|
+
/* @__PURE__ */ jsxDEV3(Text3, {
|
|
227
|
+
inverse: showCaret,
|
|
228
|
+
color,
|
|
229
|
+
children: atCursor
|
|
230
|
+
}, undefined, false, undefined, this),
|
|
231
|
+
after && /* @__PURE__ */ jsxDEV3(Text3, {
|
|
232
|
+
color,
|
|
233
|
+
children: after
|
|
234
|
+
}, undefined, false, undefined, this),
|
|
235
|
+
ghost && /* @__PURE__ */ jsxDEV3(Text3, {
|
|
236
|
+
dim: true,
|
|
237
|
+
children: ghost
|
|
238
|
+
}, undefined, false, undefined, this)
|
|
239
|
+
]
|
|
240
|
+
}, undefined, true, undefined, this);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/tui/components/picker.tsx
|
|
244
|
+
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
76
245
|
var NEW_KEY = "__new__";
|
|
77
246
|
function isSelectable(row) {
|
|
78
247
|
if (row.value === NEW_KEY)
|
|
@@ -92,6 +261,38 @@ function findNextSelectable(rows, from, direction) {
|
|
|
92
261
|
function findFirstSelectable(rows) {
|
|
93
262
|
return findNextSelectable(rows, 0, 1);
|
|
94
263
|
}
|
|
264
|
+
function isHeader(row) {
|
|
265
|
+
return !!row && row.value !== NEW_KEY && row.kind === "header";
|
|
266
|
+
}
|
|
267
|
+
function findCurrentGroupStart(rows, cursor) {
|
|
268
|
+
for (let i = cursor;i >= 0; i--) {
|
|
269
|
+
if (isHeader(rows[i])) {
|
|
270
|
+
return findNextSelectable(rows, i + 1, 1);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return findFirstSelectable(rows);
|
|
274
|
+
}
|
|
275
|
+
function findNextGroupStart(rows, cursor) {
|
|
276
|
+
for (let i = cursor + 1;i < rows.length; i++) {
|
|
277
|
+
if (isHeader(rows[i])) {
|
|
278
|
+
return findNextSelectable(rows, i + 1, 1);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return -1;
|
|
282
|
+
}
|
|
283
|
+
function findPrevGroupStart(rows, cursor) {
|
|
284
|
+
let i = cursor;
|
|
285
|
+
for (;i >= 0; i--) {
|
|
286
|
+
if (isHeader(rows[i]))
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
for (i = i - 1;i >= 0; i--) {
|
|
290
|
+
if (isHeader(rows[i])) {
|
|
291
|
+
return findNextSelectable(rows, i + 1, 1);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
return -1;
|
|
295
|
+
}
|
|
95
296
|
function Picker(props) {
|
|
96
297
|
const {
|
|
97
298
|
items,
|
|
@@ -101,8 +302,14 @@ function Picker(props) {
|
|
|
101
302
|
emptyHint,
|
|
102
303
|
maxVisible = 12
|
|
103
304
|
} = props;
|
|
104
|
-
const [filter, setFilter] =
|
|
105
|
-
const [cursor, setCursor] =
|
|
305
|
+
const [filter, setFilter] = useState2("");
|
|
306
|
+
const [cursor, setCursor] = useState2(0);
|
|
307
|
+
const ghostResult = useGhostText({
|
|
308
|
+
value: filter,
|
|
309
|
+
cursor: filter.length,
|
|
310
|
+
suggest: props.suggest ?? []
|
|
311
|
+
});
|
|
312
|
+
const ghost = props.suggest ? ghostResult.ghost : "";
|
|
106
313
|
const filtered = useMemo(() => {
|
|
107
314
|
const q = filter.trim().toLowerCase();
|
|
108
315
|
if (!q)
|
|
@@ -121,7 +328,7 @@ function Picker(props) {
|
|
|
121
328
|
setTimeout(() => setCursor(next), 0);
|
|
122
329
|
}
|
|
123
330
|
}
|
|
124
|
-
|
|
331
|
+
useInput2((e) => {
|
|
125
332
|
if (!isFocused)
|
|
126
333
|
return;
|
|
127
334
|
if (e.key === "escape" && filter.length > 0) {
|
|
@@ -141,8 +348,29 @@ function Picker(props) {
|
|
|
141
348
|
const next = findNextSelectable(visibleRows, c + 1, 1);
|
|
142
349
|
return next === -1 ? c : next;
|
|
143
350
|
});
|
|
351
|
+
} else if (filter.length === 0 && e.key === "left") {
|
|
352
|
+
setCursor((c) => {
|
|
353
|
+
const curr = findCurrentGroupStart(visibleRows, c);
|
|
354
|
+
if (curr !== -1 && curr !== c)
|
|
355
|
+
return curr;
|
|
356
|
+
const prev = findPrevGroupStart(visibleRows, c);
|
|
357
|
+
return prev === -1 ? c : prev;
|
|
358
|
+
});
|
|
359
|
+
} else if (filter.length === 0 && e.key === "right") {
|
|
360
|
+
setCursor((c) => {
|
|
361
|
+
const next = findNextGroupStart(visibleRows, c);
|
|
362
|
+
return next === -1 ? c : next;
|
|
363
|
+
});
|
|
364
|
+
} else if (e.key === "tab" && ghost) {
|
|
365
|
+
const full = ghostResult.accept();
|
|
366
|
+
if (full !== null)
|
|
367
|
+
setFilter(full);
|
|
144
368
|
} else if (e.key === "tab" && props.mode === "multi") {
|
|
145
369
|
props.onDone();
|
|
370
|
+
} else if (props.onKey) {
|
|
371
|
+
const row = visibleRows[cursor];
|
|
372
|
+
const cursorItem = row && row.value !== NEW_KEY ? row : null;
|
|
373
|
+
props.onKey(e, cursorItem);
|
|
146
374
|
}
|
|
147
375
|
}, { isActive: isFocused });
|
|
148
376
|
const submitCursor = () => {
|
|
@@ -176,50 +404,49 @@ function Picker(props) {
|
|
|
176
404
|
const visibleEnd = Math.min(visibleRows.length, visibleStart + maxVisible);
|
|
177
405
|
const slice = visibleRows.slice(visibleStart, visibleEnd);
|
|
178
406
|
const selectedSet = props.mode === "multi" ? new Set(props.selected) : new Set;
|
|
179
|
-
return /* @__PURE__ */
|
|
407
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
180
408
|
flexDirection: "column",
|
|
181
409
|
gap: 0,
|
|
182
410
|
width: "100%",
|
|
183
411
|
children: [
|
|
184
|
-
props.mode === "multi" && props.selected.length > 0 && /* @__PURE__ */
|
|
412
|
+
props.mode === "multi" && props.selected.length > 0 && /* @__PURE__ */ jsxDEV4(Box4, {
|
|
185
413
|
flexDirection: "row",
|
|
186
414
|
gap: 1,
|
|
187
415
|
children: [
|
|
188
|
-
/* @__PURE__ */
|
|
416
|
+
/* @__PURE__ */ jsxDEV4(Text4, {
|
|
189
417
|
dim: true,
|
|
190
418
|
children: "Selected:"
|
|
191
419
|
}, undefined, false, undefined, this),
|
|
192
420
|
props.selected.map((v) => {
|
|
193
421
|
const item = items.find((i) => i.value === v);
|
|
194
|
-
return /* @__PURE__ */
|
|
422
|
+
return /* @__PURE__ */ jsxDEV4(Text4, {
|
|
195
423
|
color: item?.color ?? "cyan",
|
|
196
424
|
children: item?.label ?? v
|
|
197
425
|
}, v, false, undefined, this);
|
|
198
426
|
})
|
|
199
427
|
]
|
|
200
428
|
}, undefined, true, undefined, this),
|
|
201
|
-
/* @__PURE__ */
|
|
429
|
+
/* @__PURE__ */ jsxDEV4(Box4, {
|
|
202
430
|
borderStyle: "round",
|
|
203
431
|
borderColor: isFocused ? "green" : undefined,
|
|
204
432
|
borderDimColor: !isFocused,
|
|
205
433
|
paddingX: 1,
|
|
206
|
-
children: /* @__PURE__ */
|
|
434
|
+
children: /* @__PURE__ */ jsxDEV4(TextField, {
|
|
207
435
|
value: filter,
|
|
208
436
|
onChange: setFilter,
|
|
209
437
|
onSubmit: handleSubmit,
|
|
210
438
|
placeholder,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
isFocused
|
|
439
|
+
isFocused,
|
|
440
|
+
ghost
|
|
214
441
|
}, undefined, false, undefined, this)
|
|
215
442
|
}, undefined, false, undefined, this),
|
|
216
|
-
/* @__PURE__ */
|
|
443
|
+
/* @__PURE__ */ jsxDEV4(Box4, {
|
|
217
444
|
flexDirection: "column",
|
|
218
445
|
borderStyle: "round",
|
|
219
446
|
borderDimColor: true,
|
|
220
447
|
paddingX: 1,
|
|
221
448
|
children: [
|
|
222
|
-
visibleStart > 0 && /* @__PURE__ */
|
|
449
|
+
visibleStart > 0 && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
223
450
|
dim: true,
|
|
224
451
|
children: [
|
|
225
452
|
"\u25B2 ",
|
|
@@ -227,7 +454,7 @@ function Picker(props) {
|
|
|
227
454
|
" more above"
|
|
228
455
|
]
|
|
229
456
|
}, undefined, true, undefined, this),
|
|
230
|
-
slice.length === 0 && emptyHint && /* @__PURE__ */
|
|
457
|
+
slice.length === 0 && emptyHint && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
231
458
|
dim: true,
|
|
232
459
|
children: emptyHint
|
|
233
460
|
}, undefined, false, undefined, this),
|
|
@@ -237,21 +464,21 @@ function Picker(props) {
|
|
|
237
464
|
const isNew = row.value === NEW_KEY;
|
|
238
465
|
const showDivider = isNew && filtered.length > 0 && i > 0;
|
|
239
466
|
if (isNew) {
|
|
240
|
-
return /* @__PURE__ */
|
|
467
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
241
468
|
flexDirection: "column",
|
|
242
469
|
children: [
|
|
243
|
-
showDivider && /* @__PURE__ */
|
|
470
|
+
showDivider && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
244
471
|
dim: true,
|
|
245
472
|
children: "\u2500".repeat(Math.min(20, filter.length + 12))
|
|
246
473
|
}, undefined, false, undefined, this),
|
|
247
|
-
/* @__PURE__ */
|
|
474
|
+
/* @__PURE__ */ jsxDEV4(Box4, {
|
|
248
475
|
flexDirection: "row",
|
|
249
476
|
gap: 1,
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
color: isCursor ? "black" : "cyan",
|
|
477
|
+
children: /* @__PURE__ */ jsxDEV4(Text4, {
|
|
478
|
+
color: isCursor ? "green" : "cyan",
|
|
253
479
|
bold: true,
|
|
254
480
|
children: [
|
|
481
|
+
isCursor ? "\u276F " : " ",
|
|
255
482
|
"\u271A create \u201C",
|
|
256
483
|
filter.trim(),
|
|
257
484
|
"\u201D"
|
|
@@ -263,9 +490,9 @@ function Picker(props) {
|
|
|
263
490
|
}
|
|
264
491
|
const item = row;
|
|
265
492
|
if (item.kind === "header") {
|
|
266
|
-
return /* @__PURE__ */
|
|
493
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
267
494
|
flexDirection: "row",
|
|
268
|
-
children: /* @__PURE__ */
|
|
495
|
+
children: /* @__PURE__ */ jsxDEV4(Text4, {
|
|
269
496
|
dim: true,
|
|
270
497
|
bold: true,
|
|
271
498
|
color: item.color ?? undefined,
|
|
@@ -276,39 +503,35 @@ function Picker(props) {
|
|
|
276
503
|
const isSelected = selectedSet.has(item.value);
|
|
277
504
|
const marker = props.mode === "multi" ? isSelected ? "\u2713 " : " " : "";
|
|
278
505
|
const dim = item.dim || item.disabled;
|
|
279
|
-
return /* @__PURE__ */
|
|
506
|
+
return /* @__PURE__ */ jsxDEV4(Box4, {
|
|
280
507
|
flexDirection: "row",
|
|
281
508
|
justifyContent: "space-between",
|
|
282
509
|
gap: 1,
|
|
283
|
-
backgroundColor: isCursor ? "green" : undefined,
|
|
284
510
|
children: [
|
|
285
|
-
/* @__PURE__ */
|
|
511
|
+
/* @__PURE__ */ jsxDEV4(Box4, {
|
|
286
512
|
flexDirection: "row",
|
|
287
513
|
gap: 0,
|
|
288
|
-
children: item.display ? item.display : /* @__PURE__ */
|
|
289
|
-
color: isCursor ? "
|
|
514
|
+
children: item.display ? typeof item.display === "function" ? item.display(isCursor) : item.display : /* @__PURE__ */ jsxDEV4(Text4, {
|
|
515
|
+
color: isCursor ? "green" : item.color ?? undefined,
|
|
290
516
|
bold: isCursor,
|
|
291
517
|
dim: !isCursor && dim,
|
|
292
518
|
children: [
|
|
519
|
+
isCursor ? "\u276F " : " ",
|
|
293
520
|
marker,
|
|
294
521
|
item.label
|
|
295
522
|
]
|
|
296
523
|
}, undefined, true, undefined, this)
|
|
297
524
|
}, undefined, false, undefined, this),
|
|
298
|
-
item.meta && /* @__PURE__ */
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
bold: true,
|
|
304
|
-
dim: !isCursor && dim,
|
|
305
|
-
children: item.meta
|
|
306
|
-
}, undefined, false, undefined, this)
|
|
525
|
+
item.meta && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
526
|
+
color: isCursor ? "green" : undefined,
|
|
527
|
+
bold: isCursor,
|
|
528
|
+
dim: !isCursor,
|
|
529
|
+
children: item.meta
|
|
307
530
|
}, undefined, false, undefined, this)
|
|
308
531
|
]
|
|
309
532
|
}, item.value, true, undefined, this);
|
|
310
533
|
}),
|
|
311
|
-
visibleEnd < visibleRows.length && /* @__PURE__ */
|
|
534
|
+
visibleEnd < visibleRows.length && /* @__PURE__ */ jsxDEV4(Text4, {
|
|
312
535
|
dim: true,
|
|
313
536
|
children: [
|
|
314
537
|
"\u25BC ",
|
|
@@ -322,8 +545,8 @@ function Picker(props) {
|
|
|
322
545
|
}, undefined, true, undefined, this);
|
|
323
546
|
}
|
|
324
547
|
// src/tui/components/status-dot.tsx
|
|
325
|
-
import { Text as
|
|
326
|
-
import { jsxDEV as
|
|
548
|
+
import { Text as Text5 } from "@orchetron/storm";
|
|
549
|
+
import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
|
|
327
550
|
var STATUS_COLORS = {
|
|
328
551
|
active: "orange",
|
|
329
552
|
waiting: "red",
|
|
@@ -332,7 +555,7 @@ var STATUS_COLORS = {
|
|
|
332
555
|
};
|
|
333
556
|
function StatusDot({ status }) {
|
|
334
557
|
const color = STATUS_COLORS[status] ?? "#6B7280";
|
|
335
|
-
return /* @__PURE__ */
|
|
558
|
+
return /* @__PURE__ */ jsxDEV5(Text5, {
|
|
336
559
|
color,
|
|
337
560
|
children: "\u25CF"
|
|
338
561
|
}, undefined, false, undefined, this);
|
|
@@ -504,6 +727,35 @@ function getAllSessions(opts) {
|
|
|
504
727
|
}
|
|
505
728
|
return query.all();
|
|
506
729
|
}
|
|
730
|
+
function updateSessionStatus(id, status) {
|
|
731
|
+
return getDb().update(sessions).set({ status, updatedAt: sql2`(datetime('now'))` }).where(eq(sessions.id, id)).returning().get();
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/lib/session-archive.ts
|
|
735
|
+
var ACTIVE_STATUSES = ["active", "waiting"];
|
|
736
|
+
function archiveSession(id) {
|
|
737
|
+
const session = getSession(id);
|
|
738
|
+
if (!session)
|
|
739
|
+
return { ok: false, reason: "not-found" };
|
|
740
|
+
if (ACTIVE_STATUSES.includes(session.status)) {
|
|
741
|
+
return { ok: false, reason: "active" };
|
|
742
|
+
}
|
|
743
|
+
if (session.status === "archived") {
|
|
744
|
+
return { ok: false, reason: "already-archived" };
|
|
745
|
+
}
|
|
746
|
+
const updated = updateSessionStatus(id, "archived");
|
|
747
|
+
return { ok: true, session: updated };
|
|
748
|
+
}
|
|
749
|
+
function unarchiveSession(id) {
|
|
750
|
+
const session = getSession(id);
|
|
751
|
+
if (!session)
|
|
752
|
+
return { ok: false, reason: "not-found" };
|
|
753
|
+
if (session.status !== "archived") {
|
|
754
|
+
return { ok: false, reason: "not-archived" };
|
|
755
|
+
}
|
|
756
|
+
const updated = updateSessionStatus(id, "paused");
|
|
757
|
+
return { ok: true, session: updated };
|
|
758
|
+
}
|
|
507
759
|
|
|
508
760
|
// src/lib/format.ts
|
|
509
761
|
var SECOND = 1000;
|
|
@@ -559,14 +811,16 @@ function parseSessionName(input) {
|
|
|
559
811
|
}
|
|
560
812
|
|
|
561
813
|
// src/tui/screens/launch/index.tsx
|
|
562
|
-
import { jsxDEV as
|
|
814
|
+
import { jsxDEV as jsxDEV6, Fragment } from "react/jsx-dev-runtime";
|
|
563
815
|
var STATUS_COLOR = {
|
|
564
816
|
paused: "gold",
|
|
565
|
-
waiting: "red"
|
|
817
|
+
waiting: "red",
|
|
818
|
+
archived: "purple"
|
|
566
819
|
};
|
|
567
820
|
var STATUS_RANK = {
|
|
568
821
|
paused: 0,
|
|
569
|
-
waiting: 1
|
|
822
|
+
waiting: 1,
|
|
823
|
+
archived: 2
|
|
570
824
|
};
|
|
571
825
|
function statusRank(status) {
|
|
572
826
|
return STATUS_RANK[status] ?? 99;
|
|
@@ -578,34 +832,53 @@ function sessionRow(s) {
|
|
|
578
832
|
const status = s.session.status;
|
|
579
833
|
const color = STATUS_COLOR[status] ?? "gray";
|
|
580
834
|
const disabled = status === "waiting";
|
|
835
|
+
const isArchived = status === "archived";
|
|
581
836
|
return {
|
|
582
837
|
value: `${s.groupPath}/${s.session.slug}`,
|
|
583
838
|
label: `${s.groupPath}/${s.session.slug} ${status}`,
|
|
584
839
|
meta: formatAgo(recencyKey(s)),
|
|
585
840
|
disabled,
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
841
|
+
dim: isArchived,
|
|
842
|
+
display: (isCursor) => {
|
|
843
|
+
const cursorColor = "green";
|
|
844
|
+
const dotColor = isCursor ? cursorColor : color;
|
|
845
|
+
const textColor = isCursor ? cursorColor : color;
|
|
846
|
+
const slugColor = isCursor ? cursorColor : undefined;
|
|
847
|
+
const dimText = !isCursor && (disabled || isArchived);
|
|
848
|
+
return /* @__PURE__ */ jsxDEV6(Fragment, {
|
|
849
|
+
children: [
|
|
850
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
851
|
+
color: cursorColor,
|
|
852
|
+
bold: true,
|
|
853
|
+
children: isCursor ? "\u276F " : " "
|
|
854
|
+
}, undefined, false, undefined, this),
|
|
855
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
856
|
+
color: dotColor,
|
|
857
|
+
bold: isCursor,
|
|
858
|
+
children: [
|
|
859
|
+
"\u25CF",
|
|
860
|
+
" "
|
|
861
|
+
]
|
|
862
|
+
}, undefined, true, undefined, this),
|
|
863
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
864
|
+
color: textColor,
|
|
865
|
+
bold: isCursor,
|
|
866
|
+
dim: dimText,
|
|
867
|
+
children: status.padEnd(8)
|
|
868
|
+
}, undefined, false, undefined, this),
|
|
869
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
870
|
+
color: slugColor,
|
|
871
|
+
children: " "
|
|
872
|
+
}, undefined, false, undefined, this),
|
|
873
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
874
|
+
color: slugColor,
|
|
875
|
+
bold: isCursor,
|
|
876
|
+
dim: dimText,
|
|
877
|
+
children: s.session.slug
|
|
878
|
+
}, undefined, false, undefined, this)
|
|
879
|
+
]
|
|
880
|
+
}, undefined, true, undefined, this);
|
|
881
|
+
}
|
|
609
882
|
};
|
|
610
883
|
}
|
|
611
884
|
function groupHeader(groupPath) {
|
|
@@ -617,10 +890,20 @@ function groupHeader(groupPath) {
|
|
|
617
890
|
}
|
|
618
891
|
function Launch({ onSelect }) {
|
|
619
892
|
const { exit } = useTui();
|
|
620
|
-
const [error, setError] =
|
|
621
|
-
const
|
|
893
|
+
const [error, setError] = useState3(null);
|
|
894
|
+
const [notice, setNotice] = useState3(null);
|
|
895
|
+
const [showArchived, setShowArchived] = useState3(false);
|
|
896
|
+
const [refreshKey, setRefreshKey] = useState3(0);
|
|
897
|
+
const allSessions = useMemo2(() => getAllSessions({ excludeArchived: !showArchived }), [showArchived, refreshKey]);
|
|
622
898
|
const visibleSessions = useMemo2(() => {
|
|
623
|
-
return allSessions.filter((s) =>
|
|
899
|
+
return allSessions.filter((s) => {
|
|
900
|
+
const st = s.session.status;
|
|
901
|
+
if (st === "paused" || st === "waiting")
|
|
902
|
+
return true;
|
|
903
|
+
if (st === "archived")
|
|
904
|
+
return showArchived;
|
|
905
|
+
return false;
|
|
906
|
+
}).sort((a, b) => {
|
|
624
907
|
const g = a.groupPath.localeCompare(b.groupPath);
|
|
625
908
|
if (g !== 0)
|
|
626
909
|
return g;
|
|
@@ -629,7 +912,7 @@ function Launch({ onSelect }) {
|
|
|
629
912
|
return r;
|
|
630
913
|
return recencyKey(b).localeCompare(recencyKey(a));
|
|
631
914
|
});
|
|
632
|
-
}, [allSessions]);
|
|
915
|
+
}, [allSessions, showArchived]);
|
|
633
916
|
const items = useMemo2(() => {
|
|
634
917
|
const rows = [];
|
|
635
918
|
let lastGroup = null;
|
|
@@ -642,6 +925,15 @@ function Launch({ onSelect }) {
|
|
|
642
925
|
}
|
|
643
926
|
return rows;
|
|
644
927
|
}, [visibleSessions]);
|
|
928
|
+
const suggestions = useMemo2(() => {
|
|
929
|
+
const groups2 = new Set;
|
|
930
|
+
const names = [];
|
|
931
|
+
for (const s of allSessions) {
|
|
932
|
+
groups2.add(`${s.groupPath}/`);
|
|
933
|
+
names.push(`${s.groupPath}/${s.session.slug}`);
|
|
934
|
+
}
|
|
935
|
+
return [...groups2, ...names];
|
|
936
|
+
}, [allSessions]);
|
|
645
937
|
const sessionByValue = useMemo2(() => {
|
|
646
938
|
const map = new Map;
|
|
647
939
|
for (const s of allSessions) {
|
|
@@ -649,6 +941,31 @@ function Launch({ onSelect }) {
|
|
|
649
941
|
}
|
|
650
942
|
return map;
|
|
651
943
|
}, [allSessions]);
|
|
944
|
+
const handleArchiveKey = (cursorItem) => {
|
|
945
|
+
if (!cursorItem)
|
|
946
|
+
return;
|
|
947
|
+
const existing = sessionByValue.get(cursorItem.value);
|
|
948
|
+
if (!existing)
|
|
949
|
+
return;
|
|
950
|
+
setError(null);
|
|
951
|
+
if (existing.session.status === "archived") {
|
|
952
|
+
const result2 = unarchiveSession(existing.session.id);
|
|
953
|
+
if (result2.ok) {
|
|
954
|
+
setNotice(`Unarchived ${cursorItem.value}`);
|
|
955
|
+
setRefreshKey((k) => k + 1);
|
|
956
|
+
} else {
|
|
957
|
+
setError(`Couldn't unarchive: ${result2.reason}`);
|
|
958
|
+
}
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
const result = archiveSession(existing.session.id);
|
|
962
|
+
if (result.ok) {
|
|
963
|
+
setNotice(`Archived ${cursorItem.value}`);
|
|
964
|
+
setRefreshKey((k) => k + 1);
|
|
965
|
+
} else {
|
|
966
|
+
setError(`Couldn't archive: ${result.reason}`);
|
|
967
|
+
}
|
|
968
|
+
};
|
|
652
969
|
const select = (selection) => {
|
|
653
970
|
onSelect(selection);
|
|
654
971
|
exit();
|
|
@@ -673,64 +990,67 @@ function Launch({ onSelect }) {
|
|
|
673
990
|
const counts = useMemo2(() => {
|
|
674
991
|
let paused = 0;
|
|
675
992
|
let waiting = 0;
|
|
993
|
+
let archived = 0;
|
|
676
994
|
for (const s of visibleSessions) {
|
|
677
995
|
if (s.session.status === "paused")
|
|
678
996
|
paused++;
|
|
679
997
|
else if (s.session.status === "waiting")
|
|
680
998
|
waiting++;
|
|
999
|
+
else if (s.session.status === "archived")
|
|
1000
|
+
archived++;
|
|
681
1001
|
}
|
|
682
|
-
return { paused, waiting };
|
|
1002
|
+
return { paused, waiting, archived };
|
|
683
1003
|
}, [visibleSessions]);
|
|
684
|
-
return /* @__PURE__ */
|
|
1004
|
+
return /* @__PURE__ */ jsxDEV6(Box5, {
|
|
685
1005
|
flexDirection: "column",
|
|
686
1006
|
paddingY: 1,
|
|
687
1007
|
gap: 1,
|
|
688
1008
|
children: [
|
|
689
|
-
/* @__PURE__ */
|
|
1009
|
+
/* @__PURE__ */ jsxDEV6(Box5, {
|
|
690
1010
|
marginX: 1,
|
|
691
|
-
children: /* @__PURE__ */
|
|
1011
|
+
children: /* @__PURE__ */ jsxDEV6(Logo, {}, undefined, false, undefined, this)
|
|
692
1012
|
}, undefined, false, undefined, this),
|
|
693
|
-
/* @__PURE__ */
|
|
1013
|
+
/* @__PURE__ */ jsxDEV6(Box5, {
|
|
694
1014
|
flexDirection: "column",
|
|
695
1015
|
marginX: 2,
|
|
696
1016
|
gap: 1,
|
|
697
1017
|
children: [
|
|
698
|
-
/* @__PURE__ */
|
|
699
|
-
/* @__PURE__ */
|
|
1018
|
+
/* @__PURE__ */ jsxDEV6(AppDetails, {}, undefined, false, undefined, this),
|
|
1019
|
+
/* @__PURE__ */ jsxDEV6(Box5, {
|
|
700
1020
|
flexDirection: "column",
|
|
701
1021
|
gap: 1,
|
|
702
1022
|
children: [
|
|
703
|
-
/* @__PURE__ */
|
|
1023
|
+
/* @__PURE__ */ jsxDEV6(Box5, {
|
|
704
1024
|
flexDirection: "row",
|
|
705
1025
|
gap: 1,
|
|
706
1026
|
children: [
|
|
707
|
-
/* @__PURE__ */
|
|
1027
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
708
1028
|
bold: true,
|
|
709
1029
|
children: "Sessions"
|
|
710
1030
|
}, undefined, false, undefined, this),
|
|
711
|
-
visibleSessions.length === 0 ? /* @__PURE__ */
|
|
1031
|
+
visibleSessions.length === 0 ? /* @__PURE__ */ jsxDEV6(Text6, {
|
|
712
1032
|
dim: true,
|
|
713
1033
|
children: "\xB7 none \u2014 type group/slug to create"
|
|
714
|
-
}, undefined, false, undefined, this) : /* @__PURE__ */
|
|
1034
|
+
}, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV6(Fragment, {
|
|
715
1035
|
children: [
|
|
716
|
-
/* @__PURE__ */
|
|
1036
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
717
1037
|
dim: true,
|
|
718
1038
|
children: "\xB7"
|
|
719
1039
|
}, undefined, false, undefined, this),
|
|
720
|
-
/* @__PURE__ */
|
|
1040
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
721
1041
|
color: "gold",
|
|
722
1042
|
children: [
|
|
723
1043
|
counts.paused,
|
|
724
1044
|
" paused"
|
|
725
1045
|
]
|
|
726
1046
|
}, undefined, true, undefined, this),
|
|
727
|
-
counts.waiting > 0 && /* @__PURE__ */
|
|
1047
|
+
counts.waiting > 0 && /* @__PURE__ */ jsxDEV6(Fragment, {
|
|
728
1048
|
children: [
|
|
729
|
-
/* @__PURE__ */
|
|
1049
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
730
1050
|
dim: true,
|
|
731
1051
|
children: "\xB7"
|
|
732
1052
|
}, undefined, false, undefined, this),
|
|
733
|
-
/* @__PURE__ */
|
|
1053
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
734
1054
|
color: "red",
|
|
735
1055
|
dim: true,
|
|
736
1056
|
children: [
|
|
@@ -739,27 +1059,68 @@ function Launch({ onSelect }) {
|
|
|
739
1059
|
]
|
|
740
1060
|
}, undefined, true, undefined, this)
|
|
741
1061
|
]
|
|
1062
|
+
}, undefined, true, undefined, this),
|
|
1063
|
+
showArchived && counts.archived > 0 && /* @__PURE__ */ jsxDEV6(Fragment, {
|
|
1064
|
+
children: [
|
|
1065
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
1066
|
+
dim: true,
|
|
1067
|
+
children: "\xB7"
|
|
1068
|
+
}, undefined, false, undefined, this),
|
|
1069
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
1070
|
+
color: "purple",
|
|
1071
|
+
dim: true,
|
|
1072
|
+
children: [
|
|
1073
|
+
counts.archived,
|
|
1074
|
+
" archived"
|
|
1075
|
+
]
|
|
1076
|
+
}, undefined, true, undefined, this)
|
|
1077
|
+
]
|
|
742
1078
|
}, undefined, true, undefined, this)
|
|
743
1079
|
]
|
|
744
1080
|
}, undefined, true, undefined, this)
|
|
745
1081
|
]
|
|
746
1082
|
}, undefined, true, undefined, this),
|
|
747
|
-
/* @__PURE__ */
|
|
1083
|
+
/* @__PURE__ */ jsxDEV6(Picker, {
|
|
748
1084
|
mode: "single",
|
|
749
1085
|
items,
|
|
750
1086
|
isFocused: true,
|
|
1087
|
+
maxVisible: 24,
|
|
1088
|
+
suggest: suggestions,
|
|
751
1089
|
placeholder: "Filter or type group/slug to create\u2026",
|
|
752
|
-
emptyHint: "No paused sessions. Type group/slug to create one.",
|
|
753
|
-
onSubmit: handleSubmit
|
|
1090
|
+
emptyHint: showArchived ? "No sessions. Type group/slug to create one." : "No paused sessions. Type group/slug to create one.",
|
|
1091
|
+
onSubmit: handleSubmit,
|
|
1092
|
+
onKey: (e, cursorItem) => {
|
|
1093
|
+
if (e.key === "c" && e.ctrl) {
|
|
1094
|
+
select({ type: "quit" });
|
|
1095
|
+
} else if (e.key === "a" && e.ctrl) {
|
|
1096
|
+
handleArchiveKey(cursorItem);
|
|
1097
|
+
} else if (e.key === "tab") {
|
|
1098
|
+
setError(null);
|
|
1099
|
+
setNotice(null);
|
|
1100
|
+
setShowArchived((v) => !v);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
}, undefined, false, undefined, this),
|
|
1104
|
+
notice && /* @__PURE__ */ jsxDEV6(Text6, {
|
|
1105
|
+
color: "green",
|
|
1106
|
+
children: notice
|
|
754
1107
|
}, undefined, false, undefined, this),
|
|
755
|
-
error && /* @__PURE__ */
|
|
1108
|
+
error && /* @__PURE__ */ jsxDEV6(Text6, {
|
|
756
1109
|
color: "red",
|
|
757
1110
|
children: error
|
|
758
1111
|
}, undefined, false, undefined, this),
|
|
759
|
-
/* @__PURE__ */
|
|
1112
|
+
/* @__PURE__ */ jsxDEV6(Text6, {
|
|
760
1113
|
dim: true,
|
|
761
|
-
children:
|
|
762
|
-
|
|
1114
|
+
children: [
|
|
1115
|
+
"\u2191\u2193 navigate \xB7 \u2190\u2192 skip group \xB7 enter continue/create \xB7 ctrl+a",
|
|
1116
|
+
" ",
|
|
1117
|
+
showArchived ? "(un)archive" : "archive",
|
|
1118
|
+
" \xB7 tab",
|
|
1119
|
+
" ",
|
|
1120
|
+
showArchived ? "hide" : "show",
|
|
1121
|
+
" archived \xB7 ctrl+c quit"
|
|
1122
|
+
]
|
|
1123
|
+
}, undefined, true, undefined, this)
|
|
763
1124
|
]
|
|
764
1125
|
}, undefined, true, undefined, this)
|
|
765
1126
|
]
|
|
@@ -769,8 +1130,8 @@ function Launch({ onSelect }) {
|
|
|
769
1130
|
}
|
|
770
1131
|
|
|
771
1132
|
// src/tui/screens/Exit.tsx
|
|
772
|
-
import { useState as
|
|
773
|
-
import { Box as
|
|
1133
|
+
import { useState as useState4 } from "react";
|
|
1134
|
+
import { Box as Box6, Text as Text7, useInput as useInput3, useTui as useTui2 } from "@orchetron/storm";
|
|
774
1135
|
|
|
775
1136
|
// src/db/queries/conversations.ts
|
|
776
1137
|
import { eq as eq2, and as and2, desc, sql as sql3 } from "drizzle-orm";
|
|
@@ -779,7 +1140,7 @@ function getConversationsBySession(sessionId) {
|
|
|
779
1140
|
}
|
|
780
1141
|
|
|
781
1142
|
// src/tui/screens/Exit.tsx
|
|
782
|
-
import { jsxDEV as
|
|
1143
|
+
import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
|
|
783
1144
|
var OPTIONS = [
|
|
784
1145
|
{ action: "save", label: "Save", hint: "Keep session paused for later" },
|
|
785
1146
|
{
|
|
@@ -800,10 +1161,10 @@ var OPTIONS = [
|
|
|
800
1161
|
];
|
|
801
1162
|
function Exit({ sessionId, onAction }) {
|
|
802
1163
|
const { exit } = useTui2();
|
|
803
|
-
const [cursor, setCursor] =
|
|
1164
|
+
const [cursor, setCursor] = useState4(0);
|
|
804
1165
|
const session = getSession(sessionId);
|
|
805
1166
|
const conversations2 = session ? getConversationsBySession(session.id) : [];
|
|
806
|
-
|
|
1167
|
+
useInput3((e) => {
|
|
807
1168
|
if (e.key === "c" && e.ctrl)
|
|
808
1169
|
exit();
|
|
809
1170
|
if (e.key === "up" || e.key === "k") {
|
|
@@ -820,37 +1181,37 @@ function Exit({ sessionId, onAction }) {
|
|
|
820
1181
|
}
|
|
821
1182
|
});
|
|
822
1183
|
if (!session) {
|
|
823
|
-
return /* @__PURE__ */
|
|
1184
|
+
return /* @__PURE__ */ jsxDEV7(Text7, {
|
|
824
1185
|
color: "red",
|
|
825
1186
|
children: "Session not found"
|
|
826
1187
|
}, undefined, false, undefined, this);
|
|
827
1188
|
}
|
|
828
1189
|
const duration = session.endedAt && session.startedAt ? formatDuration(new Date(session.endedAt).getTime() - new Date(session.startedAt).getTime()) : null;
|
|
829
|
-
return /* @__PURE__ */
|
|
1190
|
+
return /* @__PURE__ */ jsxDEV7(Box6, {
|
|
830
1191
|
flexDirection: "column",
|
|
831
1192
|
padding: 1,
|
|
832
1193
|
gap: 1,
|
|
833
1194
|
children: [
|
|
834
|
-
/* @__PURE__ */
|
|
1195
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
835
1196
|
bold: true,
|
|
836
1197
|
color: "#82AAFF",
|
|
837
1198
|
children: "Session ended"
|
|
838
1199
|
}, undefined, false, undefined, this),
|
|
839
|
-
/* @__PURE__ */
|
|
1200
|
+
/* @__PURE__ */ jsxDEV7(Box6, {
|
|
840
1201
|
flexDirection: "column",
|
|
841
1202
|
children: [
|
|
842
|
-
/* @__PURE__ */
|
|
1203
|
+
/* @__PURE__ */ jsxDEV7(Box6, {
|
|
843
1204
|
flexDirection: "row",
|
|
844
1205
|
gap: 1,
|
|
845
1206
|
children: [
|
|
846
|
-
/* @__PURE__ */
|
|
1207
|
+
/* @__PURE__ */ jsxDEV7(StatusDot, {
|
|
847
1208
|
status: session.status
|
|
848
1209
|
}, undefined, false, undefined, this),
|
|
849
|
-
/* @__PURE__ */
|
|
1210
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
850
1211
|
bold: true,
|
|
851
1212
|
children: session.name
|
|
852
1213
|
}, undefined, false, undefined, this),
|
|
853
|
-
duration && /* @__PURE__ */
|
|
1214
|
+
duration && /* @__PURE__ */ jsxDEV7(Text7, {
|
|
854
1215
|
dim: true,
|
|
855
1216
|
children: [
|
|
856
1217
|
"(",
|
|
@@ -860,7 +1221,7 @@ function Exit({ sessionId, onAction }) {
|
|
|
860
1221
|
}, undefined, true, undefined, this)
|
|
861
1222
|
]
|
|
862
1223
|
}, undefined, true, undefined, this),
|
|
863
|
-
/* @__PURE__ */
|
|
1224
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
864
1225
|
dim: true,
|
|
865
1226
|
children: [
|
|
866
1227
|
conversations2.length,
|
|
@@ -870,28 +1231,28 @@ function Exit({ sessionId, onAction }) {
|
|
|
870
1231
|
}, undefined, true, undefined, this)
|
|
871
1232
|
]
|
|
872
1233
|
}, undefined, true, undefined, this),
|
|
873
|
-
/* @__PURE__ */
|
|
1234
|
+
/* @__PURE__ */ jsxDEV7(Box6, {
|
|
874
1235
|
flexDirection: "column",
|
|
875
|
-
children: OPTIONS.map((opt, i) => /* @__PURE__ */
|
|
1236
|
+
children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsxDEV7(Box6, {
|
|
876
1237
|
flexDirection: "row",
|
|
877
1238
|
gap: 1,
|
|
878
1239
|
children: [
|
|
879
|
-
/* @__PURE__ */
|
|
1240
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
880
1241
|
children: i === cursor ? "\u276F" : " "
|
|
881
1242
|
}, undefined, false, undefined, this),
|
|
882
|
-
/* @__PURE__ */
|
|
1243
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
883
1244
|
bold: i === cursor,
|
|
884
1245
|
children: opt.label
|
|
885
1246
|
}, undefined, false, undefined, this),
|
|
886
|
-
/* @__PURE__ */
|
|
1247
|
+
/* @__PURE__ */ jsxDEV7(Text7, {
|
|
887
1248
|
dim: true,
|
|
888
1249
|
children: opt.hint
|
|
889
1250
|
}, undefined, false, undefined, this)
|
|
890
1251
|
]
|
|
891
1252
|
}, opt.action, true, undefined, this))
|
|
892
1253
|
}, undefined, false, undefined, this),
|
|
893
|
-
/* @__PURE__ */
|
|
894
|
-
children: /* @__PURE__ */
|
|
1254
|
+
/* @__PURE__ */ jsxDEV7(Box6, {
|
|
1255
|
+
children: /* @__PURE__ */ jsxDEV7(Text7, {
|
|
895
1256
|
dim: true,
|
|
896
1257
|
children: "\u2191\u2193 navigate \xB7 enter select \xB7 q save & quit"
|
|
897
1258
|
}, undefined, false, undefined, this)
|
|
@@ -901,12 +1262,12 @@ function Exit({ sessionId, onAction }) {
|
|
|
901
1262
|
}
|
|
902
1263
|
|
|
903
1264
|
// src/tui/screens/Resume.tsx
|
|
904
|
-
import { useState as
|
|
905
|
-
import { Box as
|
|
906
|
-
import { jsxDEV as
|
|
1265
|
+
import { useState as useState5 } from "react";
|
|
1266
|
+
import { Box as Box7, Text as Text8, useInput as useInput4, useTui as useTui3 } from "@orchetron/storm";
|
|
1267
|
+
import { jsxDEV as jsxDEV8 } from "react/jsx-dev-runtime";
|
|
907
1268
|
function Resume({ sessionId, onSelect }) {
|
|
908
1269
|
const { exit } = useTui3();
|
|
909
|
-
const [cursor, setCursor] =
|
|
1270
|
+
const [cursor, setCursor] = useState5(0);
|
|
910
1271
|
const session = getSession(sessionId);
|
|
911
1272
|
const conversations2 = getConversationsBySession(sessionId);
|
|
912
1273
|
const totalOptions = conversations2.length + 1;
|
|
@@ -914,7 +1275,7 @@ function Resume({ sessionId, onSelect }) {
|
|
|
914
1275
|
onSelect(selection);
|
|
915
1276
|
exit();
|
|
916
1277
|
};
|
|
917
|
-
|
|
1278
|
+
useInput4((e) => {
|
|
918
1279
|
if (e.key === "c" && e.ctrl)
|
|
919
1280
|
select({ type: "back" });
|
|
920
1281
|
if (e.key === "up" || e.key === "k") {
|
|
@@ -933,17 +1294,17 @@ function Resume({ sessionId, onSelect }) {
|
|
|
933
1294
|
}
|
|
934
1295
|
});
|
|
935
1296
|
if (!session) {
|
|
936
|
-
return /* @__PURE__ */
|
|
1297
|
+
return /* @__PURE__ */ jsxDEV8(Text8, {
|
|
937
1298
|
color: "red",
|
|
938
1299
|
children: "Session not found"
|
|
939
1300
|
}, undefined, false, undefined, this);
|
|
940
1301
|
}
|
|
941
|
-
return /* @__PURE__ */
|
|
1302
|
+
return /* @__PURE__ */ jsxDEV8(Box7, {
|
|
942
1303
|
flexDirection: "column",
|
|
943
1304
|
padding: 1,
|
|
944
1305
|
gap: 1,
|
|
945
1306
|
children: [
|
|
946
|
-
/* @__PURE__ */
|
|
1307
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
947
1308
|
bold: true,
|
|
948
1309
|
color: "#82AAFF",
|
|
949
1310
|
children: [
|
|
@@ -951,17 +1312,17 @@ function Resume({ sessionId, onSelect }) {
|
|
|
951
1312
|
session.name
|
|
952
1313
|
]
|
|
953
1314
|
}, undefined, true, undefined, this),
|
|
954
|
-
/* @__PURE__ */
|
|
1315
|
+
/* @__PURE__ */ jsxDEV8(Box7, {
|
|
955
1316
|
flexDirection: "column",
|
|
956
1317
|
children: [
|
|
957
|
-
/* @__PURE__ */
|
|
1318
|
+
/* @__PURE__ */ jsxDEV8(Box7, {
|
|
958
1319
|
flexDirection: "row",
|
|
959
1320
|
gap: 1,
|
|
960
1321
|
children: [
|
|
961
|
-
/* @__PURE__ */
|
|
1322
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
962
1323
|
children: cursor === 0 ? "\u276F" : " "
|
|
963
1324
|
}, undefined, false, undefined, this),
|
|
964
|
-
/* @__PURE__ */
|
|
1325
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
965
1326
|
bold: cursor === 0,
|
|
966
1327
|
color: "#34D399",
|
|
967
1328
|
children: "+ New conversation"
|
|
@@ -973,42 +1334,42 @@ function Resume({ sessionId, onSelect }) {
|
|
|
973
1334
|
const isSelected = cursor === idx;
|
|
974
1335
|
const duration = conv.endedAt ? formatDuration(new Date(conv.endedAt).getTime() - new Date(conv.startedAt).getTime()) : "active";
|
|
975
1336
|
const ago = formatAgo(conv.startedAt);
|
|
976
|
-
return /* @__PURE__ */
|
|
1337
|
+
return /* @__PURE__ */ jsxDEV8(Box7, {
|
|
977
1338
|
flexDirection: "row",
|
|
978
1339
|
gap: 1,
|
|
979
1340
|
children: [
|
|
980
|
-
/* @__PURE__ */
|
|
1341
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
981
1342
|
children: isSelected ? "\u276F" : " "
|
|
982
1343
|
}, undefined, false, undefined, this),
|
|
983
|
-
/* @__PURE__ */
|
|
1344
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
984
1345
|
bold: isSelected,
|
|
985
1346
|
dim: conv.discarded,
|
|
986
1347
|
children: conv.id.slice(0, 8)
|
|
987
1348
|
}, undefined, false, undefined, this),
|
|
988
|
-
/* @__PURE__ */
|
|
1349
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
989
1350
|
dim: true,
|
|
990
1351
|
children: ago
|
|
991
1352
|
}, undefined, false, undefined, this),
|
|
992
|
-
/* @__PURE__ */
|
|
1353
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
993
1354
|
dim: true,
|
|
994
1355
|
children: "\xB7"
|
|
995
1356
|
}, undefined, false, undefined, this),
|
|
996
|
-
/* @__PURE__ */
|
|
1357
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
997
1358
|
dim: true,
|
|
998
1359
|
children: [
|
|
999
1360
|
conv.eventCount,
|
|
1000
1361
|
" events"
|
|
1001
1362
|
]
|
|
1002
1363
|
}, undefined, true, undefined, this),
|
|
1003
|
-
/* @__PURE__ */
|
|
1364
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
1004
1365
|
dim: true,
|
|
1005
1366
|
children: "\xB7"
|
|
1006
1367
|
}, undefined, false, undefined, this),
|
|
1007
|
-
/* @__PURE__ */
|
|
1368
|
+
/* @__PURE__ */ jsxDEV8(Text8, {
|
|
1008
1369
|
dim: true,
|
|
1009
1370
|
children: duration
|
|
1010
1371
|
}, undefined, false, undefined, this),
|
|
1011
|
-
conv.discarded && /* @__PURE__ */
|
|
1372
|
+
conv.discarded && /* @__PURE__ */ jsxDEV8(Text8, {
|
|
1012
1373
|
color: "red",
|
|
1013
1374
|
dim: true,
|
|
1014
1375
|
children: "(discarded)"
|
|
@@ -1018,8 +1379,8 @@ function Resume({ sessionId, onSelect }) {
|
|
|
1018
1379
|
})
|
|
1019
1380
|
]
|
|
1020
1381
|
}, undefined, true, undefined, this),
|
|
1021
|
-
/* @__PURE__ */
|
|
1022
|
-
children: /* @__PURE__ */
|
|
1382
|
+
/* @__PURE__ */ jsxDEV8(Box7, {
|
|
1383
|
+
children: /* @__PURE__ */ jsxDEV8(Text8, {
|
|
1023
1384
|
dim: true,
|
|
1024
1385
|
children: "\u2191\u2193 navigate \xB7 enter select \xB7 q back"
|
|
1025
1386
|
}, undefined, false, undefined, this)
|
|
@@ -1029,7 +1390,7 @@ function Resume({ sessionId, onSelect }) {
|
|
|
1029
1390
|
}
|
|
1030
1391
|
|
|
1031
1392
|
// src/tui/run-screen.tsx
|
|
1032
|
-
import { jsxDEV as
|
|
1393
|
+
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
1033
1394
|
var [, , screen, outputPath, ...args] = process.argv;
|
|
1034
1395
|
if (!screen || !outputPath) {
|
|
1035
1396
|
console.error("Usage: run-screen <screen> <outputPath> [args...]");
|
|
@@ -1039,7 +1400,7 @@ var result;
|
|
|
1039
1400
|
switch (screen) {
|
|
1040
1401
|
case "launch": {
|
|
1041
1402
|
let selection = { type: "quit" };
|
|
1042
|
-
const app = render(/* @__PURE__ */
|
|
1403
|
+
const app = render(/* @__PURE__ */ jsxDEV9(Launch, {
|
|
1043
1404
|
onSelect: (s) => {
|
|
1044
1405
|
selection = s;
|
|
1045
1406
|
}
|
|
@@ -1056,7 +1417,7 @@ switch (screen) {
|
|
|
1056
1417
|
process.exit(1);
|
|
1057
1418
|
}
|
|
1058
1419
|
let action = "save";
|
|
1059
|
-
const app = render(/* @__PURE__ */
|
|
1420
|
+
const app = render(/* @__PURE__ */ jsxDEV9(Exit, {
|
|
1060
1421
|
sessionId,
|
|
1061
1422
|
onAction: (a) => {
|
|
1062
1423
|
action = a;
|
|
@@ -1074,7 +1435,7 @@ switch (screen) {
|
|
|
1074
1435
|
process.exit(1);
|
|
1075
1436
|
}
|
|
1076
1437
|
let selection = { type: "back" };
|
|
1077
|
-
const app = render(/* @__PURE__ */
|
|
1438
|
+
const app = render(/* @__PURE__ */ jsxDEV9(Resume, {
|
|
1078
1439
|
sessionId,
|
|
1079
1440
|
onSelect: (s) => {
|
|
1080
1441
|
selection = s;
|