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.
Files changed (2) hide show
  1. package/dist/run-screen.js +507 -146
  2. package/package.json +1 -1
@@ -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 useState2 } from "react";
23
- import { Box as Box4, Text as Text5, useTui } from "@orchetron/storm";
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 Box3, Text as Text3, TextInput, useInput } from "@orchetron/storm";
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] = useState("");
105
- const [cursor, setCursor] = useState(0);
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
- useInput((e) => {
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__ */ jsxDEV3(Box3, {
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__ */ jsxDEV3(Box3, {
412
+ props.mode === "multi" && props.selected.length > 0 && /* @__PURE__ */ jsxDEV4(Box4, {
185
413
  flexDirection: "row",
186
414
  gap: 1,
187
415
  children: [
188
- /* @__PURE__ */ jsxDEV3(Text3, {
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__ */ jsxDEV3(Text3, {
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__ */ jsxDEV3(Box3, {
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__ */ jsxDEV3(TextInput, {
434
+ children: /* @__PURE__ */ jsxDEV4(TextField, {
207
435
  value: filter,
208
436
  onChange: setFilter,
209
437
  onSubmit: handleSubmit,
210
438
  placeholder,
211
- color: "green",
212
- placeholderColor: "gray",
213
- isFocused
439
+ isFocused,
440
+ ghost
214
441
  }, undefined, false, undefined, this)
215
442
  }, undefined, false, undefined, this),
216
- /* @__PURE__ */ jsxDEV3(Box3, {
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__ */ jsxDEV3(Text3, {
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__ */ jsxDEV3(Text3, {
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__ */ jsxDEV3(Box3, {
467
+ return /* @__PURE__ */ jsxDEV4(Box4, {
241
468
  flexDirection: "column",
242
469
  children: [
243
- showDivider && /* @__PURE__ */ jsxDEV3(Text3, {
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__ */ jsxDEV3(Box3, {
474
+ /* @__PURE__ */ jsxDEV4(Box4, {
248
475
  flexDirection: "row",
249
476
  gap: 1,
250
- backgroundColor: isCursor ? "green" : undefined,
251
- children: /* @__PURE__ */ jsxDEV3(Text3, {
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__ */ jsxDEV3(Box3, {
493
+ return /* @__PURE__ */ jsxDEV4(Box4, {
267
494
  flexDirection: "row",
268
- children: /* @__PURE__ */ jsxDEV3(Text3, {
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__ */ jsxDEV3(Box3, {
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__ */ jsxDEV3(Box3, {
511
+ /* @__PURE__ */ jsxDEV4(Box4, {
286
512
  flexDirection: "row",
287
513
  gap: 0,
288
- children: item.display ? item.display : /* @__PURE__ */ jsxDEV3(Text3, {
289
- color: isCursor ? "black" : item.color ?? undefined,
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__ */ jsxDEV3(Box3, {
299
- paddingX: 1,
300
- backgroundColor: isCursor ? "black" : "#3a3a3a",
301
- children: /* @__PURE__ */ jsxDEV3(Text3, {
302
- color: isCursor ? "green" : "white",
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__ */ jsxDEV3(Text3, {
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 Text4 } from "@orchetron/storm";
326
- import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
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__ */ jsxDEV4(Text4, {
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 jsxDEV5, Fragment } from "react/jsx-dev-runtime";
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
- display: /* @__PURE__ */ jsxDEV5(Fragment, {
587
- children: [
588
- /* @__PURE__ */ jsxDEV5(Text5, {
589
- children: " "
590
- }, undefined, false, undefined, this),
591
- /* @__PURE__ */ jsxDEV5(Text5, {
592
- color,
593
- children: "\u25CF "
594
- }, undefined, false, undefined, this),
595
- /* @__PURE__ */ jsxDEV5(Text5, {
596
- color,
597
- dim: disabled,
598
- children: status.padEnd(8)
599
- }, undefined, false, undefined, this),
600
- /* @__PURE__ */ jsxDEV5(Text5, {
601
- children: " "
602
- }, undefined, false, undefined, this),
603
- /* @__PURE__ */ jsxDEV5(Text5, {
604
- dim: disabled,
605
- children: s.session.slug
606
- }, undefined, false, undefined, this)
607
- ]
608
- }, undefined, true, undefined, this)
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] = useState2(null);
621
- const allSessions = useMemo2(() => getAllSessions({ excludeArchived: true }), []);
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) => s.session.status === "paused" || s.session.status === "waiting").sort((a, b) => {
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__ */ jsxDEV5(Box4, {
1004
+ return /* @__PURE__ */ jsxDEV6(Box5, {
685
1005
  flexDirection: "column",
686
1006
  paddingY: 1,
687
1007
  gap: 1,
688
1008
  children: [
689
- /* @__PURE__ */ jsxDEV5(Box4, {
1009
+ /* @__PURE__ */ jsxDEV6(Box5, {
690
1010
  marginX: 1,
691
- children: /* @__PURE__ */ jsxDEV5(Logo, {}, undefined, false, undefined, this)
1011
+ children: /* @__PURE__ */ jsxDEV6(Logo, {}, undefined, false, undefined, this)
692
1012
  }, undefined, false, undefined, this),
693
- /* @__PURE__ */ jsxDEV5(Box4, {
1013
+ /* @__PURE__ */ jsxDEV6(Box5, {
694
1014
  flexDirection: "column",
695
1015
  marginX: 2,
696
1016
  gap: 1,
697
1017
  children: [
698
- /* @__PURE__ */ jsxDEV5(AppDetails, {}, undefined, false, undefined, this),
699
- /* @__PURE__ */ jsxDEV5(Box4, {
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__ */ jsxDEV5(Box4, {
1023
+ /* @__PURE__ */ jsxDEV6(Box5, {
704
1024
  flexDirection: "row",
705
1025
  gap: 1,
706
1026
  children: [
707
- /* @__PURE__ */ jsxDEV5(Text5, {
1027
+ /* @__PURE__ */ jsxDEV6(Text6, {
708
1028
  bold: true,
709
1029
  children: "Sessions"
710
1030
  }, undefined, false, undefined, this),
711
- visibleSessions.length === 0 ? /* @__PURE__ */ jsxDEV5(Text5, {
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__ */ jsxDEV5(Fragment, {
1034
+ }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV6(Fragment, {
715
1035
  children: [
716
- /* @__PURE__ */ jsxDEV5(Text5, {
1036
+ /* @__PURE__ */ jsxDEV6(Text6, {
717
1037
  dim: true,
718
1038
  children: "\xB7"
719
1039
  }, undefined, false, undefined, this),
720
- /* @__PURE__ */ jsxDEV5(Text5, {
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__ */ jsxDEV5(Fragment, {
1047
+ counts.waiting > 0 && /* @__PURE__ */ jsxDEV6(Fragment, {
728
1048
  children: [
729
- /* @__PURE__ */ jsxDEV5(Text5, {
1049
+ /* @__PURE__ */ jsxDEV6(Text6, {
730
1050
  dim: true,
731
1051
  children: "\xB7"
732
1052
  }, undefined, false, undefined, this),
733
- /* @__PURE__ */ jsxDEV5(Text5, {
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__ */ jsxDEV5(Picker, {
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__ */ jsxDEV5(Text5, {
1108
+ error && /* @__PURE__ */ jsxDEV6(Text6, {
756
1109
  color: "red",
757
1110
  children: error
758
1111
  }, undefined, false, undefined, this),
759
- /* @__PURE__ */ jsxDEV5(Text5, {
1112
+ /* @__PURE__ */ jsxDEV6(Text6, {
760
1113
  dim: true,
761
- children: "\u2191\u2193 navigate \xB7 enter continue/create \xB7 esc clear \xB7 ctrl+c quit"
762
- }, undefined, false, undefined, this)
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 useState3 } from "react";
773
- import { Box as Box5, Text as Text6, useInput as useInput2, useTui as useTui2 } from "@orchetron/storm";
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 jsxDEV6 } from "react/jsx-dev-runtime";
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] = useState3(0);
1164
+ const [cursor, setCursor] = useState4(0);
804
1165
  const session = getSession(sessionId);
805
1166
  const conversations2 = session ? getConversationsBySession(session.id) : [];
806
- useInput2((e) => {
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__ */ jsxDEV6(Text6, {
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__ */ jsxDEV6(Box5, {
1190
+ return /* @__PURE__ */ jsxDEV7(Box6, {
830
1191
  flexDirection: "column",
831
1192
  padding: 1,
832
1193
  gap: 1,
833
1194
  children: [
834
- /* @__PURE__ */ jsxDEV6(Text6, {
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__ */ jsxDEV6(Box5, {
1200
+ /* @__PURE__ */ jsxDEV7(Box6, {
840
1201
  flexDirection: "column",
841
1202
  children: [
842
- /* @__PURE__ */ jsxDEV6(Box5, {
1203
+ /* @__PURE__ */ jsxDEV7(Box6, {
843
1204
  flexDirection: "row",
844
1205
  gap: 1,
845
1206
  children: [
846
- /* @__PURE__ */ jsxDEV6(StatusDot, {
1207
+ /* @__PURE__ */ jsxDEV7(StatusDot, {
847
1208
  status: session.status
848
1209
  }, undefined, false, undefined, this),
849
- /* @__PURE__ */ jsxDEV6(Text6, {
1210
+ /* @__PURE__ */ jsxDEV7(Text7, {
850
1211
  bold: true,
851
1212
  children: session.name
852
1213
  }, undefined, false, undefined, this),
853
- duration && /* @__PURE__ */ jsxDEV6(Text6, {
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__ */ jsxDEV6(Text6, {
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__ */ jsxDEV6(Box5, {
1234
+ /* @__PURE__ */ jsxDEV7(Box6, {
874
1235
  flexDirection: "column",
875
- children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsxDEV6(Box5, {
1236
+ children: OPTIONS.map((opt, i) => /* @__PURE__ */ jsxDEV7(Box6, {
876
1237
  flexDirection: "row",
877
1238
  gap: 1,
878
1239
  children: [
879
- /* @__PURE__ */ jsxDEV6(Text6, {
1240
+ /* @__PURE__ */ jsxDEV7(Text7, {
880
1241
  children: i === cursor ? "\u276F" : " "
881
1242
  }, undefined, false, undefined, this),
882
- /* @__PURE__ */ jsxDEV6(Text6, {
1243
+ /* @__PURE__ */ jsxDEV7(Text7, {
883
1244
  bold: i === cursor,
884
1245
  children: opt.label
885
1246
  }, undefined, false, undefined, this),
886
- /* @__PURE__ */ jsxDEV6(Text6, {
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__ */ jsxDEV6(Box5, {
894
- children: /* @__PURE__ */ jsxDEV6(Text6, {
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 useState4 } from "react";
905
- import { Box as Box6, Text as Text7, useInput as useInput3, useTui as useTui3 } from "@orchetron/storm";
906
- import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
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] = useState4(0);
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
- useInput3((e) => {
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__ */ jsxDEV7(Text7, {
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__ */ jsxDEV7(Box6, {
1302
+ return /* @__PURE__ */ jsxDEV8(Box7, {
942
1303
  flexDirection: "column",
943
1304
  padding: 1,
944
1305
  gap: 1,
945
1306
  children: [
946
- /* @__PURE__ */ jsxDEV7(Text7, {
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__ */ jsxDEV7(Box6, {
1315
+ /* @__PURE__ */ jsxDEV8(Box7, {
955
1316
  flexDirection: "column",
956
1317
  children: [
957
- /* @__PURE__ */ jsxDEV7(Box6, {
1318
+ /* @__PURE__ */ jsxDEV8(Box7, {
958
1319
  flexDirection: "row",
959
1320
  gap: 1,
960
1321
  children: [
961
- /* @__PURE__ */ jsxDEV7(Text7, {
1322
+ /* @__PURE__ */ jsxDEV8(Text8, {
962
1323
  children: cursor === 0 ? "\u276F" : " "
963
1324
  }, undefined, false, undefined, this),
964
- /* @__PURE__ */ jsxDEV7(Text7, {
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__ */ jsxDEV7(Box6, {
1337
+ return /* @__PURE__ */ jsxDEV8(Box7, {
977
1338
  flexDirection: "row",
978
1339
  gap: 1,
979
1340
  children: [
980
- /* @__PURE__ */ jsxDEV7(Text7, {
1341
+ /* @__PURE__ */ jsxDEV8(Text8, {
981
1342
  children: isSelected ? "\u276F" : " "
982
1343
  }, undefined, false, undefined, this),
983
- /* @__PURE__ */ jsxDEV7(Text7, {
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__ */ jsxDEV7(Text7, {
1349
+ /* @__PURE__ */ jsxDEV8(Text8, {
989
1350
  dim: true,
990
1351
  children: ago
991
1352
  }, undefined, false, undefined, this),
992
- /* @__PURE__ */ jsxDEV7(Text7, {
1353
+ /* @__PURE__ */ jsxDEV8(Text8, {
993
1354
  dim: true,
994
1355
  children: "\xB7"
995
1356
  }, undefined, false, undefined, this),
996
- /* @__PURE__ */ jsxDEV7(Text7, {
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__ */ jsxDEV7(Text7, {
1364
+ /* @__PURE__ */ jsxDEV8(Text8, {
1004
1365
  dim: true,
1005
1366
  children: "\xB7"
1006
1367
  }, undefined, false, undefined, this),
1007
- /* @__PURE__ */ jsxDEV7(Text7, {
1368
+ /* @__PURE__ */ jsxDEV8(Text8, {
1008
1369
  dim: true,
1009
1370
  children: duration
1010
1371
  }, undefined, false, undefined, this),
1011
- conv.discarded && /* @__PURE__ */ jsxDEV7(Text7, {
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__ */ jsxDEV7(Box6, {
1022
- children: /* @__PURE__ */ jsxDEV7(Text7, {
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 jsxDEV8 } from "react/jsx-dev-runtime";
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__ */ jsxDEV8(Launch, {
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__ */ jsxDEV8(Exit, {
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__ */ jsxDEV8(Resume, {
1438
+ const app = render(/* @__PURE__ */ jsxDEV9(Resume, {
1078
1439
  sessionId,
1079
1440
  onSelect: (s) => {
1080
1441
  selection = s;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bertrand",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },