opencode-sesh 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -10,7 +10,7 @@ import { createElement as _$createElement } from "@opentui/solid";
10
10
  /** @jsxImportSource @opentui/solid */
11
11
  import { Plugin } from "@opencode/plugin/tui";
12
12
  import { createEffect, createMemo, createRoot, createSignal, For, getOwner, on, onCleanup, onMount, runWithOwner, Show } from "solid-js";
13
- import { mkdir, readFile, rename, rmdir, unlink, writeFile } from "node:fs/promises";
13
+ import { lstat, mkdir, readFile, rename, rmdir, unlink, writeFile } from "node:fs/promises";
14
14
  import { existsSync } from "node:fs";
15
15
  import { dirname, join } from "node:path";
16
16
  import { spawn, spawnSync } from "node:child_process";
@@ -185,14 +185,28 @@ const emptyPins = () => ({
185
185
  directories: []
186
186
  });
187
187
  const pinsPath = () => process.env.SESH_PINS_FILE ?? join(process.env.XDG_DATA_HOME ?? join(process.env.HOME ?? "", ".local/share"), "sesh/pins.json");
188
- async function readPins() {
188
+ async function readPins(strict = false) {
189
189
  try {
190
190
  const data = JSON.parse(await readFile(pinsPath(), "utf8"));
191
+ if (!data || !Array.isArray(data.sessions) || !Array.isArray(data.directories) || !data.sessions.every(id => typeof id === "string") || !data.directories.every(dir => typeof dir === "string")) {
192
+ throw new Error("invalid pins file");
193
+ }
191
194
  return {
192
- sessions: Array.isArray(data.sessions) ? data.sessions.filter(id => typeof id === "string") : [],
193
- directories: Array.isArray(data.directories) ? data.directories.filter(dir => typeof dir === "string") : []
195
+ sessions: data.sessions,
196
+ directories: data.directories
194
197
  };
195
- } catch {
198
+ } catch (error) {
199
+ if (strict) {
200
+ if (error.code !== "ENOENT") throw error;
201
+ let absent = false;
202
+ try {
203
+ await lstat(pinsPath());
204
+ } catch (statError) {
205
+ if (statError.code !== "ENOENT") throw statError;
206
+ absent = true;
207
+ }
208
+ if (!absent) throw error;
209
+ }
196
210
  return emptyPins();
197
211
  }
198
212
  }
@@ -210,27 +224,15 @@ async function togglePin(kind, value) {
210
224
  break;
211
225
  } catch (error) {
212
226
  if (error.code !== "EEXIST") throw error;
213
- try {
214
- const owner = Number((await readFile(join(lock, "pid"), "utf8")).trim());
215
- if (Number.isSafeInteger(owner) && owner > 0) {
216
- try {
217
- process.kill(owner, 0);
218
- } catch (check) {
219
- if (check.code === "ESRCH") {
220
- await unlink(join(lock, "pid")).catch(() => {});
221
- await rmdir(lock).catch(() => {});
222
- }
223
- }
224
- }
225
- } catch {}
227
+ // Only the owner removes a lock; stale reclamation can race a new owner.
226
228
  await new Promise(resolve => setTimeout(resolve, 100));
227
229
  }
228
230
  }
229
- if (!locked) throw new Error("pins are busy");
231
+ if (!locked) throw new Error(`pins lock is busy: ${lock}; if it persists, stop all sesh pickers and OpenCode instances before removing this lock directory`);
230
232
  const tmp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}`;
231
233
  try {
232
234
  await writeFile(join(lock, "pid"), `${process.pid}\n`);
233
- const next = await readPins();
235
+ const next = await readPins(true);
234
236
  next[kind] = next[kind].includes(value) ? next[kind].filter(item => item !== value) : [...next[kind], value];
235
237
  await writeFile(tmp, JSON.stringify(next) + "\n", {
236
238
  mode: 0o600
@@ -240,7 +242,7 @@ async function togglePin(kind, value) {
240
242
  } finally {
241
243
  await unlink(tmp).catch(() => {});
242
244
  await unlink(join(lock, "pid")).catch(() => {});
243
- await rmdir(lock);
245
+ await rmdir(lock).catch(() => {});
244
246
  }
245
247
  }
246
248
  function pinnedFirst(entries, pins) {
@@ -355,6 +357,13 @@ function ensureRootMouse(renderer) {
355
357
  const LEFT_BUTTON = 0;
356
358
  const RIGHT_BUTTON = 2;
357
359
  function openInCmuxWorkspace(api, entry) {
360
+ if (!SESSION_ID_PATTERN.test(entry.id)) {
361
+ api.ui.toast({
362
+ message: "Invalid session ID",
363
+ variant: "error"
364
+ });
365
+ return;
366
+ }
358
367
  if (!process.env.CMUX_WORKSPACE_ID) {
359
368
  api.ui.toast({
360
369
  message: "Right-click opens a new workspace only inside cmux",
@@ -542,8 +551,12 @@ function sidebarMarker(current, live) {
542
551
  }
543
552
  const SESSION_PAGE_LIMIT = 200;
544
553
  const SESSION_MAX = 5000;
545
- async function fetchEntries(api) {
554
+ async function fetchEntries(api, active = () => true) {
546
555
  const home = process.env.HOME ?? "";
556
+ if (!active()) return {
557
+ entries: [],
558
+ truncated: false
559
+ };
547
560
  const projectResult = await api.client.project.list();
548
561
  const projects = projectResult?.data ?? projectResult ?? [];
549
562
  const projectName = new Map(projects.map(p => [p.id, p.name?.trim() || shortDir(p.canonical, home)]));
@@ -551,6 +564,7 @@ async function fetchEntries(api) {
551
564
  let cursor;
552
565
  let truncated = false;
553
566
  for (;;) {
567
+ if (!active()) break;
554
568
  const result = await api.client.experimental.session.list({
555
569
  limit: SESSION_PAGE_LIMIT,
556
570
  roots: true,
@@ -593,18 +607,20 @@ const SESSION_ID_PATTERN = /^ses_[A-Za-z0-9]+$/;
593
607
  const TRANSCRIPT_BATCH = 64;
594
608
  const REMOTE_CONCURRENCY = 8;
595
609
  const nextTick = () => new Promise(resolve => setTimeout(resolve, 0));
610
+ let resolvedDbPath;
596
611
  function resolveDbPath() {
597
612
  if (process.env.SESH_DB) return process.env.SESH_DB;
613
+ if (resolvedDbPath) return resolvedDbPath;
598
614
  const home = process.env.HOME ?? "";
599
615
  const dataHome = process.env.XDG_DATA_HOME ?? `${home}/.local/share`;
600
616
  const xdgPath = `${dataHome}/opencode/opencode.db`;
601
- if (existsSync(xdgPath)) return xdgPath;
617
+ if (existsSync(xdgPath)) return resolvedDbPath = xdgPath;
602
618
  try {
603
619
  const result = spawnSync(process.env.SESH_OPENCODE ?? "opencode", ["debug", "paths"], {
604
620
  encoding: "utf8"
605
621
  });
606
622
  const match = result.stdout?.match(/^db\s+(.+)$/m);
607
- if (match) return match[1].trimEnd();
623
+ if (result.status === 0 && match && existsSync(match[1].trimEnd())) return resolvedDbPath = match[1].trimEnd();
608
624
  } catch {}
609
625
  return xdgPath;
610
626
  }
@@ -620,6 +636,75 @@ async function openTranscriptDb() {
620
636
  return undefined;
621
637
  }
622
638
  }
639
+ function createSessionPoll(api, refreshPins) {
640
+ const listeners = new Set();
641
+ let snapshot = {
642
+ entries: [],
643
+ waiting: new Map(),
644
+ failed: false
645
+ };
646
+ let clock;
647
+ let inFlight;
648
+ const active = () => listeners.size > 0;
649
+ const load = () => {
650
+ if (inFlight || !active()) return;
651
+ inFlight = (async () => {
652
+ refreshPins();
653
+ try {
654
+ const result = await fetchEntries(api, active);
655
+ if (!active()) return;
656
+ const previous = new Map(snapshot.entries.map(entry => [entry.id, entry]));
657
+ const entries = result.entries.map(entry => {
658
+ const old = previous.get(entry.id);
659
+ return old && old.title === entry.title && old.dir === entry.dir && old.group === entry.group && old.updated === entry.updated ? old : entry;
660
+ });
661
+ const unchanged = entries.length === snapshot.entries.length && entries.every((entry, i) => entry === snapshot.entries[i]);
662
+ snapshot = {
663
+ ...snapshot,
664
+ entries: unchanged ? snapshot.entries : entries,
665
+ failed: false
666
+ };
667
+ } catch {
668
+ snapshot = {
669
+ ...snapshot,
670
+ failed: true
671
+ };
672
+ }
673
+ if (!active()) return;
674
+ const db = await openTranscriptDb();
675
+ if (db) {
676
+ try {
677
+ if (active()) snapshot = {
678
+ ...snapshot,
679
+ waiting: await queryWaitingIds(db)
680
+ };
681
+ } catch {
682
+ // Keep the previous waiting set when the local store is unavailable.
683
+ } finally {
684
+ db.close();
685
+ }
686
+ }
687
+ for (const listener of listeners) listener(snapshot);
688
+ })().finally(() => {
689
+ inFlight = undefined;
690
+ });
691
+ };
692
+ return listener => {
693
+ listeners.add(listener);
694
+ listener(snapshot);
695
+ if (!clock) {
696
+ load();
697
+ clock = setInterval(load, POLL_MS);
698
+ }
699
+ return () => {
700
+ listeners.delete(listener);
701
+ if (!active() && clock) {
702
+ clearInterval(clock);
703
+ clock = undefined;
704
+ }
705
+ };
706
+ };
707
+ }
623
708
  function costRowsQuery(cutoff, includeLegacy) {
624
709
  const legacy = includeLegacy ? `UNION ALL
625
710
  SELECT s.directory, s.id AS session_id, m.time_created, m.data
@@ -734,7 +819,7 @@ function addTranscript(index, sid, data) {
734
819
  }
735
820
  for (const text of texts) {
736
821
  const base = index.get(sid) ?? "";
737
- index.set(sid, `${base} ${text.toLowerCase()}`.trim());
822
+ index.set(sid, `${base} ${text}`.trim());
738
823
  }
739
824
  } catch {
740
825
  // ignore malformed messages
@@ -744,25 +829,29 @@ function addTranscript(index, sid, data) {
744
829
  // Index titles/directories immediately, then add transcript text progressively
745
830
  // in batches so the render thread can breathe. Covers every entry, not a fixed
746
831
  // newest window; `onProgress` lets the picker show coverage.
747
- async function buildSearchIndex(api, entries, onProgress) {
832
+ async function buildSearchIndex(api, entries, onProgress, active = () => true) {
748
833
  const index = new Map();
749
834
  for (const entry of entries) {
750
- index.set(entry.id, `${entry.title.toLowerCase()} ${entry.dir.toLowerCase()}`);
835
+ index.set(entry.id, `${entry.title} ${entry.dir}`);
751
836
  }
752
837
  const ids = entries.map(entry => entry.id).filter(id => SESSION_ID_PATTERN.test(id));
753
838
  const remaining = new Set(ids);
754
839
  const total = ids.length;
755
840
  let indexed = 0;
756
- const report = complete => onProgress?.({
757
- indexed,
758
- total,
759
- complete
760
- }, index);
841
+ const report = complete => {
842
+ if (active()) onProgress?.({
843
+ indexed,
844
+ total,
845
+ complete
846
+ }, index);
847
+ };
761
848
  report(false);
849
+ if (!active()) return index;
762
850
  const db = await openTranscriptDb();
763
851
  if (db) {
764
852
  try {
765
853
  for (let i = 0; i < ids.length; i += TRANSCRIPT_BATCH) {
854
+ if (!active()) break;
766
855
  const batch = ids.slice(i, i + TRANSCRIPT_BATCH);
767
856
  const placeholders = batch.map(() => "?").join(",");
768
857
  const rows = db.query(`SELECT session_id AS sid, data FROM session_message WHERE session_id IN (${placeholders}) AND type IN ('user', 'assistant') ORDER BY seq`).all(...batch) ?? [];
@@ -778,28 +867,30 @@ async function buildSearchIndex(api, entries, onProgress) {
778
867
  db.close();
779
868
  }
780
869
  }
781
- if (remaining.size > 0) {
870
+ if (active() && remaining.size > 0) {
782
871
  await buildSearchIndexRemote(api, [...remaining], index, () => {
783
872
  indexed += 1;
784
873
  if (indexed % TRANSCRIPT_BATCH === 0) report(false);
785
- });
874
+ }, active);
786
875
  }
787
876
  report(true);
788
877
  return index;
789
878
  }
790
- async function buildSearchIndexRemote(api, ids, index, onEach) {
879
+ async function buildSearchIndexRemote(api, ids, index, onEach, active = () => true) {
791
880
  const home = process.env.HOME ?? "";
792
881
  const cacheDir = process.env.SESH_CACHE_DIR ?? `${process.env.XDG_CACHE_HOME ?? `${home}/.cache`}/sesh`;
793
882
  let cursor = 0;
794
883
  // Bounded concurrency: a fixed worker pool instead of one request per session.
795
884
  const worker = async () => {
796
885
  for (;;) {
886
+ if (!active()) return;
797
887
  const i = cursor++;
798
888
  if (i >= ids.length) return;
799
889
  const id = ids[i];
800
890
  const base = index.get(id) ?? "";
801
891
  try {
802
892
  const raw = await readFile(`${cacheDir}/extractions/${id}.json`, "utf8");
893
+ if (!active()) return;
803
894
  const record = JSON.parse(raw);
804
895
  const fulltext = typeof record?.fulltextLower === "string" ? record.fulltextLower : "";
805
896
  // Extraction caches prefix the transcript with the cached title. The
@@ -809,12 +900,15 @@ async function buildSearchIndexRemote(api, ids, index, onEach) {
809
900
  const transcript = title && fulltext.startsWith(title) ? fulltext.slice(title.length) : fulltext;
810
901
  index.set(id, `${base} ${transcript}`.trim());
811
902
  } catch {
903
+ if (!active()) return;
812
904
  try {
813
905
  const result = await api.client.session.messages({
814
- sessionID: id
906
+ sessionID: id,
907
+ active
815
908
  });
909
+ if (!active()) return;
816
910
  const messages = result.data ?? [];
817
- const text = messages.flatMap(message => message.parts.filter(part => part.type === "text").map(part => part.text)).join(" ").toLowerCase();
911
+ const text = messages.flatMap(message => message.parts.filter(part => part.type === "text").map(part => part.text)).join(" ");
818
912
  index.set(id, `${base} ${text}`.trim());
819
913
  } catch {}
820
914
  }
@@ -826,13 +920,13 @@ async function buildSearchIndexRemote(api, ids, index, onEach) {
826
920
  }, worker));
827
921
  }
828
922
 
829
- // The index is title + directory + text parts, all lowercased. Start looking
923
+ // The index is title + directory + text parts. Start looking
830
924
  // after the metadata so a title match never masquerades as a transcript hit.
831
925
  function transcriptMatchExcerpt(indexed, entry, query) {
832
926
  const needle = query.trim().toLowerCase();
833
927
  if (!indexed || !needle) return undefined;
834
- const transcriptStart = `${entry.title.toLowerCase()} ${entry.dir.toLowerCase()}`.length + 1;
835
- const at = indexed.indexOf(needle, transcriptStart);
928
+ const transcriptStart = `${entry.title} ${entry.dir}`.length + 1;
929
+ const at = indexed.toLowerCase().indexOf(needle, transcriptStart);
836
930
  if (at < 0) return undefined;
837
931
  const start = Math.max(transcriptStart, at - 28);
838
932
  const end = Math.min(indexed.length, Math.max(at + needle.length + 28, start + 90));
@@ -847,7 +941,7 @@ function filterPickerEntries(entries, filters, index, waitingIds, pinnedSessions
847
941
  if (filters.waitingOnly && !waitingIds.has(entry.id)) return false;
848
942
  if (filters.pinnedOnly && !pinned.has(entry.id)) return false;
849
943
  if (!q) return true;
850
- return (index.get(entry.id) ?? `${entry.title} ${entry.dir}`.toLowerCase()).includes(q);
944
+ return (index.get(entry.id) ?? `${entry.title} ${entry.dir}`).toLowerCase().includes(q);
851
945
  });
852
946
  }
853
947
  const TRANSCRIPT_PREVIEW_TURNS = 8;
@@ -1114,44 +1208,11 @@ function SidebarSessions(props) {
1114
1208
  const params = route.params;
1115
1209
  return params && typeof params.sessionID === "string" ? params.sessionID : undefined;
1116
1210
  });
1117
- onMount(() => {
1118
- let alive = true;
1119
- const load = async () => {
1120
- props.refreshPins();
1121
- try {
1122
- const {
1123
- entries: all
1124
- } = await fetchEntries(props.api);
1125
- if (alive) {
1126
- setEntries(all);
1127
- setLoadFailed(false);
1128
- }
1129
- } catch {
1130
- // leave the previous list in place rather than flashing to blank, but
1131
- // say so when there is nothing at all to show
1132
- if (alive && entries().length === 0) setLoadFailed(true);
1133
- }
1134
- try {
1135
- const db = await openTranscriptDb();
1136
- if (db) {
1137
- try {
1138
- const ids = await queryWaitingIds(db);
1139
- if (alive) setWaiting(ids);
1140
- } finally {
1141
- db.close();
1142
- }
1143
- }
1144
- } catch {
1145
- // leave the previous waiting set in place rather than flashing
1146
- }
1147
- };
1148
- void load();
1149
- const clock = setInterval(() => void load(), POLL_MS);
1150
- onCleanup(() => {
1151
- alive = false;
1152
- clearInterval(clock);
1153
- });
1154
- });
1211
+ onMount(() => onCleanup(props.poll(snapshot => {
1212
+ setEntries(snapshot.entries);
1213
+ setLoadFailed(snapshot.failed);
1214
+ setWaiting(snapshot.waiting);
1215
+ })));
1155
1216
  const filteredEntries = createMemo(() => {
1156
1217
  const q = query().trim().toLowerCase();
1157
1218
  const ordered = entries();
@@ -1159,7 +1220,6 @@ function SidebarSessions(props) {
1159
1220
  return ordered.filter(entry => entry.title.toLowerCase().includes(q) || entry.dir.toLowerCase().includes(q));
1160
1221
  });
1161
1222
  const shownEntries = createMemo(() => filteredEntries());
1162
- const remaining = createMemo(() => Math.max(0, filteredEntries().length - shownEntries().length));
1163
1223
  const NEEDS_INPUT_DIR = "__needs_input__";
1164
1224
  const waitingEntries = createMemo(() => {
1165
1225
  const ids = waiting();
@@ -1460,7 +1520,6 @@ function SidebarSessions(props) {
1460
1520
  let disposeSearch;
1461
1521
  let disposeNav;
1462
1522
  let disposeConfirm;
1463
- let insideSearchBox = false;
1464
1523
  createEffect(() => {
1465
1524
  disposeConfirm?.();
1466
1525
  disposeConfirm = undefined;
@@ -1505,10 +1564,6 @@ function SidebarSessions(props) {
1505
1564
  const onRootMouseDown = () => {
1506
1565
  menu.close();
1507
1566
  preview.closeIfOpen();
1508
- if (insideSearchBox) {
1509
- insideSearchBox = false;
1510
- return;
1511
- }
1512
1567
  if (searching()) setSearching(false);
1513
1568
  // A click anywhere outside the sidebar means input is back in the main
1514
1569
  // view: release the nav layer, hover shortcuts and any armed delete so
@@ -1541,12 +1596,12 @@ function SidebarSessions(props) {
1541
1596
  });
1542
1597
  });
1543
1598
  const openSidebarPreview = entry => preview.open(entry);
1599
+ const hoveredEntry = createMemo(() => entries().find(entry => entry.id === hovered()));
1544
1600
  createEffect(() => {
1545
1601
  disposeHoverSpace?.();
1546
1602
  disposeHoverSpace = undefined;
1547
- const id = hovered();
1548
- if (!id) return;
1549
- const entry = entries().find(e => e.id === id);
1603
+ if (navActive()) return;
1604
+ const entry = hoveredEntry();
1550
1605
  if (!entry) return;
1551
1606
  disposeHoverSpace = props.api.keymap.registerLayer({
1552
1607
  mode: "base",
@@ -1670,19 +1725,7 @@ function SidebarSessions(props) {
1670
1725
  cancelDelete();
1671
1726
  setNavActive(false);
1672
1727
  }
1673
- }, ...(pendingDelete() ? [{
1674
- key: "y",
1675
- desc: "Confirm delete",
1676
- preventDefault: true,
1677
- cmd: () => {
1678
- confirmArmed();
1679
- }
1680
- }, {
1681
- key: "n",
1682
- desc: "Cancel delete",
1683
- preventDefault: true,
1684
- cmd: cancelDelete
1685
- }] : [])];
1728
+ }];
1686
1729
  disposeNav = props.api.keymap.registerLayer({
1687
1730
  mode: "base",
1688
1731
  priority: 20,
@@ -1768,12 +1811,12 @@ function SidebarSessions(props) {
1768
1811
  },
1769
1812
  get fallback() {
1770
1813
  return (() => {
1771
- var _el$33 = _$createElement("text");
1772
- _$insert(_el$33, () => loadFailed() ? "Session list unavailable · will retry" : "No sessions yet · option+o to browse");
1773
- _$effect(_$p => _$setProp(_el$33, "style", {
1814
+ var _el$32 = _$createElement("text");
1815
+ _$insert(_el$32, () => loadFailed() ? "Session list unavailable · will retry" : "No sessions yet · option+o to browse");
1816
+ _$effect(_$p => _$setProp(_el$32, "style", {
1774
1817
  fg: theme().textMuted
1775
1818
  }, _$p));
1776
- return _el$33;
1819
+ return _el$32;
1777
1820
  })();
1778
1821
  },
1779
1822
  get children() {
@@ -1788,7 +1831,6 @@ function SidebarSessions(props) {
1788
1831
  // Sidebar-internal: the root handler must not see this click, or
1789
1832
  // it would clear the search this box just activated.
1790
1833
  event.stopPropagation();
1791
- insideSearchBox = true;
1792
1834
  setSearching(true);
1793
1835
  });
1794
1836
  _$setProp(_el$23, "flexGrow", 1);
@@ -1846,34 +1888,34 @@ function SidebarSessions(props) {
1846
1888
  },
1847
1889
  children: row => {
1848
1890
  if (row.kind === "group") return (() => {
1849
- var _el$34 = _$createElement("box"),
1850
- _el$35 = _$createElement("text"),
1851
- _el$36 = _$createElement("span"),
1852
- _el$37 = _$createElement("b"),
1853
- _el$38 = _$createElement("text"),
1854
- _el$39 = _$createTextNode(` (`),
1855
- _el$41 = _$createTextNode(`)`);
1856
- _$insertNode(_el$34, _el$35);
1857
- _$insertNode(_el$34, _el$38);
1858
- _$setProp(_el$34, "flexDirection", "row");
1859
- _$setProp(_el$34, "paddingTop", 1);
1860
- _$setProp(_el$34, "onMouseDown", event => {
1891
+ var _el$33 = _$createElement("box"),
1892
+ _el$34 = _$createElement("text"),
1893
+ _el$35 = _$createElement("span"),
1894
+ _el$36 = _$createElement("b"),
1895
+ _el$37 = _$createElement("text"),
1896
+ _el$38 = _$createTextNode(` (`),
1897
+ _el$40 = _$createTextNode(`)`);
1898
+ _$insertNode(_el$33, _el$34);
1899
+ _$insertNode(_el$33, _el$37);
1900
+ _$setProp(_el$33, "flexDirection", "row");
1901
+ _$setProp(_el$33, "paddingTop", 1);
1902
+ _$setProp(_el$33, "onMouseDown", event => {
1861
1903
  event.stopPropagation();
1862
1904
  if (event.button === RIGHT_BUTTON) return;
1863
1905
  toggleGroup(row.dir);
1864
1906
  });
1865
- _$insertNode(_el$35, _el$36);
1866
- _$insertNode(_el$35, _el$37);
1867
- _$setProp(_el$35, "flexGrow", 1);
1868
- _$setProp(_el$35, "flexShrink", 1);
1869
- _$setProp(_el$35, "wrapMode", "none");
1870
- _$insert(_el$36, () => collapsed()[row.dir] ? "▸ " : "▾ ");
1871
- _$insert(_el$37, () => props.pins().directories.includes(row.dir) ? "★ " : "", null);
1872
- _$insert(_el$37, () => truncate(row.label, SIDEBAR_GROUP_WIDTH - (props.pins().directories.includes(row.dir) ? 2 : 0)), null);
1873
- _$insertNode(_el$38, _el$39);
1874
- _$insertNode(_el$38, _el$41);
1875
- _$setProp(_el$38, "flexShrink", 0);
1876
- _$insert(_el$38, () => row.count, _el$41);
1907
+ _$insertNode(_el$34, _el$35);
1908
+ _$insertNode(_el$34, _el$36);
1909
+ _$setProp(_el$34, "flexGrow", 1);
1910
+ _$setProp(_el$34, "flexShrink", 1);
1911
+ _$setProp(_el$34, "wrapMode", "none");
1912
+ _$insert(_el$35, () => collapsed()[row.dir] ? "▸ " : "▾ ");
1913
+ _$insert(_el$36, () => props.pins().directories.includes(row.dir) ? "★ " : "", null);
1914
+ _$insert(_el$36, () => truncate(row.label, SIDEBAR_GROUP_WIDTH - (props.pins().directories.includes(row.dir) ? 2 : 0)), null);
1915
+ _$insertNode(_el$37, _el$38);
1916
+ _$insertNode(_el$37, _el$40);
1917
+ _$setProp(_el$37, "flexShrink", 0);
1918
+ _$insert(_el$37, () => row.count, _el$40);
1877
1919
  _$effect(_p$ => {
1878
1920
  var _v$15 = {
1879
1921
  fg: theme().textMuted
@@ -1881,29 +1923,29 @@ function SidebarSessions(props) {
1881
1923
  _v$16 = {
1882
1924
  fg: theme().textMuted
1883
1925
  };
1884
- _v$15 !== _p$.e && (_p$.e = _$setProp(_el$36, "style", _v$15, _p$.e));
1885
- _v$16 !== _p$.t && (_p$.t = _$setProp(_el$38, "style", _v$16, _p$.t));
1926
+ _v$15 !== _p$.e && (_p$.e = _$setProp(_el$35, "style", _v$15, _p$.e));
1927
+ _v$16 !== _p$.t && (_p$.t = _$setProp(_el$37, "style", _v$16, _p$.t));
1886
1928
  return _p$;
1887
1929
  }, {
1888
1930
  e: undefined,
1889
1931
  t: undefined
1890
1932
  });
1891
- return _el$34;
1933
+ return _el$33;
1892
1934
  })();
1893
1935
  const marker = createMemo(() => markerOf(row.entry.id));
1894
1936
  return (() => {
1895
- var _el$42 = _$createElement("box"),
1896
- _el$43 = _$createElement("text"),
1937
+ var _el$41 = _$createElement("box"),
1938
+ _el$42 = _$createElement("text"),
1939
+ _el$43 = _$createElement("span"),
1897
1940
  _el$44 = _$createElement("span"),
1898
- _el$45 = _$createElement("span"),
1899
- _el$46 = _$createElement("text");
1900
- _$insertNode(_el$42, _el$43);
1901
- _$insertNode(_el$42, _el$46);
1902
- _$setProp(_el$42, "flexDirection", "row");
1903
- _$setProp(_el$42, "gap", 1);
1904
- _$setProp(_el$42, "paddingLeft", 1);
1905
- _$setProp(_el$42, "paddingRight", 1);
1906
- _$setProp(_el$42, "onMouseOver", () => {
1941
+ _el$45 = _$createElement("text");
1942
+ _$insertNode(_el$41, _el$42);
1943
+ _$insertNode(_el$41, _el$45);
1944
+ _$setProp(_el$41, "flexDirection", "row");
1945
+ _$setProp(_el$41, "gap", 1);
1946
+ _$setProp(_el$41, "paddingLeft", 1);
1947
+ _$setProp(_el$41, "paddingRight", 1);
1948
+ _$setProp(_el$41, "onMouseOver", () => {
1907
1949
  setHovered(row.entry.id);
1908
1950
  // The keyboard layer wins over the hover layer while nav is
1909
1951
  // active. Keep its cursor on the hovered row so Ctrl-S/Ctrl-D
@@ -1913,8 +1955,8 @@ function SidebarSessions(props) {
1913
1955
  if (index >= 0) setCursor(index);
1914
1956
  }
1915
1957
  });
1916
- _$setProp(_el$42, "onMouseOut", () => setHovered(undefined));
1917
- _$setProp(_el$42, "onMouseDown", event => {
1958
+ _$setProp(_el$41, "onMouseOut", () => setHovered(undefined));
1959
+ _$setProp(_el$41, "onMouseDown", event => {
1918
1960
  if (event.button === RIGHT_BUTTON) {
1919
1961
  event.stopPropagation();
1920
1962
  menu.open(row.entry, event.x, event.y);
@@ -1926,15 +1968,15 @@ function SidebarSessions(props) {
1926
1968
  void openSession(row.entry);
1927
1969
  }
1928
1970
  });
1929
- _$insertNode(_el$43, _el$44);
1930
- _$insertNode(_el$43, _el$45);
1931
- _$setProp(_el$43, "flexShrink", 0);
1932
- _$insert(_el$44, () => row.last ? "└" : "├");
1933
- _$insert(_el$45, (() => {
1971
+ _$insertNode(_el$42, _el$43);
1972
+ _$insertNode(_el$42, _el$44);
1973
+ _$setProp(_el$42, "flexShrink", 0);
1974
+ _$insert(_el$43, () => row.last ? "└" : "├");
1975
+ _$insert(_el$44, (() => {
1934
1976
  var _c$3 = _$memo(() => marker() === "current");
1935
1977
  return () => _c$3() ? "●" : _$memo(() => marker() === "running")() ? SIDEBAR_SPINNER[spinFrame()] : isActive(row.entry.id) ? "▸" : "○";
1936
1978
  })());
1937
- _$insert(_el$42, _$createComponent(Highlighted, {
1979
+ _$insert(_el$41, _$createComponent(Highlighted, {
1938
1980
  get text() {
1939
1981
  return `${props.pins().sessions.includes(row.entry.id) ? "★ " : ""}${truncate(row.entry.title, SIDEBAR_TITLE_WIDTH - (props.pins().sessions.includes(row.entry.id) ? 2 : 0))}`;
1940
1982
  },
@@ -1947,9 +1989,9 @@ function SidebarSessions(props) {
1947
1989
  get matchColor() {
1948
1990
  return theme().warning;
1949
1991
  }
1950
- }), _el$46);
1951
- _$setProp(_el$46, "flexShrink", 0);
1952
- _$insert(_el$46, (() => {
1992
+ }), _el$45);
1993
+ _$setProp(_el$45, "flexShrink", 0);
1994
+ _$insert(_el$45, (() => {
1953
1995
  var _c$4 = _$memo(() => !!isPendingDelete(row.entry.id));
1954
1996
  return () => _c$4() ? "option+d again" : ago(row.entry.updated);
1955
1997
  })());
@@ -1964,10 +2006,10 @@ function SidebarSessions(props) {
1964
2006
  _v$20 = {
1965
2007
  fg: isPendingDelete(row.entry.id) ? theme().error : theme().textMuted
1966
2008
  };
1967
- _v$17 !== _p$.e && (_p$.e = _$setProp(_el$42, "backgroundColor", _v$17, _p$.e));
1968
- _v$18 !== _p$.t && (_p$.t = _$setProp(_el$44, "style", _v$18, _p$.t));
1969
- _v$19 !== _p$.a && (_p$.a = _$setProp(_el$45, "style", _v$19, _p$.a));
1970
- _v$20 !== _p$.o && (_p$.o = _$setProp(_el$46, "style", _v$20, _p$.o));
2009
+ _v$17 !== _p$.e && (_p$.e = _$setProp(_el$41, "backgroundColor", _v$17, _p$.e));
2010
+ _v$18 !== _p$.t && (_p$.t = _$setProp(_el$43, "style", _v$18, _p$.t));
2011
+ _v$19 !== _p$.a && (_p$.a = _$setProp(_el$44, "style", _v$19, _p$.a));
2012
+ _v$20 !== _p$.o && (_p$.o = _$setProp(_el$45, "style", _v$20, _p$.o));
1971
2013
  return _p$;
1972
2014
  }, {
1973
2015
  e: undefined,
@@ -1975,49 +2017,37 @@ function SidebarSessions(props) {
1975
2017
  a: undefined,
1976
2018
  o: undefined
1977
2019
  });
1978
- return _el$42;
2020
+ return _el$41;
1979
2021
  })();
1980
2022
  }
1981
2023
  }));
1982
2024
  return _el$26;
1983
2025
  })(), _$createComponent(Show, {
1984
2026
  get when() {
1985
- return remaining() > 0;
2027
+ return _$memo(() => !!query().trim())() && filteredEntries().length === 0;
1986
2028
  },
1987
2029
  get children() {
1988
2030
  var _el$27 = _$createElement("text");
1989
- _$insert(_el$27, () => `… ${remaining()} more · option+o for all`);
2031
+ _$insertNode(_el$27, _$createTextNode(`No title or directory matches · option+o to search transcripts`));
1990
2032
  _$effect(_$p => _$setProp(_el$27, "style", {
1991
2033
  fg: theme().textMuted
1992
2034
  }, _$p));
1993
2035
  return _el$27;
1994
2036
  }
1995
- }), _$createComponent(Show, {
1996
- get when() {
1997
- return _$memo(() => !!query().trim())() && filteredEntries().length === 0;
1998
- },
1999
- get children() {
2000
- var _el$28 = _$createElement("text");
2001
- _$insertNode(_el$28, _$createTextNode(`No title or directory matches · option+o to search transcripts`));
2002
- _$effect(_$p => _$setProp(_el$28, "style", {
2003
- fg: theme().textMuted
2004
- }, _$p));
2005
- return _el$28;
2006
- }
2007
2037
  }), _$createComponent(Show, {
2008
2038
  get when() {
2009
2039
  return navActive();
2010
2040
  },
2011
2041
  get children() {
2012
- var _el$30 = _$createElement("box"),
2013
- _el$31 = _$createElement("text");
2014
- _$insertNode(_el$30, _el$31);
2015
- _$setProp(_el$30, "paddingTop", 1);
2016
- _$insertNode(_el$31, _$createTextNode(`↑↓ move · enter open · option+p preview · option+s/r pin · option+d delete · esc done`));
2017
- _$effect(_$p => _$setProp(_el$31, "style", {
2042
+ var _el$29 = _$createElement("box"),
2043
+ _el$30 = _$createElement("text");
2044
+ _$insertNode(_el$29, _el$30);
2045
+ _$setProp(_el$29, "paddingTop", 1);
2046
+ _$insertNode(_el$30, _$createTextNode(`↑↓ move · enter open · option+p preview · option+s/r pin · option+d delete · esc done`));
2047
+ _$effect(_$p => _$setProp(_el$30, "style", {
2018
2048
  fg: theme().textMuted
2019
2049
  }, _$p));
2020
- return _el$30;
2050
+ return _el$29;
2021
2051
  }
2022
2052
  })];
2023
2053
  }
@@ -2042,45 +2072,45 @@ function SidebarSessions(props) {
2042
2072
  },
2043
2073
  keyed: true,
2044
2074
  children: view => (() => {
2045
- var _el$47 = _$createElement("box");
2046
- _$setProp(_el$47, "position", "absolute");
2047
- _$setProp(_el$47, "flexDirection", "column");
2048
- _$setProp(_el$47, "border", true);
2049
- _$setProp(_el$47, "borderStyle", "rounded");
2050
- _$setProp(_el$47, "paddingLeft", 1);
2051
- _$setProp(_el$47, "paddingRight", 1);
2052
- _$setProp(_el$47, "onMouseDown", event => event.stopPropagation());
2053
- _$setProp(_el$47, "onMouseUp", event => event.stopPropagation());
2054
- _$insert(_el$47, _$createComponent(For, {
2075
+ var _el$46 = _$createElement("box");
2076
+ _$setProp(_el$46, "position", "absolute");
2077
+ _$setProp(_el$46, "flexDirection", "column");
2078
+ _$setProp(_el$46, "border", true);
2079
+ _$setProp(_el$46, "borderStyle", "rounded");
2080
+ _$setProp(_el$46, "paddingLeft", 1);
2081
+ _$setProp(_el$46, "paddingRight", 1);
2082
+ _$setProp(_el$46, "onMouseDown", event => event.stopPropagation());
2083
+ _$setProp(_el$46, "onMouseUp", event => event.stopPropagation());
2084
+ _$insert(_el$46, _$createComponent(For, {
2055
2085
  get each() {
2056
2086
  return view.state.items;
2057
2087
  },
2058
2088
  children: (item, index) => (() => {
2059
- var _el$48 = _$createElement("box"),
2060
- _el$49 = _$createElement("text");
2061
- _$insertNode(_el$48, _el$49);
2062
- _$setProp(_el$48, "height", 1);
2063
- _$setProp(_el$48, "onMouseOver", () => menu.select(index()));
2064
- _$setProp(_el$48, "onMouseDown", event => event.stopPropagation());
2065
- _$setProp(_el$48, "onMouseUp", event => {
2089
+ var _el$47 = _$createElement("box"),
2090
+ _el$48 = _$createElement("text");
2091
+ _$insertNode(_el$47, _el$48);
2092
+ _$setProp(_el$47, "height", 1);
2093
+ _$setProp(_el$47, "onMouseOver", () => menu.select(index()));
2094
+ _$setProp(_el$47, "onMouseDown", event => event.stopPropagation());
2095
+ _$setProp(_el$47, "onMouseUp", event => {
2066
2096
  event.stopPropagation();
2067
2097
  menu.click(index(), event.button);
2068
2098
  });
2069
- _$setProp(_el$49, "wrapMode", "none");
2070
- _$insert(_el$49, () => item.label);
2099
+ _$setProp(_el$48, "wrapMode", "none");
2100
+ _$insert(_el$48, () => item.label);
2071
2101
  _$effect(_p$ => {
2072
2102
  var _v$27 = view.state.index === index() ? theme().backgroundElement : RGBA.fromInts(0, 0, 0, 0),
2073
2103
  _v$28 = {
2074
2104
  fg: item.id === "delete" || item.id === "confirm" ? theme().error : view.state.index === index() ? theme().text : theme().textMuted
2075
2105
  };
2076
- _v$27 !== _p$.e && (_p$.e = _$setProp(_el$48, "backgroundColor", _v$27, _p$.e));
2077
- _v$28 !== _p$.t && (_p$.t = _$setProp(_el$49, "style", _v$28, _p$.t));
2106
+ _v$27 !== _p$.e && (_p$.e = _$setProp(_el$47, "backgroundColor", _v$27, _p$.e));
2107
+ _v$28 !== _p$.t && (_p$.t = _$setProp(_el$48, "style", _v$28, _p$.t));
2078
2108
  return _p$;
2079
2109
  }, {
2080
2110
  e: undefined,
2081
2111
  t: undefined
2082
2112
  });
2083
- return _el$48;
2113
+ return _el$47;
2084
2114
  })()
2085
2115
  }));
2086
2116
  _$effect(_p$ => {
@@ -2090,12 +2120,12 @@ function SidebarSessions(props) {
2090
2120
  _v$24 = view.box.height,
2091
2121
  _v$25 = theme().borderActive,
2092
2122
  _v$26 = theme().backgroundPanel;
2093
- _v$21 !== _p$.e && (_p$.e = _$setProp(_el$47, "left", _v$21, _p$.e));
2094
- _v$22 !== _p$.t && (_p$.t = _$setProp(_el$47, "top", _v$22, _p$.t));
2095
- _v$23 !== _p$.a && (_p$.a = _$setProp(_el$47, "width", _v$23, _p$.a));
2096
- _v$24 !== _p$.o && (_p$.o = _$setProp(_el$47, "height", _v$24, _p$.o));
2097
- _v$25 !== _p$.i && (_p$.i = _$setProp(_el$47, "borderColor", _v$25, _p$.i));
2098
- _v$26 !== _p$.n && (_p$.n = _$setProp(_el$47, "backgroundColor", _v$26, _p$.n));
2123
+ _v$21 !== _p$.e && (_p$.e = _$setProp(_el$46, "left", _v$21, _p$.e));
2124
+ _v$22 !== _p$.t && (_p$.t = _$setProp(_el$46, "top", _v$22, _p$.t));
2125
+ _v$23 !== _p$.a && (_p$.a = _$setProp(_el$46, "width", _v$23, _p$.a));
2126
+ _v$24 !== _p$.o && (_p$.o = _$setProp(_el$46, "height", _v$24, _p$.o));
2127
+ _v$25 !== _p$.i && (_p$.i = _$setProp(_el$46, "borderColor", _v$25, _p$.i));
2128
+ _v$26 !== _p$.n && (_p$.n = _$setProp(_el$46, "backgroundColor", _v$26, _p$.n));
2099
2129
  return _p$;
2100
2130
  }, {
2101
2131
  e: undefined,
@@ -2105,7 +2135,7 @@ function SidebarSessions(props) {
2105
2135
  i: undefined,
2106
2136
  n: undefined
2107
2137
  });
2108
- return _el$47;
2138
+ return _el$46;
2109
2139
  })()
2110
2140
  });
2111
2141
  }
@@ -2148,7 +2178,6 @@ function HomeSessions(props) {
2148
2178
  const preview = createTranscriptPreview(props.api);
2149
2179
  let disposeHoverSpace;
2150
2180
  let disposeSearch;
2151
- let insideSearchBox = false;
2152
2181
  const cancelDelete = () => {
2153
2182
  if (confirmTimer) clearTimeout(confirmTimer);
2154
2183
  confirmTimer = undefined;
@@ -2255,11 +2284,9 @@ function HomeSessions(props) {
2255
2284
  });
2256
2285
  const onRootMouseDown = () => {
2257
2286
  preview.closeIfOpen();
2258
- if (insideSearchBox) {
2259
- insideSearchBox = false;
2260
- return;
2261
- }
2262
2287
  if (searching()) setSearching(false);
2288
+ cancelDelete();
2289
+ setHovered(undefined);
2263
2290
  };
2264
2291
 
2265
2292
  // A modal dialog owns input while open: yield this list's keyboard captures
@@ -2289,12 +2316,11 @@ function HomeSessions(props) {
2289
2316
  bindings: searchBindings(appendQuery, () => setSearching(false))
2290
2317
  });
2291
2318
  });
2319
+ const hoveredEntry = createMemo(() => entries().find(entry => entry.id === hovered()));
2292
2320
  createEffect(() => {
2293
2321
  disposeHoverSpace?.();
2294
2322
  disposeHoverSpace = undefined;
2295
- const id = hovered();
2296
- if (!id) return;
2297
- const entry = entries().find(e => e.id === id);
2323
+ const entry = hoveredEntry();
2298
2324
  if (!entry) return;
2299
2325
  disposeHoverSpace = props.api.keymap.registerLayer({
2300
2326
  mode: "base",
@@ -2330,62 +2356,43 @@ function HomeSessions(props) {
2330
2356
  disposeConfirm?.();
2331
2357
  if (confirmTimer) clearTimeout(confirmTimer);
2332
2358
  });
2333
- onMount(() => {
2334
- let alive = true;
2335
- const load = async () => {
2336
- props.refreshPins();
2337
- try {
2338
- const {
2339
- entries: all
2340
- } = await fetchEntries(props.api);
2341
- if (alive) {
2342
- setEntries(all);
2343
- setLoadFailed(false);
2344
- }
2345
- } catch {
2346
- if (alive && entries().length === 0) setLoadFailed(true);
2347
- }
2348
- };
2349
- void load();
2350
- const clock = setInterval(() => void load(), POLL_MS);
2351
- onCleanup(() => {
2352
- alive = false;
2353
- clearInterval(clock);
2354
- });
2355
- });
2359
+ onMount(() => onCleanup(props.poll(snapshot => {
2360
+ setEntries(snapshot.entries);
2361
+ setLoadFailed(snapshot.failed);
2362
+ })));
2356
2363
  const visible = createMemo(() => {
2357
2364
  const q = query().trim().toLowerCase();
2358
2365
  const list = q ? entries().filter(entry => entry.title.toLowerCase().includes(q) || entry.dir.toLowerCase().includes(q)) : entries();
2359
2366
  return pinnedFirst(list, props.pins()).slice(0, HOME_SESSION_LIMIT);
2360
2367
  });
2361
2368
  return (() => {
2362
- var _el$50 = _$createElement("box"),
2363
- _el$51 = _$createElement("box");
2364
- _$insertNode(_el$50, _el$51);
2369
+ var _el$49 = _$createElement("box"),
2370
+ _el$50 = _$createElement("box");
2371
+ _$insertNode(_el$49, _el$50);
2372
+ _$setProp(_el$49, "width", "100%");
2373
+ _$setProp(_el$49, "alignItems", "center");
2374
+ _$setProp(_el$50, "flexDirection", "column");
2365
2375
  _$setProp(_el$50, "width", "100%");
2366
- _$setProp(_el$50, "alignItems", "center");
2367
- _$setProp(_el$51, "flexDirection", "column");
2368
- _$setProp(_el$51, "width", "100%");
2369
- _$setProp(_el$51, "maxWidth", 72);
2370
- _$setProp(_el$51, "paddingLeft", 1);
2371
- _$setProp(_el$51, "paddingRight", 1);
2372
- _$setProp(_el$51, "paddingTop", 1);
2373
- _$setProp(_el$51, "gap", 1);
2374
- _$insert(_el$51, _$createComponent(Show, {
2376
+ _$setProp(_el$50, "maxWidth", 72);
2377
+ _$setProp(_el$50, "paddingLeft", 1);
2378
+ _$setProp(_el$50, "paddingRight", 1);
2379
+ _$setProp(_el$50, "paddingTop", 1);
2380
+ _$setProp(_el$50, "gap", 1);
2381
+ _$insert(_el$50, _$createComponent(Show, {
2375
2382
  get when() {
2376
2383
  return entries().length > 0;
2377
2384
  },
2378
2385
  get fallback() {
2379
2386
  return (() => {
2380
- var _el$65 = _$createElement("box"),
2381
- _el$66 = _$createElement("text"),
2382
- _el$68 = _$createElement("text");
2383
- _$insertNode(_el$65, _el$66);
2384
- _$insertNode(_el$65, _el$68);
2385
- _$setProp(_el$65, "flexDirection", "row");
2386
- _$setProp(_el$65, "gap", 1);
2387
- _$insertNode(_el$66, _$createTextNode(`Recent sessions`));
2388
- _$insert(_el$68, () => loadFailed() ? "· list unavailable, will retry" : "· none yet, option+o to browse");
2387
+ var _el$64 = _$createElement("box"),
2388
+ _el$65 = _$createElement("text"),
2389
+ _el$67 = _$createElement("text");
2390
+ _$insertNode(_el$64, _el$65);
2391
+ _$insertNode(_el$64, _el$67);
2392
+ _$setProp(_el$64, "flexDirection", "row");
2393
+ _$setProp(_el$64, "gap", 1);
2394
+ _$insertNode(_el$65, _$createTextNode(`Recent sessions`));
2395
+ _$insert(_el$67, () => loadFailed() ? "· list unavailable, will retry" : "· none yet, option+o to browse");
2389
2396
  _$effect(_p$ => {
2390
2397
  var _v$33 = {
2391
2398
  fg: theme().textMuted
@@ -2393,66 +2400,66 @@ function HomeSessions(props) {
2393
2400
  _v$34 = {
2394
2401
  fg: theme().textMuted
2395
2402
  };
2396
- _v$33 !== _p$.e && (_p$.e = _$setProp(_el$66, "style", _v$33, _p$.e));
2397
- _v$34 !== _p$.t && (_p$.t = _$setProp(_el$68, "style", _v$34, _p$.t));
2403
+ _v$33 !== _p$.e && (_p$.e = _$setProp(_el$65, "style", _v$33, _p$.e));
2404
+ _v$34 !== _p$.t && (_p$.t = _$setProp(_el$67, "style", _v$34, _p$.t));
2398
2405
  return _p$;
2399
2406
  }, {
2400
2407
  e: undefined,
2401
2408
  t: undefined
2402
2409
  });
2403
- return _el$65;
2410
+ return _el$64;
2404
2411
  })();
2405
2412
  },
2406
2413
  get children() {
2407
2414
  return [(() => {
2408
- var _el$52 = _$createElement("box"),
2409
- _el$53 = _$createElement("box"),
2410
- _el$54 = _$createElement("text"),
2411
- _el$56 = _$createElement("text"),
2415
+ var _el$51 = _$createElement("box"),
2416
+ _el$52 = _$createElement("box"),
2417
+ _el$53 = _$createElement("text"),
2418
+ _el$55 = _$createElement("text"),
2419
+ _el$57 = _$createElement("box"),
2412
2420
  _el$58 = _$createElement("box"),
2413
- _el$59 = _$createElement("box"),
2414
- _el$60 = _$createElement("text");
2421
+ _el$59 = _$createElement("text");
2422
+ _$insertNode(_el$51, _el$52);
2423
+ _$insertNode(_el$51, _el$57);
2424
+ _$setProp(_el$51, "flexDirection", "row");
2425
+ _$setProp(_el$51, "justifyContent", "space-between");
2426
+ _$setProp(_el$51, "gap", 2);
2415
2427
  _$insertNode(_el$52, _el$53);
2416
- _$insertNode(_el$52, _el$58);
2428
+ _$insertNode(_el$52, _el$55);
2417
2429
  _$setProp(_el$52, "flexDirection", "row");
2418
- _$setProp(_el$52, "justifyContent", "space-between");
2419
- _$setProp(_el$52, "gap", 2);
2420
- _$insertNode(_el$53, _el$54);
2421
- _$insertNode(_el$53, _el$56);
2422
- _$setProp(_el$53, "flexDirection", "row");
2423
- _$setProp(_el$53, "gap", 1);
2424
- _$insertNode(_el$54, _$createTextNode(`Recent sessions`));
2425
- _$insertNode(_el$56, _$createTextNode(`· option+o for all`));
2426
- _$insertNode(_el$58, _el$59);
2427
- _$setProp(_el$58, "flexDirection", "row");
2428
- _$setProp(_el$58, "gap", 1);
2429
- _$setProp(_el$58, "paddingLeft", 1);
2430
- _$setProp(_el$58, "paddingRight", 1);
2431
- _$setProp(_el$58, "onMouseDown", () => {
2432
- insideSearchBox = true;
2430
+ _$setProp(_el$52, "gap", 1);
2431
+ _$insertNode(_el$53, _$createTextNode(`Recent sessions`));
2432
+ _$insertNode(_el$55, _$createTextNode(`· option+o for all`));
2433
+ _$insertNode(_el$57, _el$58);
2434
+ _$setProp(_el$57, "flexDirection", "row");
2435
+ _$setProp(_el$57, "gap", 1);
2436
+ _$setProp(_el$57, "paddingLeft", 1);
2437
+ _$setProp(_el$57, "paddingRight", 1);
2438
+ _$setProp(_el$57, "onMouseDown", event => {
2439
+ event.stopPropagation();
2433
2440
  setSearching(true);
2434
2441
  });
2435
- _$insertNode(_el$59, _el$60);
2436
- _$setProp(_el$59, "width", 24);
2437
- _$setProp(_el$60, "flexGrow", 1);
2438
- _$setProp(_el$60, "flexShrink", 1);
2439
- _$setProp(_el$60, "overflow", "hidden");
2440
- _$setProp(_el$60, "wrapMode", "none");
2441
- _$insert(_el$60, () => query() || (searching() ? "" : "search…"), null);
2442
- _$insert(_el$60, () => searching() ? "▏" : "", null);
2443
- _$insert(_el$58, _$createComponent(Show, {
2442
+ _$insertNode(_el$58, _el$59);
2443
+ _$setProp(_el$58, "width", 24);
2444
+ _$setProp(_el$59, "flexGrow", 1);
2445
+ _$setProp(_el$59, "flexShrink", 1);
2446
+ _$setProp(_el$59, "overflow", "hidden");
2447
+ _$setProp(_el$59, "wrapMode", "none");
2448
+ _$insert(_el$59, () => query() || (searching() ? "" : "search…"), null);
2449
+ _$insert(_el$59, () => searching() ? "▏" : "", null);
2450
+ _$insert(_el$57, _$createComponent(Show, {
2444
2451
  get when() {
2445
2452
  return query();
2446
2453
  },
2447
2454
  get children() {
2448
- var _el$61 = _$createElement("text");
2449
- _$insertNode(_el$61, _$createTextNode(`✕`));
2450
- _$setProp(_el$61, "flexShrink", 0);
2451
- _$setProp(_el$61, "onMouseDown", () => setQuery(""));
2452
- _$effect(_$p => _$setProp(_el$61, "style", {
2455
+ var _el$60 = _$createElement("text");
2456
+ _$insertNode(_el$60, _$createTextNode(`✕`));
2457
+ _$setProp(_el$60, "flexShrink", 0);
2458
+ _$setProp(_el$60, "onMouseDown", () => setQuery(""));
2459
+ _$effect(_$p => _$setProp(_el$60, "style", {
2453
2460
  fg: theme().textMuted
2454
2461
  }, _$p));
2455
- return _el$61;
2462
+ return _el$60;
2456
2463
  }
2457
2464
  }), null);
2458
2465
  _$effect(_p$ => {
@@ -2466,10 +2473,10 @@ function HomeSessions(props) {
2466
2473
  _v$32 = {
2467
2474
  fg: query() ? theme().text : theme().textMuted
2468
2475
  };
2469
- _v$29 !== _p$.e && (_p$.e = _$setProp(_el$54, "style", _v$29, _p$.e));
2470
- _v$30 !== _p$.t && (_p$.t = _$setProp(_el$56, "style", _v$30, _p$.t));
2471
- _v$31 !== _p$.a && (_p$.a = _$setProp(_el$58, "backgroundColor", _v$31, _p$.a));
2472
- _v$32 !== _p$.o && (_p$.o = _$setProp(_el$60, "style", _v$32, _p$.o));
2476
+ _v$29 !== _p$.e && (_p$.e = _$setProp(_el$53, "style", _v$29, _p$.e));
2477
+ _v$30 !== _p$.t && (_p$.t = _$setProp(_el$55, "style", _v$30, _p$.t));
2478
+ _v$31 !== _p$.a && (_p$.a = _$setProp(_el$57, "backgroundColor", _v$31, _p$.a));
2479
+ _v$32 !== _p$.o && (_p$.o = _$setProp(_el$59, "style", _v$32, _p$.o));
2473
2480
  return _p$;
2474
2481
  }, {
2475
2482
  e: undefined,
@@ -2477,27 +2484,27 @@ function HomeSessions(props) {
2477
2484
  a: undefined,
2478
2485
  o: undefined
2479
2486
  });
2480
- return _el$52;
2487
+ return _el$51;
2481
2488
  })(), _$createComponent(For, {
2482
2489
  get each() {
2483
2490
  return visible();
2484
2491
  },
2485
2492
  children: entry => (() => {
2486
- var _el$69 = _$createElement("box"),
2487
- _el$70 = _$createElement("text"),
2488
- _el$72 = _$createElement("text");
2489
- _$insertNode(_el$69, _el$70);
2490
- _$insertNode(_el$69, _el$72);
2491
- _$setProp(_el$69, "flexDirection", "row");
2492
- _$setProp(_el$69, "gap", 1);
2493
- _$setProp(_el$69, "onMouseOver", () => setHovered(entry.id));
2494
- _$setProp(_el$69, "onMouseOut", () => setHovered(undefined));
2495
- _$setProp(_el$69, "onMouseDown", event => event.button === RIGHT_BUTTON ? openInCmuxWorkspace(props.api, entry) : props.api.route.navigate("session", {
2493
+ var _el$68 = _$createElement("box"),
2494
+ _el$69 = _$createElement("text"),
2495
+ _el$71 = _$createElement("text");
2496
+ _$insertNode(_el$68, _el$69);
2497
+ _$insertNode(_el$68, _el$71);
2498
+ _$setProp(_el$68, "flexDirection", "row");
2499
+ _$setProp(_el$68, "gap", 1);
2500
+ _$setProp(_el$68, "onMouseOver", () => setHovered(entry.id));
2501
+ _$setProp(_el$68, "onMouseOut", () => setHovered(undefined));
2502
+ _$setProp(_el$68, "onMouseDown", event => event.button === RIGHT_BUTTON ? openInCmuxWorkspace(props.api, entry) : props.api.route.navigate("session", {
2496
2503
  sessionID: entry.id
2497
2504
  }));
2498
- _$insertNode(_el$70, _$createTextNode(`○`));
2499
- _$setProp(_el$70, "flexShrink", 0);
2500
- _$insert(_el$69, _$createComponent(Highlighted, {
2505
+ _$insertNode(_el$69, _$createTextNode(`○`));
2506
+ _$setProp(_el$69, "flexShrink", 0);
2507
+ _$insert(_el$68, _$createComponent(Highlighted, {
2501
2508
  get text() {
2502
2509
  return `${props.pins().sessions.includes(entry.id) ? "★ " : ""}${truncate(entry.title, HOME_TITLE_WIDTH - (props.pins().sessions.includes(entry.id) ? 2 : 0))}`;
2503
2510
  },
@@ -2510,9 +2517,9 @@ function HomeSessions(props) {
2510
2517
  get matchColor() {
2511
2518
  return theme().warning;
2512
2519
  }
2513
- }), _el$72);
2514
- _$setProp(_el$72, "flexShrink", 0);
2515
- _$insert(_el$72, (() => {
2520
+ }), _el$71);
2521
+ _$setProp(_el$71, "flexShrink", 0);
2522
+ _$insert(_el$71, (() => {
2516
2523
  var _c$5 = _$memo(() => pendingDelete() === entry.id);
2517
2524
  return () => _c$5() ? "option+d again" : `${props.pins().directories.includes(entry.dir) ? "★ " : ""}${prettyDir(entry.dir, home)} · ${ago(entry.updated)}`;
2518
2525
  })());
@@ -2524,33 +2531,33 @@ function HomeSessions(props) {
2524
2531
  _v$37 = {
2525
2532
  fg: pendingDelete() === entry.id ? theme().error : theme().textMuted
2526
2533
  };
2527
- _v$35 !== _p$.e && (_p$.e = _$setProp(_el$69, "backgroundColor", _v$35, _p$.e));
2528
- _v$36 !== _p$.t && (_p$.t = _$setProp(_el$70, "style", _v$36, _p$.t));
2529
- _v$37 !== _p$.a && (_p$.a = _$setProp(_el$72, "style", _v$37, _p$.a));
2534
+ _v$35 !== _p$.e && (_p$.e = _$setProp(_el$68, "backgroundColor", _v$35, _p$.e));
2535
+ _v$36 !== _p$.t && (_p$.t = _$setProp(_el$69, "style", _v$36, _p$.t));
2536
+ _v$37 !== _p$.a && (_p$.a = _$setProp(_el$71, "style", _v$37, _p$.a));
2530
2537
  return _p$;
2531
2538
  }, {
2532
2539
  e: undefined,
2533
2540
  t: undefined,
2534
2541
  a: undefined
2535
2542
  });
2536
- return _el$69;
2543
+ return _el$68;
2537
2544
  })()
2538
2545
  }), _$createComponent(Show, {
2539
2546
  get when() {
2540
2547
  return visible().length === 0;
2541
2548
  },
2542
2549
  get children() {
2543
- var _el$63 = _$createElement("text");
2544
- _$insertNode(_el$63, _$createTextNode(`No title or directory matches · option+o to search transcripts`));
2545
- _$effect(_$p => _$setProp(_el$63, "style", {
2550
+ var _el$62 = _$createElement("text");
2551
+ _$insertNode(_el$62, _$createTextNode(`No title or directory matches · option+o to search transcripts`));
2552
+ _$effect(_$p => _$setProp(_el$62, "style", {
2546
2553
  fg: theme().textMuted
2547
2554
  }, _$p));
2548
- return _el$63;
2555
+ return _el$62;
2549
2556
  }
2550
2557
  })];
2551
2558
  }
2552
2559
  }));
2553
- return _el$50;
2560
+ return _el$49;
2554
2561
  })();
2555
2562
  }
2556
2563
  const tui = async api => {
@@ -2570,6 +2577,7 @@ const tui = async api => {
2570
2577
  });
2571
2578
  };
2572
2579
  refreshPins();
2580
+ const poll = createSessionPoll(api, refreshPins);
2573
2581
  const onTogglePin = (kind, value) => {
2574
2582
  if (!value) return;
2575
2583
  pinVersion += 1;
@@ -2592,7 +2600,7 @@ const tui = async api => {
2592
2600
  api: api,
2593
2601
  pins: pins,
2594
2602
  onTogglePin: onTogglePin,
2595
- refreshPins: refreshPins
2603
+ poll: poll
2596
2604
  });
2597
2605
  },
2598
2606
  home_bottom() {
@@ -2600,7 +2608,7 @@ const tui = async api => {
2600
2608
  api: api,
2601
2609
  pins: pins,
2602
2610
  onTogglePin: onTogglePin,
2603
- refreshPins: refreshPins
2611
+ poll: poll
2604
2612
  });
2605
2613
  }
2606
2614
  }
@@ -2671,7 +2679,7 @@ const tui = async api => {
2671
2679
  // Publish a fresh snapshot: the indexing workers mutate their own map,
2672
2680
  // while Solid needs a new reference to update search results mid-scan.
2673
2681
  setSearchIndex(new Map(index));
2674
- });
2682
+ }, () => alive);
2675
2683
  const orderedEntries = createMemo(() => pinnedFirst(allEntries(), pins()));
2676
2684
  const currentProject = () => {
2677
2685
  const route = api.route.current;
@@ -2826,9 +2834,12 @@ const tui = async api => {
2826
2834
 
2827
2835
  // Match OpenTUI's scrollbox: honor every wheel event's delta. The viewport
2828
2836
  // stays independent of selection, so fast scrolling cannot recenter on hover.
2837
+ let scrollRemainder = 0;
2829
2838
  const scrollPicker = scroll => {
2830
2839
  if (showPreview() || !scroll || scroll.direction !== "up" && scroll.direction !== "down") return;
2831
- const amount = Math.trunc(scroll.delta) * (scroll.direction === "down" ? 1 : -1);
2840
+ scrollRemainder += scroll.delta * (scroll.direction === "down" ? 1 : -1);
2841
+ const amount = Math.trunc(scrollRemainder);
2842
+ scrollRemainder -= amount;
2832
2843
  setViewportStart(start => Math.max(0, Math.min(maxViewportStart(), start + amount)));
2833
2844
  };
2834
2845
 
@@ -3109,64 +3120,64 @@ const tui = async api => {
3109
3120
  if (previewTimer) clearTimeout(previewTimer);
3110
3121
  };
3111
3122
  api.ui.dialog.replace(() => (() => {
3112
- var _el$73 = _$createElement("box"),
3123
+ var _el$72 = _$createElement("box"),
3124
+ _el$73 = _$createElement("box"),
3113
3125
  _el$74 = _$createElement("box"),
3114
- _el$75 = _$createElement("box"),
3115
- _el$76 = _$createElement("text"),
3116
- _el$77 = _$createTextNode(`Sessions `),
3117
- _el$78 = _$createElement("span"),
3118
- _el$79 = _$createTextNode(`(`),
3119
- _el$80 = _$createTextNode(`)`),
3120
- _el$81 = _$createElement("text"),
3121
- _el$83 = _$createElement("box"),
3122
- _el$84 = _$createElement("input"),
3123
- _el$87 = _$createElement("box"),
3126
+ _el$75 = _$createElement("text"),
3127
+ _el$76 = _$createTextNode(`Sessions `),
3128
+ _el$77 = _$createElement("span"),
3129
+ _el$78 = _$createTextNode(`(`),
3130
+ _el$79 = _$createTextNode(`)`),
3131
+ _el$80 = _$createElement("text"),
3132
+ _el$82 = _$createElement("box"),
3133
+ _el$83 = _$createElement("input"),
3134
+ _el$86 = _$createElement("box"),
3135
+ _el$87 = _$createElement("text"),
3124
3136
  _el$88 = _$createElement("text"),
3125
3137
  _el$89 = _$createElement("text"),
3126
- _el$90 = _$createElement("text"),
3127
- _el$91 = _$createElement("box"),
3128
- _el$94 = _$createElement("box"),
3129
- _el$95 = _$createElement("text");
3138
+ _el$90 = _$createElement("box"),
3139
+ _el$93 = _$createElement("box"),
3140
+ _el$94 = _$createElement("text");
3141
+ _$insertNode(_el$72, _el$73);
3142
+ _$insertNode(_el$72, _el$90);
3143
+ _$insertNode(_el$72, _el$93);
3144
+ _$setProp(_el$72, "flexDirection", "column");
3145
+ _$setProp(_el$72, "paddingTop", 1);
3146
+ _$setProp(_el$72, "paddingBottom", 1);
3147
+ _$setProp(_el$72, "gap", 1);
3130
3148
  _$insertNode(_el$73, _el$74);
3131
- _$insertNode(_el$73, _el$91);
3132
- _$insertNode(_el$73, _el$94);
3133
- _$setProp(_el$73, "flexDirection", "column");
3134
- _$setProp(_el$73, "paddingTop", 1);
3135
- _$setProp(_el$73, "paddingBottom", 1);
3136
- _$setProp(_el$73, "gap", 1);
3149
+ _$insertNode(_el$73, _el$82);
3150
+ _$insertNode(_el$73, _el$86);
3151
+ _$setProp(_el$73, "paddingLeft", 4);
3152
+ _$setProp(_el$73, "paddingRight", 4);
3137
3153
  _$insertNode(_el$74, _el$75);
3138
- _$insertNode(_el$74, _el$83);
3139
- _$insertNode(_el$74, _el$87);
3140
- _$setProp(_el$74, "paddingLeft", 4);
3141
- _$setProp(_el$74, "paddingRight", 4);
3154
+ _$insertNode(_el$74, _el$80);
3155
+ _$setProp(_el$74, "flexDirection", "row");
3156
+ _$setProp(_el$74, "justifyContent", "space-between");
3142
3157
  _$insertNode(_el$75, _el$76);
3143
- _$insertNode(_el$75, _el$81);
3144
- _$setProp(_el$75, "flexDirection", "row");
3145
- _$setProp(_el$75, "justifyContent", "space-between");
3146
- _$insertNode(_el$76, _el$77);
3147
- _$insertNode(_el$76, _el$78);
3148
- _$insertNode(_el$78, _el$79);
3149
- _$insertNode(_el$78, _el$80);
3150
- _$insert(_el$78, () => selectableEntries().length, _el$80);
3151
- _$insertNode(_el$81, _$createTextNode(`esc`));
3152
- _$setProp(_el$81, "onMouseUp", close);
3153
- _$insertNode(_el$83, _el$84);
3154
- _$setProp(_el$83, "paddingTop", 1);
3155
- _$setProp(_el$84, "focused", true);
3156
- _$setProp(_el$84, "placeholder", "Search title, directory, transcript…");
3157
- _$setProp(_el$84, "cursorStyle", {
3158
+ _$insertNode(_el$75, _el$77);
3159
+ _$insertNode(_el$77, _el$78);
3160
+ _$insertNode(_el$77, _el$79);
3161
+ _$insert(_el$77, () => selectableEntries().length, _el$79);
3162
+ _$insertNode(_el$80, _$createTextNode(`esc`));
3163
+ _$setProp(_el$80, "onMouseUp", close);
3164
+ _$insertNode(_el$82, _el$83);
3165
+ _$setProp(_el$82, "paddingTop", 1);
3166
+ _$setProp(_el$83, "focused", true);
3167
+ _$setProp(_el$83, "placeholder", "Search title, directory, transcript…");
3168
+ _$setProp(_el$83, "cursorStyle", {
3158
3169
  style: "line",
3159
3170
  blinking: false
3160
3171
  });
3161
- _$setProp(_el$84, "onInput", value => {
3172
+ _$setProp(_el$83, "onInput", value => {
3162
3173
  if (pendingDelete()) return;
3163
3174
  setQuery(value);
3164
3175
  });
3165
- _$setProp(_el$84, "onSubmit", () => {
3176
+ _$setProp(_el$83, "onSubmit", () => {
3166
3177
  if (confirmArmed()) return;
3167
3178
  choose();
3168
3179
  });
3169
- _$setProp(_el$84, "onKeyDown", event => {
3180
+ _$setProp(_el$83, "onKeyDown", event => {
3170
3181
  if (event.name === "escape") {
3171
3182
  event.preventDefault();
3172
3183
  handleEscape();
@@ -3198,79 +3209,79 @@ const tui = async api => {
3198
3209
  }
3199
3210
  }
3200
3211
  });
3201
- _$insert(_el$74, _$createComponent(Show, {
3212
+ _$insert(_el$73, _$createComponent(Show, {
3202
3213
  get when() {
3203
3214
  return coverageLabel();
3204
3215
  },
3205
3216
  get children() {
3206
- var _el$85 = _$createElement("box"),
3207
- _el$86 = _$createElement("text");
3208
- _$insertNode(_el$85, _el$86);
3209
- _$setProp(_el$85, "paddingTop", 1);
3210
- _$insert(_el$86, coverageLabel);
3211
- _$effect(_$p => _$setProp(_el$86, "style", {
3217
+ var _el$84 = _$createElement("box"),
3218
+ _el$85 = _$createElement("text");
3219
+ _$insertNode(_el$84, _el$85);
3220
+ _$setProp(_el$84, "paddingTop", 1);
3221
+ _$insert(_el$85, coverageLabel);
3222
+ _$effect(_$p => _$setProp(_el$85, "style", {
3212
3223
  fg: api.theme.current.textMuted
3213
3224
  }, _$p));
3214
- return _el$85;
3225
+ return _el$84;
3215
3226
  }
3216
- }), _el$87);
3217
- _$insertNode(_el$87, _el$88);
3218
- _$insertNode(_el$87, _el$89);
3219
- _$insertNode(_el$87, _el$90);
3220
- _$setProp(_el$87, "flexDirection", "row");
3221
- _$setProp(_el$87, "gap", 2);
3222
- _$setProp(_el$87, "paddingTop", 1);
3223
- _$setProp(_el$88, "onMouseDown", () => {
3227
+ }), _el$86);
3228
+ _$insertNode(_el$86, _el$87);
3229
+ _$insertNode(_el$86, _el$88);
3230
+ _$insertNode(_el$86, _el$89);
3231
+ _$setProp(_el$86, "flexDirection", "row");
3232
+ _$setProp(_el$86, "gap", 2);
3233
+ _$setProp(_el$86, "paddingTop", 1);
3234
+ _$setProp(_el$87, "onMouseDown", () => {
3224
3235
  const group = currentProject();
3225
3236
  if (group) setScope(scope() === group ? undefined : group);else api.ui.toast({
3226
3237
  message: "No current project to filter",
3227
3238
  variant: "info"
3228
3239
  });
3229
3240
  });
3230
- _$insert(_el$88, (() => {
3241
+ _$insert(_el$87, (() => {
3231
3242
  var _c$6 = _$memo(() => !!scope());
3232
3243
  return () => _c$6() ? `Project: ${truncate(scope(), 22)}` : "Project: all";
3233
3244
  })());
3234
- _$setProp(_el$89, "onMouseDown", () => setWaitingOnly(value => !value));
3235
- _$insert(_el$89, () => waitingOnly() ? "● Needs input" : "○ Needs input");
3236
- _$setProp(_el$90, "onMouseDown", () => setPinnedOnly(value => !value));
3237
- _$insert(_el$90, () => pinnedOnly() ? "★ Pinned" : "☆ Pinned");
3238
- _$setProp(_el$91, "flexDirection", "column");
3239
- _$setProp(_el$91, "flexGrow", 1);
3240
- _$setProp(_el$91, "overflow", "hidden");
3241
- _$setProp(_el$91, "onMouseScroll", event => {
3245
+ _$setProp(_el$88, "onMouseDown", () => setWaitingOnly(value => !value));
3246
+ _$insert(_el$88, () => waitingOnly() ? "● Needs input" : "○ Needs input");
3247
+ _$setProp(_el$89, "onMouseDown", () => setPinnedOnly(value => !value));
3248
+ _$insert(_el$89, () => pinnedOnly() ? "★ Pinned" : "☆ Pinned");
3249
+ _$setProp(_el$90, "flexDirection", "column");
3250
+ _$setProp(_el$90, "flexGrow", 1);
3251
+ _$setProp(_el$90, "overflow", "hidden");
3252
+ _$setProp(_el$90, "onMouseScroll", event => {
3242
3253
  scrollPicker(event.scroll);
3243
3254
  });
3244
- _$insert(_el$91, _$createComponent(For, {
3255
+ _$insert(_el$90, _$createComponent(For, {
3245
3256
  get each() {
3246
3257
  return visiblePickerRows();
3247
3258
  },
3248
3259
  children: row => {
3249
3260
  if (row.kind === "group") return (() => {
3250
- var _el$108 = _$createElement("box"),
3261
+ var _el$107 = _$createElement("box"),
3262
+ _el$108 = _$createElement("text"),
3251
3263
  _el$109 = _$createElement("text"),
3252
- _el$110 = _$createElement("text"),
3253
- _el$111 = _$createTextNode(` (`),
3254
- _el$112 = _$createTextNode(`)`);
3255
- _$insertNode(_el$108, _el$109);
3256
- _$insertNode(_el$108, _el$110);
3257
- _$setProp(_el$108, "flexDirection", "row");
3258
- _$setProp(_el$108, "paddingLeft", 4);
3259
- _$setProp(_el$108, "paddingRight", 4);
3260
- _$setProp(_el$108, "onMouseDown", () => setCollapsed(state => ({
3264
+ _el$110 = _$createTextNode(` (`),
3265
+ _el$111 = _$createTextNode(`)`);
3266
+ _$insertNode(_el$107, _el$108);
3267
+ _$insertNode(_el$107, _el$109);
3268
+ _$setProp(_el$107, "flexDirection", "row");
3269
+ _$setProp(_el$107, "paddingLeft", 4);
3270
+ _$setProp(_el$107, "paddingRight", 4);
3271
+ _$setProp(_el$107, "onMouseDown", () => setCollapsed(state => ({
3261
3272
  ...state,
3262
3273
  [row.dir]: !state[row.dir]
3263
3274
  })));
3264
- _$setProp(_el$109, "flexGrow", 1);
3265
- _$setProp(_el$109, "flexShrink", 1);
3266
- _$setProp(_el$109, "wrapMode", "none");
3267
- _$insert(_el$109, () => collapsed()[row.dir] && !query().trim() ? "▸ " : "▾ ", null);
3268
- _$insert(_el$109, () => row.pinned ? "★ " : "", null);
3269
- _$insert(_el$109, () => row.label, null);
3270
- _$insertNode(_el$110, _el$111);
3271
- _$insertNode(_el$110, _el$112);
3272
- _$setProp(_el$110, "flexShrink", 0);
3273
- _$insert(_el$110, () => row.count, _el$112);
3275
+ _$setProp(_el$108, "flexGrow", 1);
3276
+ _$setProp(_el$108, "flexShrink", 1);
3277
+ _$setProp(_el$108, "wrapMode", "none");
3278
+ _$insert(_el$108, () => collapsed()[row.dir] && !query().trim() ? "▸ " : "▾ ", null);
3279
+ _$insert(_el$108, () => row.pinned ? "★ " : "", null);
3280
+ _$insert(_el$108, () => row.label, null);
3281
+ _$insertNode(_el$109, _el$110);
3282
+ _$insertNode(_el$109, _el$111);
3283
+ _$setProp(_el$109, "flexShrink", 0);
3284
+ _$insert(_el$109, () => row.count, _el$111);
3274
3285
  _$effect(_p$ => {
3275
3286
  var _v$58 = row.continued ? 0 : 1,
3276
3287
  _v$59 = {
@@ -3280,10 +3291,10 @@ const tui = async api => {
3280
3291
  _v$61 = {
3281
3292
  fg: api.theme.current.textMuted
3282
3293
  };
3283
- _v$58 !== _p$.e && (_p$.e = _$setProp(_el$108, "paddingTop", _v$58, _p$.e));
3284
- _v$59 !== _p$.t && (_p$.t = _$setProp(_el$109, "style", _v$59, _p$.t));
3285
- _v$60 !== _p$.a && (_p$.a = _$setProp(_el$109, "attributes", _v$60, _p$.a));
3286
- _v$61 !== _p$.o && (_p$.o = _$setProp(_el$110, "style", _v$61, _p$.o));
3294
+ _v$58 !== _p$.e && (_p$.e = _$setProp(_el$107, "paddingTop", _v$58, _p$.e));
3295
+ _v$59 !== _p$.t && (_p$.t = _$setProp(_el$108, "style", _v$59, _p$.t));
3296
+ _v$60 !== _p$.a && (_p$.a = _$setProp(_el$108, "attributes", _v$60, _p$.a));
3297
+ _v$61 !== _p$.o && (_p$.o = _$setProp(_el$109, "style", _v$61, _p$.o));
3287
3298
  return _p$;
3288
3299
  }, {
3289
3300
  e: undefined,
@@ -3291,46 +3302,46 @@ const tui = async api => {
3291
3302
  a: undefined,
3292
3303
  o: undefined
3293
3304
  });
3294
- return _el$108;
3305
+ return _el$107;
3295
3306
  })();
3296
3307
  const excerpt = createMemo(() => transcriptMatchExcerpt(searchIndex().get(row.entry.id), row.entry, query()));
3297
3308
  return (() => {
3298
- var _el$113 = _$createElement("box"),
3299
- _el$114 = _$createElement("box"),
3300
- _el$115 = _$createElement("text"),
3301
- _el$118 = _$createElement("text");
3302
- _$insertNode(_el$113, _el$114);
3303
- _$setProp(_el$113, "flexDirection", "column");
3304
- _$setProp(_el$113, "paddingLeft", 6);
3305
- _$setProp(_el$113, "paddingRight", 4);
3306
- _$setProp(_el$113, "onMouseMove", () => {
3309
+ var _el$112 = _$createElement("box"),
3310
+ _el$113 = _$createElement("box"),
3311
+ _el$114 = _$createElement("text"),
3312
+ _el$117 = _$createElement("text");
3313
+ _$insertNode(_el$112, _el$113);
3314
+ _$setProp(_el$112, "flexDirection", "column");
3315
+ _$setProp(_el$112, "paddingLeft", 6);
3316
+ _$setProp(_el$112, "paddingRight", 4);
3317
+ _$setProp(_el$112, "onMouseMove", () => {
3307
3318
  // Repainting under a stationary pointer must not select
3308
3319
  // another row while the wheel is moving the viewport.
3309
3320
  const index = selectableEntries().findIndex(entry => entry.id === row.entry.id);
3310
3321
  if (index >= 0) setCursor(index);
3311
3322
  });
3312
- _$setProp(_el$113, "onMouseDown", event => event.button === RIGHT_BUTTON ? (cleanup(), api.ui.dialog.clear(), openInCmuxWorkspace(api, row.entry)) : choose(row.entry));
3313
- _$insertNode(_el$114, _el$115);
3314
- _$insertNode(_el$114, _el$118);
3315
- _$setProp(_el$114, "flexDirection", "row");
3316
- _$setProp(_el$114, "gap", 1);
3317
- _$setProp(_el$115, "flexShrink", 0);
3318
- _$insert(_el$115, () => row.last ? "└" : "├");
3319
- _$insert(_el$114, _$createComponent(Show, {
3323
+ _$setProp(_el$112, "onMouseDown", event => event.button === RIGHT_BUTTON ? (cleanup(), api.ui.dialog.clear(), openInCmuxWorkspace(api, row.entry)) : choose(row.entry));
3324
+ _$insertNode(_el$113, _el$114);
3325
+ _$insertNode(_el$113, _el$117);
3326
+ _$setProp(_el$113, "flexDirection", "row");
3327
+ _$setProp(_el$113, "gap", 1);
3328
+ _$setProp(_el$114, "flexShrink", 0);
3329
+ _$insert(_el$114, () => row.last ? "└" : "├");
3330
+ _$insert(_el$113, _$createComponent(Show, {
3320
3331
  get when() {
3321
3332
  return row.entry.id === currentSessionID();
3322
3333
  },
3323
3334
  get children() {
3324
- var _el$116 = _$createElement("text");
3325
- _$insertNode(_el$116, _$createTextNode(`●`));
3326
- _$setProp(_el$116, "flexShrink", 0);
3327
- _$effect(_$p => _$setProp(_el$116, "style", {
3335
+ var _el$115 = _$createElement("text");
3336
+ _$insertNode(_el$115, _$createTextNode(`●`));
3337
+ _$setProp(_el$115, "flexShrink", 0);
3338
+ _$effect(_$p => _$setProp(_el$115, "style", {
3328
3339
  fg: row.entry.id === selectableEntries()[cursor()]?.id ? api.theme.current.text : api.theme.current.primary
3329
3340
  }, _$p));
3330
- return _el$116;
3341
+ return _el$115;
3331
3342
  }
3332
- }), _el$118);
3333
- _$insert(_el$114, _$createComponent(Highlighted, {
3343
+ }), _el$117);
3344
+ _$insert(_el$113, _$createComponent(Highlighted, {
3334
3345
  get text() {
3335
3346
  return `${pins().sessions.includes(row.entry.id) ? "★ " : ""}${truncate(row.entry.title, pins().sessions.includes(row.entry.id) ? 59 : 61)}`;
3336
3347
  },
@@ -3346,26 +3357,26 @@ const tui = async api => {
3346
3357
  get matchColor() {
3347
3358
  return _$memo(() => row.entry.id === selectableEntries()[cursor()]?.id)() ? api.theme.current.text : api.theme.current.warning;
3348
3359
  }
3349
- }), _el$118);
3350
- _$setProp(_el$118, "flexShrink", 0);
3351
- _$insert(_el$118, (() => {
3360
+ }), _el$117);
3361
+ _$setProp(_el$117, "flexShrink", 0);
3362
+ _$insert(_el$117, (() => {
3352
3363
  var _c$0 = _$memo(() => pendingDelete()?.id === row.entry.id);
3353
3364
  return () => _c$0() ? "press y to delete" : `${ago(row.entry.updated)}${query().trim() && !`${row.entry.title} ${row.entry.dir}`.toLowerCase().includes(query().trim().toLowerCase()) ? " · transcript match" : ""}`;
3354
3365
  })());
3355
- _$insert(_el$113, _$createComponent(Show, {
3366
+ _$insert(_el$112, _$createComponent(Show, {
3356
3367
  get when() {
3357
3368
  return excerpt();
3358
3369
  },
3359
3370
  children: match => (() => {
3360
- var _el$119 = _$createElement("box"),
3361
- _el$120 = _$createElement("text");
3362
- _$insertNode(_el$119, _el$120);
3363
- _$setProp(_el$119, "flexDirection", "row");
3364
- _$setProp(_el$119, "gap", 1);
3365
- _$setProp(_el$119, "paddingLeft", 2);
3366
- _$insertNode(_el$120, _$createTextNode(`↳`));
3367
- _$setProp(_el$120, "flexShrink", 0);
3368
- _$insert(_el$119, _$createComponent(Highlighted, {
3371
+ var _el$118 = _$createElement("box"),
3372
+ _el$119 = _$createElement("text");
3373
+ _$insertNode(_el$118, _el$119);
3374
+ _$setProp(_el$118, "flexDirection", "row");
3375
+ _$setProp(_el$118, "gap", 1);
3376
+ _$setProp(_el$118, "paddingLeft", 2);
3377
+ _$insertNode(_el$119, _$createTextNode(`↳`));
3378
+ _$setProp(_el$119, "flexShrink", 0);
3379
+ _$insert(_el$118, _$createComponent(Highlighted, {
3369
3380
  get text() {
3370
3381
  return match();
3371
3382
  },
@@ -3379,10 +3390,10 @@ const tui = async api => {
3379
3390
  return api.theme.current.warning;
3380
3391
  }
3381
3392
  }), null);
3382
- _$effect(_$p => _$setProp(_el$120, "style", {
3393
+ _$effect(_$p => _$setProp(_el$119, "style", {
3383
3394
  fg: api.theme.current.textMuted
3384
3395
  }, _$p));
3385
- return _el$119;
3396
+ return _el$118;
3386
3397
  })()
3387
3398
  }), null);
3388
3399
  _$effect(_p$ => {
@@ -3393,126 +3404,126 @@ const tui = async api => {
3393
3404
  _v$64 = {
3394
3405
  fg: pendingDelete()?.id === row.entry.id ? api.theme.current.error : row.entry.id === selectableEntries()[cursor()]?.id ? api.theme.current.text : api.theme.current.textMuted
3395
3406
  };
3396
- _v$62 !== _p$.e && (_p$.e = _$setProp(_el$113, "backgroundColor", _v$62, _p$.e));
3397
- _v$63 !== _p$.t && (_p$.t = _$setProp(_el$115, "style", _v$63, _p$.t));
3398
- _v$64 !== _p$.a && (_p$.a = _$setProp(_el$118, "style", _v$64, _p$.a));
3407
+ _v$62 !== _p$.e && (_p$.e = _$setProp(_el$112, "backgroundColor", _v$62, _p$.e));
3408
+ _v$63 !== _p$.t && (_p$.t = _$setProp(_el$114, "style", _v$63, _p$.t));
3409
+ _v$64 !== _p$.a && (_p$.a = _$setProp(_el$117, "style", _v$64, _p$.a));
3399
3410
  return _p$;
3400
3411
  }, {
3401
3412
  e: undefined,
3402
3413
  t: undefined,
3403
3414
  a: undefined
3404
3415
  });
3405
- return _el$113;
3416
+ return _el$112;
3406
3417
  })();
3407
3418
  }
3408
3419
  }), null);
3409
- _$insert(_el$91, _$createComponent(Show, {
3420
+ _$insert(_el$90, _$createComponent(Show, {
3410
3421
  get when() {
3411
3422
  return matchedGroups().length === 0;
3412
3423
  },
3413
3424
  get children() {
3414
- var _el$92 = _$createElement("box"),
3415
- _el$93 = _$createElement("text");
3416
- _$insertNode(_el$92, _el$93);
3417
- _$setProp(_el$92, "paddingLeft", 4);
3418
- _$setProp(_el$92, "paddingRight", 4);
3419
- _$insert(_el$93, (() => {
3425
+ var _el$91 = _$createElement("box"),
3426
+ _el$92 = _$createElement("text");
3427
+ _$insertNode(_el$91, _el$92);
3428
+ _$setProp(_el$91, "paddingLeft", 4);
3429
+ _$setProp(_el$91, "paddingRight", 4);
3430
+ _$insert(_el$92, (() => {
3420
3431
  var _c$7 = _$memo(() => !!(waitingOnly() && waitingCoverage() === "loading"));
3421
3432
  return () => _c$7() ? "Checking which sessions need input…" : _$memo(() => !!(waitingOnly() && waitingCoverage() === "unavailable"))() ? "Needs-input data unavailable · turn off the filter" : _$memo(() => !!(pinnedOnly() && pins().sessions.length === 0))() ? "No pinned sessions yet · ctrl+s pins a session" : _$memo(() => !!(!indexProgress().complete && query().trim()))() ? "No matches yet · still searching transcripts…" : _$memo(() => !!scope())() ? `No matches in ${scope()} · ctrl+g for all projects` : waitingOnly() ? "No sessions need input with these filters" : "No sessions match · try another search";
3422
3433
  })());
3423
- _$effect(_$p => _$setProp(_el$93, "style", {
3434
+ _$effect(_$p => _$setProp(_el$92, "style", {
3424
3435
  fg: api.theme.current.textMuted
3425
3436
  }, _$p));
3426
- return _el$92;
3437
+ return _el$91;
3427
3438
  }
3428
3439
  }), null);
3429
- _$insertNode(_el$94, _el$95);
3430
- _$setProp(_el$94, "paddingLeft", 4);
3431
- _$setProp(_el$94, "paddingRight", 4);
3432
- _$setProp(_el$94, "flexShrink", 0);
3433
- _$setProp(_el$94, "flexDirection", "column");
3434
- _$insert(_el$95, (() => {
3440
+ _$insertNode(_el$93, _el$94);
3441
+ _$setProp(_el$93, "paddingLeft", 4);
3442
+ _$setProp(_el$93, "paddingRight", 4);
3443
+ _$setProp(_el$93, "flexShrink", 0);
3444
+ _$setProp(_el$93, "flexDirection", "column");
3445
+ _$insert(_el$94, (() => {
3435
3446
  var _c$8 = _$memo(() => !!pendingDelete());
3436
3447
  return () => _c$8() ? `Delete "${truncate(pendingDelete().title, 40)}"? y confirm · n cancel` : "↑↓ move · enter open · ctrl+g project · option+w input · option+s pinned · option+p preview";
3437
3448
  })());
3438
- _$insert(_el$94, _$createComponent(Show, {
3449
+ _$insert(_el$93, _$createComponent(Show, {
3439
3450
  get when() {
3440
3451
  return !pendingDelete();
3441
3452
  },
3442
3453
  get children() {
3443
- var _el$96 = _$createElement("text");
3444
- _$insertNode(_el$96, _$createTextNode(`ctrl+s/d pin · option+d delete · ctrl+f fork · esc close`));
3445
- _$effect(_$p => _$setProp(_el$96, "style", {
3454
+ var _el$95 = _$createElement("text");
3455
+ _$insertNode(_el$95, _$createTextNode(`ctrl+s/d pin · option+d delete · ctrl+f fork · esc close`));
3456
+ _$effect(_$p => _$setProp(_el$95, "style", {
3446
3457
  fg: api.theme.current.textMuted
3447
3458
  }, _$p));
3448
- return _el$96;
3459
+ return _el$95;
3449
3460
  }
3450
3461
  }), null);
3451
- _$insert(_el$73, _$createComponent(Show, {
3462
+ _$insert(_el$72, _$createComponent(Show, {
3452
3463
  get when() {
3453
3464
  return showPreview();
3454
3465
  },
3455
3466
  get children() {
3456
- var _el$98 = _$createElement("box"),
3457
- _el$99 = _$createElement("box"),
3467
+ var _el$97 = _$createElement("box"),
3468
+ _el$98 = _$createElement("box"),
3469
+ _el$99 = _$createElement("text"),
3458
3470
  _el$100 = _$createElement("text"),
3459
- _el$101 = _$createElement("text"),
3460
- _el$105 = _$createElement("scrollbox"),
3461
- _el$106 = _$createElement("text");
3471
+ _el$104 = _$createElement("scrollbox"),
3472
+ _el$105 = _$createElement("text");
3473
+ _$insertNode(_el$97, _el$98);
3474
+ _$insertNode(_el$97, _el$104);
3475
+ _$insertNode(_el$97, _el$105);
3476
+ _$setProp(_el$97, "position", "absolute");
3477
+ _$setProp(_el$97, "left", 0);
3478
+ _$setProp(_el$97, "top", 0);
3479
+ _$setProp(_el$97, "width", dialogWidth);
3480
+ _$setProp(_el$97, "flexDirection", "column");
3481
+ _$setProp(_el$97, "paddingLeft", 4);
3482
+ _$setProp(_el$97, "paddingRight", 4);
3483
+ _$setProp(_el$97, "paddingTop", 1);
3484
+ _$setProp(_el$97, "paddingBottom", 1);
3485
+ _$setProp(_el$97, "gap", 1);
3462
3486
  _$insertNode(_el$98, _el$99);
3463
- _$insertNode(_el$98, _el$105);
3464
- _$insertNode(_el$98, _el$106);
3465
- _$setProp(_el$98, "position", "absolute");
3466
- _$setProp(_el$98, "left", 0);
3467
- _$setProp(_el$98, "top", 0);
3468
- _$setProp(_el$98, "width", dialogWidth);
3469
- _$setProp(_el$98, "flexDirection", "column");
3470
- _$setProp(_el$98, "paddingLeft", 4);
3471
- _$setProp(_el$98, "paddingRight", 4);
3472
- _$setProp(_el$98, "paddingTop", 1);
3473
- _$setProp(_el$98, "paddingBottom", 1);
3474
- _$setProp(_el$98, "gap", 1);
3475
- _$insertNode(_el$99, _el$100);
3476
- _$insertNode(_el$99, _el$101);
3477
- _$setProp(_el$99, "flexDirection", "row");
3478
- _$setProp(_el$99, "justifyContent", "space-between");
3479
- _$insert(_el$100, (() => {
3487
+ _$insertNode(_el$98, _el$100);
3488
+ _$setProp(_el$98, "flexDirection", "row");
3489
+ _$setProp(_el$98, "justifyContent", "space-between");
3490
+ _$insert(_el$99, (() => {
3480
3491
  var _c$9 = _$memo(() => !!previewID());
3481
3492
  return () => _c$9() ? truncate(selectableEntries()[cursor()].title, dialogWidth - 18) : "Preview";
3482
3493
  })());
3483
- _$insertNode(_el$101, _$createTextNode(`esc close`));
3484
- _$insert(_el$98, _$createComponent(Show, {
3494
+ _$insertNode(_el$100, _$createTextNode(`esc close`));
3495
+ _$insert(_el$97, _$createComponent(Show, {
3485
3496
  get when() {
3486
3497
  return previewID();
3487
3498
  },
3488
3499
  get children() {
3489
- var _el$103 = _$createElement("text"),
3490
- _el$104 = _$createTextNode(` · `);
3491
- _$insertNode(_el$103, _el$104);
3492
- _$insert(_el$103, () => prettyDir(selectableEntries()[cursor()].dir, process.env.HOME ?? ""), _el$104);
3493
- _$insert(_el$103, () => ago(selectableEntries()[cursor()].updated), null);
3494
- _$effect(_$p => _$setProp(_el$103, "style", {
3500
+ var _el$102 = _$createElement("text"),
3501
+ _el$103 = _$createTextNode(` · `);
3502
+ _$insertNode(_el$102, _el$103);
3503
+ _$insert(_el$102, () => prettyDir(selectableEntries()[cursor()].dir, process.env.HOME ?? ""), _el$103);
3504
+ _$insert(_el$102, () => ago(selectableEntries()[cursor()].updated), null);
3505
+ _$effect(_$p => _$setProp(_el$102, "style", {
3495
3506
  fg: api.theme.current.textMuted
3496
3507
  }, _$p));
3497
- return _el$103;
3508
+ return _el$102;
3498
3509
  }
3499
- }), _el$105);
3500
- _$setProp(_el$105, "flexGrow", 1);
3501
- _$setProp(_el$105, "scrollbarOptions", {
3510
+ }), _el$104);
3511
+ _$setProp(_el$104, "flexGrow", 1);
3512
+ _$setProp(_el$104, "scrollbarOptions", {
3502
3513
  visible: false
3503
3514
  });
3504
- _$insert(_el$105, _$createComponent(Show, {
3515
+ _$insert(_el$104, _$createComponent(Show, {
3505
3516
  get when() {
3506
3517
  return previewID();
3507
3518
  },
3508
3519
  get fallback() {
3509
3520
  return (() => {
3510
- var _el$122 = _$createElement("text");
3511
- _$insertNode(_el$122, _$createTextNode(`Select a session to preview`));
3512
- _$effect(_$p => _$setProp(_el$122, "style", {
3521
+ var _el$121 = _$createElement("text");
3522
+ _$insertNode(_el$121, _$createTextNode(`Select a session to preview`));
3523
+ _$effect(_$p => _$setProp(_el$121, "style", {
3513
3524
  fg: api.theme.current.textMuted
3514
3525
  }, _$p));
3515
- return _el$122;
3526
+ return _el$121;
3516
3527
  })();
3517
3528
  },
3518
3529
  get children() {
@@ -3522,40 +3533,40 @@ const tui = async api => {
3522
3533
  },
3523
3534
  get fallback() {
3524
3535
  return (() => {
3525
- var _el$124 = _$createElement("text");
3526
- _$insertNode(_el$124, _$createTextNode(`Loading…`));
3527
- _$effect(_$p => _$setProp(_el$124, "style", {
3536
+ var _el$123 = _$createElement("text");
3537
+ _$insertNode(_el$123, _$createTextNode(`Loading…`));
3538
+ _$effect(_$p => _$setProp(_el$123, "style", {
3528
3539
  fg: api.theme.current.textMuted
3529
3540
  }, _$p));
3530
- return _el$124;
3541
+ return _el$123;
3531
3542
  })();
3532
3543
  },
3533
3544
  children: text => getMarkdownStyle(api.theme.current, api.renderer?.nativeSession) ? (() => {
3534
- var _el$126 = _$createElement("markdown");
3545
+ var _el$125 = _$createElement("markdown");
3535
3546
  _$effect(_p$ => {
3536
3547
  var _v$65 = text(),
3537
3548
  _v$66 = getMarkdownStyle(api.theme.current, api.renderer?.nativeSession),
3538
3549
  _v$67 = getTreeSitterClient();
3539
- _v$65 !== _p$.e && (_p$.e = _$setProp(_el$126, "content", _v$65, _p$.e));
3540
- _v$66 !== _p$.t && (_p$.t = _$setProp(_el$126, "syntaxStyle", _v$66, _p$.t));
3541
- _v$67 !== _p$.a && (_p$.a = _$setProp(_el$126, "treeSitterClient", _v$67, _p$.a));
3550
+ _v$65 !== _p$.e && (_p$.e = _$setProp(_el$125, "content", _v$65, _p$.e));
3551
+ _v$66 !== _p$.t && (_p$.t = _$setProp(_el$125, "syntaxStyle", _v$66, _p$.t));
3552
+ _v$67 !== _p$.a && (_p$.a = _$setProp(_el$125, "treeSitterClient", _v$67, _p$.a));
3542
3553
  return _p$;
3543
3554
  }, {
3544
3555
  e: undefined,
3545
3556
  t: undefined,
3546
3557
  a: undefined
3547
3558
  });
3548
- return _el$126;
3559
+ return _el$125;
3549
3560
  })() : (() => {
3550
- var _el$127 = _$createElement("text");
3551
- _$setProp(_el$127, "wrapMode", "word");
3552
- _$insert(_el$127, text);
3553
- return _el$127;
3561
+ var _el$126 = _$createElement("text");
3562
+ _$setProp(_el$126, "wrapMode", "word");
3563
+ _$insert(_el$126, text);
3564
+ return _el$126;
3554
3565
  })()
3555
3566
  });
3556
3567
  }
3557
3568
  }));
3558
- _$insertNode(_el$106, _$createTextNode(`↑↓ switch session · esc back to picker`));
3569
+ _$insertNode(_el$105, _$createTextNode(`↑↓ switch session · esc back to picker`));
3559
3570
  _$effect(_p$ => {
3560
3571
  var _v$38 = dialogHeight(),
3561
3572
  _v$39 = api.theme.current.backgroundPanel,
@@ -3566,11 +3577,11 @@ const tui = async api => {
3566
3577
  _v$42 = {
3567
3578
  fg: api.theme.current.textMuted
3568
3579
  };
3569
- _v$38 !== _p$.e && (_p$.e = _$setProp(_el$98, "height", _v$38, _p$.e));
3570
- _v$39 !== _p$.t && (_p$.t = _$setProp(_el$98, "backgroundColor", _v$39, _p$.t));
3571
- _v$40 !== _p$.a && (_p$.a = _$setProp(_el$100, "attributes", _v$40, _p$.a));
3572
- _v$41 !== _p$.o && (_p$.o = _$setProp(_el$101, "style", _v$41, _p$.o));
3573
- _v$42 !== _p$.i && (_p$.i = _$setProp(_el$106, "style", _v$42, _p$.i));
3580
+ _v$38 !== _p$.e && (_p$.e = _$setProp(_el$97, "height", _v$38, _p$.e));
3581
+ _v$39 !== _p$.t && (_p$.t = _$setProp(_el$97, "backgroundColor", _v$39, _p$.t));
3582
+ _v$40 !== _p$.a && (_p$.a = _$setProp(_el$99, "attributes", _v$40, _p$.a));
3583
+ _v$41 !== _p$.o && (_p$.o = _$setProp(_el$100, "style", _v$41, _p$.o));
3584
+ _v$42 !== _p$.i && (_p$.i = _$setProp(_el$105, "style", _v$42, _p$.i));
3574
3585
  return _p$;
3575
3586
  }, {
3576
3587
  e: undefined,
@@ -3579,7 +3590,7 @@ const tui = async api => {
3579
3590
  o: undefined,
3580
3591
  i: undefined
3581
3592
  });
3582
- return _el$98;
3593
+ return _el$97;
3583
3594
  }
3584
3595
  }), null);
3585
3596
  _$effect(_p$ => {
@@ -3610,21 +3621,21 @@ const tui = async api => {
3610
3621
  _v$57 = {
3611
3622
  fg: pendingDelete() ? api.theme.current.warning : api.theme.current.textMuted
3612
3623
  };
3613
- _v$43 !== _p$.e && (_p$.e = _$setProp(_el$73, "height", _v$43, _p$.e));
3614
- _v$44 !== _p$.t && (_p$.t = _$setProp(_el$73, "marginTop", _v$44, _p$.t));
3615
- _v$45 !== _p$.a && (_p$.a = _$setProp(_el$73, "backgroundColor", _v$45, _p$.a));
3616
- _v$46 !== _p$.o && (_p$.o = _$setProp(_el$76, "attributes", _v$46, _p$.o));
3617
- _v$47 !== _p$.i && (_p$.i = _$setProp(_el$78, "style", _v$47, _p$.i));
3618
- _v$48 !== _p$.n && (_p$.n = _$setProp(_el$81, "style", _v$48, _p$.n));
3619
- _v$49 !== _p$.s && (_p$.s = _$setProp(_el$84, "value", _v$49, _p$.s));
3620
- _v$50 !== _p$.h && (_p$.h = _$setProp(_el$84, "placeholderColor", _v$50, _p$.h));
3621
- _v$51 !== _p$.r && (_p$.r = _$setProp(_el$84, "focusedBackgroundColor", _v$51, _p$.r));
3622
- _v$52 !== _p$.d && (_p$.d = _$setProp(_el$84, "focusedTextColor", _v$52, _p$.d));
3623
- _v$53 !== _p$.l && (_p$.l = _$setProp(_el$84, "cursorColor", _v$53, _p$.l));
3624
- _v$54 !== _p$.u && (_p$.u = _$setProp(_el$88, "style", _v$54, _p$.u));
3625
- _v$55 !== _p$.c && (_p$.c = _$setProp(_el$89, "style", _v$55, _p$.c));
3626
- _v$56 !== _p$.w && (_p$.w = _$setProp(_el$90, "style", _v$56, _p$.w));
3627
- _v$57 !== _p$.m && (_p$.m = _$setProp(_el$95, "style", _v$57, _p$.m));
3624
+ _v$43 !== _p$.e && (_p$.e = _$setProp(_el$72, "height", _v$43, _p$.e));
3625
+ _v$44 !== _p$.t && (_p$.t = _$setProp(_el$72, "marginTop", _v$44, _p$.t));
3626
+ _v$45 !== _p$.a && (_p$.a = _$setProp(_el$72, "backgroundColor", _v$45, _p$.a));
3627
+ _v$46 !== _p$.o && (_p$.o = _$setProp(_el$75, "attributes", _v$46, _p$.o));
3628
+ _v$47 !== _p$.i && (_p$.i = _$setProp(_el$77, "style", _v$47, _p$.i));
3629
+ _v$48 !== _p$.n && (_p$.n = _$setProp(_el$80, "style", _v$48, _p$.n));
3630
+ _v$49 !== _p$.s && (_p$.s = _$setProp(_el$83, "value", _v$49, _p$.s));
3631
+ _v$50 !== _p$.h && (_p$.h = _$setProp(_el$83, "placeholderColor", _v$50, _p$.h));
3632
+ _v$51 !== _p$.r && (_p$.r = _$setProp(_el$83, "focusedBackgroundColor", _v$51, _p$.r));
3633
+ _v$52 !== _p$.d && (_p$.d = _$setProp(_el$83, "focusedTextColor", _v$52, _p$.d));
3634
+ _v$53 !== _p$.l && (_p$.l = _$setProp(_el$83, "cursorColor", _v$53, _p$.l));
3635
+ _v$54 !== _p$.u && (_p$.u = _$setProp(_el$87, "style", _v$54, _p$.u));
3636
+ _v$55 !== _p$.c && (_p$.c = _$setProp(_el$88, "style", _v$55, _p$.c));
3637
+ _v$56 !== _p$.w && (_p$.w = _$setProp(_el$89, "style", _v$56, _p$.w));
3638
+ _v$57 !== _p$.m && (_p$.m = _$setProp(_el$94, "style", _v$57, _p$.m));
3628
3639
  return _p$;
3629
3640
  }, {
3630
3641
  e: undefined,
@@ -3643,7 +3654,7 @@ const tui = async api => {
3643
3654
  w: undefined,
3644
3655
  m: undefined
3645
3656
  });
3646
- return _el$73;
3657
+ return _el$72;
3647
3658
  })(), () => {
3648
3659
  cleanup();
3649
3660
  });
@@ -3689,65 +3700,65 @@ const tui = async api => {
3689
3700
  }]
3690
3701
  });
3691
3702
  api.ui.dialog.replace(() => (() => {
3692
- var _el$128 = _$createElement("box"),
3693
- _el$129 = _$createElement("text"),
3694
- _el$130 = _$createTextNode(`Cost digest `),
3695
- _el$132 = _$createElement("span"),
3696
- _el$134 = _$createElement("box"),
3697
- _el$135 = _$createElement("text");
3703
+ var _el$127 = _$createElement("box"),
3704
+ _el$128 = _$createElement("text"),
3705
+ _el$129 = _$createTextNode(`Cost digest `),
3706
+ _el$131 = _$createElement("span"),
3707
+ _el$133 = _$createElement("box"),
3708
+ _el$134 = _$createElement("text");
3709
+ _$insertNode(_el$127, _el$128);
3710
+ _$insertNode(_el$127, _el$133);
3711
+ _$setProp(_el$127, "flexDirection", "column");
3712
+ _$setProp(_el$127, "paddingLeft", 4);
3713
+ _$setProp(_el$127, "paddingRight", 4);
3714
+ _$setProp(_el$127, "paddingTop", 1);
3715
+ _$setProp(_el$127, "gap", 1);
3698
3716
  _$insertNode(_el$128, _el$129);
3699
- _$insertNode(_el$128, _el$134);
3700
- _$setProp(_el$128, "flexDirection", "column");
3701
- _$setProp(_el$128, "paddingLeft", 4);
3702
- _$setProp(_el$128, "paddingRight", 4);
3703
- _$setProp(_el$128, "paddingTop", 1);
3704
- _$setProp(_el$128, "gap", 1);
3705
- _$insertNode(_el$129, _el$130);
3706
- _$insertNode(_el$129, _el$132);
3707
- _$insertNode(_el$132, _$createTextNode(`(24h · lifetime)`));
3708
- _$insert(_el$128, _$createComponent(Show, {
3717
+ _$insertNode(_el$128, _el$131);
3718
+ _$insertNode(_el$131, _$createTextNode(`(24h · lifetime)`));
3719
+ _$insert(_el$127, _$createComponent(Show, {
3709
3720
  get when() {
3710
3721
  return !failed && rows.length > 0;
3711
3722
  },
3712
3723
  get fallback() {
3713
3724
  return (() => {
3714
- var _el$137 = _$createElement("text");
3715
- _$insert(_el$137, failed ? "Cost data unavailable." : "No assistant cost recorded.");
3716
- _$effect(_$p => _$setProp(_el$137, "style", {
3725
+ var _el$136 = _$createElement("text");
3726
+ _$insert(_el$136, failed ? "Cost data unavailable." : "No assistant cost recorded.");
3727
+ _$effect(_$p => _$setProp(_el$136, "style", {
3717
3728
  fg: api.theme.current.textMuted
3718
3729
  }, _$p));
3719
- return _el$137;
3730
+ return _el$136;
3720
3731
  })();
3721
3732
  },
3722
3733
  get children() {
3723
3734
  return _$createComponent(For, {
3724
3735
  each: rows,
3725
3736
  children: row => (() => {
3726
- var _el$138 = _$createElement("box"),
3737
+ var _el$137 = _$createElement("box"),
3738
+ _el$138 = _$createElement("text"),
3727
3739
  _el$139 = _$createElement("text"),
3728
3740
  _el$140 = _$createElement("text"),
3729
- _el$141 = _$createElement("text"),
3730
- _el$142 = _$createTextNode(`(`),
3731
- _el$143 = _$createTextNode(`)`),
3732
- _el$144 = _$createElement("text");
3733
- _$insertNode(_el$138, _el$139);
3734
- _$insertNode(_el$138, _el$140);
3735
- _$insertNode(_el$138, _el$141);
3736
- _$insertNode(_el$138, _el$144);
3737
- _$setProp(_el$138, "flexDirection", "row");
3738
- _$setProp(_el$138, "gap", 2);
3741
+ _el$141 = _$createTextNode(`(`),
3742
+ _el$142 = _$createTextNode(`)`),
3743
+ _el$143 = _$createElement("text");
3744
+ _$insertNode(_el$137, _el$138);
3745
+ _$insertNode(_el$137, _el$139);
3746
+ _$insertNode(_el$137, _el$140);
3747
+ _$insertNode(_el$137, _el$143);
3748
+ _$setProp(_el$137, "flexDirection", "row");
3749
+ _$setProp(_el$137, "gap", 2);
3750
+ _$setProp(_el$138, "flexShrink", 0);
3751
+ _$insert(_el$138, () => money(row.window));
3739
3752
  _$setProp(_el$139, "flexShrink", 0);
3740
- _$insert(_el$139, () => money(row.window));
3753
+ _$insert(_el$139, () => money(row.lifetime));
3754
+ _$insertNode(_el$140, _el$141);
3755
+ _$insertNode(_el$140, _el$142);
3741
3756
  _$setProp(_el$140, "flexShrink", 0);
3742
- _$insert(_el$140, () => money(row.lifetime));
3743
- _$insertNode(_el$141, _el$142);
3744
- _$insertNode(_el$141, _el$143);
3745
- _$setProp(_el$141, "flexShrink", 0);
3746
- _$insert(_el$141, () => row.sessions, _el$143);
3747
- _$setProp(_el$144, "flexGrow", 1);
3748
- _$setProp(_el$144, "flexShrink", 1);
3749
- _$setProp(_el$144, "wrapMode", "none");
3750
- _$insert(_el$144, () => prettyDir(row.directory, home));
3757
+ _$insert(_el$140, () => row.sessions, _el$142);
3758
+ _$setProp(_el$143, "flexGrow", 1);
3759
+ _$setProp(_el$143, "flexShrink", 1);
3760
+ _$setProp(_el$143, "wrapMode", "none");
3761
+ _$insert(_el$143, () => prettyDir(row.directory, home));
3751
3762
  _$effect(_p$ => {
3752
3763
  var _v$72 = {
3753
3764
  fg: api.theme.current.success
@@ -3758,23 +3769,23 @@ const tui = async api => {
3758
3769
  _v$74 = {
3759
3770
  fg: api.theme.current.textMuted
3760
3771
  };
3761
- _v$72 !== _p$.e && (_p$.e = _$setProp(_el$139, "style", _v$72, _p$.e));
3762
- _v$73 !== _p$.t && (_p$.t = _$setProp(_el$140, "style", _v$73, _p$.t));
3763
- _v$74 !== _p$.a && (_p$.a = _$setProp(_el$141, "style", _v$74, _p$.a));
3772
+ _v$72 !== _p$.e && (_p$.e = _$setProp(_el$138, "style", _v$72, _p$.e));
3773
+ _v$73 !== _p$.t && (_p$.t = _$setProp(_el$139, "style", _v$73, _p$.t));
3774
+ _v$74 !== _p$.a && (_p$.a = _$setProp(_el$140, "style", _v$74, _p$.a));
3764
3775
  return _p$;
3765
3776
  }, {
3766
3777
  e: undefined,
3767
3778
  t: undefined,
3768
3779
  a: undefined
3769
3780
  });
3770
- return _el$138;
3781
+ return _el$137;
3771
3782
  })()
3772
3783
  });
3773
3784
  }
3774
- }), _el$134);
3775
- _$insertNode(_el$134, _el$135);
3776
- _$setProp(_el$134, "flexShrink", 0);
3777
- _$insertNode(_el$135, _$createTextNode(`esc close`));
3785
+ }), _el$133);
3786
+ _$insertNode(_el$133, _el$134);
3787
+ _$setProp(_el$133, "flexShrink", 0);
3788
+ _$insertNode(_el$134, _$createTextNode(`esc close`));
3778
3789
  _$effect(_p$ => {
3779
3790
  var _v$68 = api.theme.current.backgroundPanel,
3780
3791
  _v$69 = TextAttributes.BOLD,
@@ -3784,10 +3795,10 @@ const tui = async api => {
3784
3795
  _v$71 = {
3785
3796
  fg: api.theme.current.textMuted
3786
3797
  };
3787
- _v$68 !== _p$.e && (_p$.e = _$setProp(_el$128, "backgroundColor", _v$68, _p$.e));
3788
- _v$69 !== _p$.t && (_p$.t = _$setProp(_el$129, "attributes", _v$69, _p$.t));
3789
- _v$70 !== _p$.a && (_p$.a = _$setProp(_el$132, "style", _v$70, _p$.a));
3790
- _v$71 !== _p$.o && (_p$.o = _$setProp(_el$135, "style", _v$71, _p$.o));
3798
+ _v$68 !== _p$.e && (_p$.e = _$setProp(_el$127, "backgroundColor", _v$68, _p$.e));
3799
+ _v$69 !== _p$.t && (_p$.t = _$setProp(_el$128, "attributes", _v$69, _p$.t));
3800
+ _v$70 !== _p$.a && (_p$.a = _$setProp(_el$131, "style", _v$70, _p$.a));
3801
+ _v$71 !== _p$.o && (_p$.o = _$setProp(_el$134, "style", _v$71, _p$.o));
3791
3802
  return _p$;
3792
3803
  }, {
3793
3804
  e: undefined,
@@ -3795,7 +3806,7 @@ const tui = async api => {
3795
3806
  a: undefined,
3796
3807
  o: undefined
3797
3808
  });
3798
- return _el$128;
3809
+ return _el$127;
3799
3810
  })(), () => {
3800
3811
  disposeKeys();
3801
3812
  });
@@ -3904,61 +3915,61 @@ const tui = async api => {
3904
3915
  });
3905
3916
  const home = process.env.HOME ?? "";
3906
3917
  api.ui.dialog.replace(() => (() => {
3907
- var _el$145 = _$createElement("box"),
3908
- _el$146 = _$createElement("text"),
3909
- _el$147 = _$createTextNode(`Needs input `),
3910
- _el$149 = _$createElement("span"),
3911
- _el$150 = _$createTextNode(`(`),
3912
- _el$151 = _$createTextNode(` · longest waiting first)`),
3913
- _el$152 = _$createElement("scrollbox"),
3914
- _el$153 = _$createElement("box"),
3915
- _el$154 = _$createElement("text");
3918
+ var _el$144 = _$createElement("box"),
3919
+ _el$145 = _$createElement("text"),
3920
+ _el$146 = _$createTextNode(`Needs input `),
3921
+ _el$148 = _$createElement("span"),
3922
+ _el$149 = _$createTextNode(`(`),
3923
+ _el$150 = _$createTextNode(` · longest waiting first)`),
3924
+ _el$151 = _$createElement("scrollbox"),
3925
+ _el$152 = _$createElement("box"),
3926
+ _el$153 = _$createElement("text");
3927
+ _$insertNode(_el$144, _el$145);
3928
+ _$insertNode(_el$144, _el$151);
3929
+ _$insertNode(_el$144, _el$152);
3930
+ _$setProp(_el$144, "flexDirection", "column");
3931
+ _$setProp(_el$144, "paddingLeft", 4);
3932
+ _$setProp(_el$144, "paddingRight", 4);
3933
+ _$setProp(_el$144, "paddingTop", 1);
3934
+ _$setProp(_el$144, "gap", 1);
3916
3935
  _$insertNode(_el$145, _el$146);
3917
- _$insertNode(_el$145, _el$152);
3918
- _$insertNode(_el$145, _el$153);
3919
- _$setProp(_el$145, "flexDirection", "column");
3920
- _$setProp(_el$145, "paddingLeft", 4);
3921
- _$setProp(_el$145, "paddingRight", 4);
3922
- _$setProp(_el$145, "paddingTop", 1);
3923
- _$setProp(_el$145, "gap", 1);
3924
- _$insertNode(_el$146, _el$147);
3925
- _$insertNode(_el$146, _el$149);
3926
- _$insertNode(_el$149, _el$150);
3927
- _$insertNode(_el$149, _el$151);
3928
- _$insert(_el$149, () => items.length, _el$151);
3929
- _$setProp(_el$152, "flexGrow", 1);
3930
- _$setProp(_el$152, "scrollbarOptions", {
3936
+ _$insertNode(_el$145, _el$148);
3937
+ _$insertNode(_el$148, _el$149);
3938
+ _$insertNode(_el$148, _el$150);
3939
+ _$insert(_el$148, () => items.length, _el$150);
3940
+ _$setProp(_el$151, "flexGrow", 1);
3941
+ _$setProp(_el$151, "scrollbarOptions", {
3931
3942
  visible: false
3932
3943
  });
3933
- _$insert(_el$152, _$createComponent(For, {
3944
+ _$insert(_el$151, _$createComponent(For, {
3934
3945
  each: items,
3935
3946
  children: (item, index) => (() => {
3936
- var _el$156 = _$createElement("box"),
3947
+ var _el$155 = _$createElement("box"),
3948
+ _el$156 = _$createElement("text"),
3937
3949
  _el$157 = _$createElement("text"),
3938
3950
  _el$158 = _$createElement("text"),
3939
- _el$159 = _$createElement("text"),
3940
- _el$160 = _$createTextNode(` · `);
3941
- _$insertNode(_el$156, _el$157);
3942
- _$insertNode(_el$156, _el$158);
3943
- _$insertNode(_el$156, _el$159);
3944
- _$setProp(_el$156, "flexDirection", "row");
3945
- _$setProp(_el$156, "gap", 2);
3946
- _$setProp(_el$156, "paddingLeft", 1);
3947
- _$setProp(_el$156, "paddingRight", 1);
3948
- _$setProp(_el$156, "onMouseDown", () => {
3951
+ _el$159 = _$createTextNode(` · `);
3952
+ _$insertNode(_el$155, _el$156);
3953
+ _$insertNode(_el$155, _el$157);
3954
+ _$insertNode(_el$155, _el$158);
3955
+ _$setProp(_el$155, "flexDirection", "row");
3956
+ _$setProp(_el$155, "gap", 2);
3957
+ _$setProp(_el$155, "paddingLeft", 1);
3958
+ _$setProp(_el$155, "paddingRight", 1);
3959
+ _$setProp(_el$155, "onMouseDown", () => {
3949
3960
  setCursor(index());
3950
3961
  choose(item);
3951
3962
  });
3952
- _$setProp(_el$157, "flexGrow", 1);
3953
- _$setProp(_el$157, "flexShrink", 1);
3954
- _$setProp(_el$157, "wrapMode", "none");
3955
- _$insert(_el$157, () => truncate(item.entry.title, 48));
3963
+ _$setProp(_el$156, "flexGrow", 1);
3964
+ _$setProp(_el$156, "flexShrink", 1);
3965
+ _$setProp(_el$156, "wrapMode", "none");
3966
+ _$insert(_el$156, () => truncate(item.entry.title, 48));
3967
+ _$setProp(_el$157, "flexShrink", 0);
3968
+ _$insert(_el$157, () => item.reason);
3969
+ _$insertNode(_el$158, _el$159);
3956
3970
  _$setProp(_el$158, "flexShrink", 0);
3957
- _$insert(_el$158, () => item.reason);
3958
- _$insertNode(_el$159, _el$160);
3959
- _$setProp(_el$159, "flexShrink", 0);
3960
- _$insert(_el$159, () => prettyDir(item.entry.dir, home), _el$160);
3961
- _$insert(_el$159, (() => {
3971
+ _$insert(_el$158, () => prettyDir(item.entry.dir, home), _el$159);
3972
+ _$insert(_el$158, (() => {
3962
3973
  var _c$1 = _$memo(() => item.since === undefined);
3963
3974
  return () => _c$1() ? "time unknown" : `waiting ${ago(item.since)}`;
3964
3975
  })(), null);
@@ -3973,10 +3984,10 @@ const tui = async api => {
3973
3984
  _v$83 = {
3974
3985
  fg: index() === cursor() ? api.theme.current.text : api.theme.current.textMuted
3975
3986
  };
3976
- _v$80 !== _p$.e && (_p$.e = _$setProp(_el$156, "backgroundColor", _v$80, _p$.e));
3977
- _v$81 !== _p$.t && (_p$.t = _$setProp(_el$157, "style", _v$81, _p$.t));
3978
- _v$82 !== _p$.a && (_p$.a = _$setProp(_el$158, "style", _v$82, _p$.a));
3979
- _v$83 !== _p$.o && (_p$.o = _$setProp(_el$159, "style", _v$83, _p$.o));
3987
+ _v$80 !== _p$.e && (_p$.e = _$setProp(_el$155, "backgroundColor", _v$80, _p$.e));
3988
+ _v$81 !== _p$.t && (_p$.t = _$setProp(_el$156, "style", _v$81, _p$.t));
3989
+ _v$82 !== _p$.a && (_p$.a = _$setProp(_el$157, "style", _v$82, _p$.a));
3990
+ _v$83 !== _p$.o && (_p$.o = _$setProp(_el$158, "style", _v$83, _p$.o));
3980
3991
  return _p$;
3981
3992
  }, {
3982
3993
  e: undefined,
@@ -3984,12 +3995,12 @@ const tui = async api => {
3984
3995
  a: undefined,
3985
3996
  o: undefined
3986
3997
  });
3987
- return _el$156;
3998
+ return _el$155;
3988
3999
  })()
3989
4000
  }));
3990
- _$insertNode(_el$153, _el$154);
3991
- _$setProp(_el$153, "flexShrink", 0);
3992
- _$insertNode(_el$154, _$createTextNode(`↑↓ navigate · enter open · n open next waiting · esc close`));
4001
+ _$insertNode(_el$152, _el$153);
4002
+ _$setProp(_el$152, "flexShrink", 0);
4003
+ _$insertNode(_el$153, _$createTextNode(`↑↓ navigate · enter open · n open next waiting · esc close`));
3993
4004
  _$effect(_p$ => {
3994
4005
  var _v$75 = api.theme.current.backgroundPanel,
3995
4006
  _v$76 = TextAttributes.BOLD,
@@ -4000,11 +4011,11 @@ const tui = async api => {
4000
4011
  _v$79 = {
4001
4012
  fg: api.theme.current.textMuted
4002
4013
  };
4003
- _v$75 !== _p$.e && (_p$.e = _$setProp(_el$145, "backgroundColor", _v$75, _p$.e));
4004
- _v$76 !== _p$.t && (_p$.t = _$setProp(_el$146, "attributes", _v$76, _p$.t));
4005
- _v$77 !== _p$.a && (_p$.a = _$setProp(_el$149, "style", _v$77, _p$.a));
4006
- _v$78 !== _p$.o && (_p$.o = _$setProp(_el$152, "height", _v$78, _p$.o));
4007
- _v$79 !== _p$.i && (_p$.i = _$setProp(_el$154, "style", _v$79, _p$.i));
4014
+ _v$75 !== _p$.e && (_p$.e = _$setProp(_el$144, "backgroundColor", _v$75, _p$.e));
4015
+ _v$76 !== _p$.t && (_p$.t = _$setProp(_el$145, "attributes", _v$76, _p$.t));
4016
+ _v$77 !== _p$.a && (_p$.a = _$setProp(_el$148, "style", _v$77, _p$.a));
4017
+ _v$78 !== _p$.o && (_p$.o = _$setProp(_el$151, "height", _v$78, _p$.o));
4018
+ _v$79 !== _p$.i && (_p$.i = _$setProp(_el$153, "style", _v$79, _p$.i));
4008
4019
  return _p$;
4009
4020
  }, {
4010
4021
  e: undefined,
@@ -4013,7 +4024,7 @@ const tui = async api => {
4013
4024
  o: undefined,
4014
4025
  i: undefined
4015
4026
  });
4016
- return _el$145;
4027
+ return _el$144;
4017
4028
  })(), () => {
4018
4029
  disposeNav();
4019
4030
  });
@@ -4053,7 +4064,7 @@ const tui = async api => {
4053
4064
  void openNeeds(true);
4054
4065
  }
4055
4066
  }]);
4056
- api.keymap.registerLayer({
4067
+ const disposePickerKey = api.keymap.registerLayer({
4057
4068
  bindings: [{
4058
4069
  key: "alt+o",
4059
4070
  desc: "Pick session",
@@ -4061,6 +4072,7 @@ const tui = async api => {
4061
4072
  cmd: () => void openPicker()
4062
4073
  }]
4063
4074
  });
4075
+ onCleanup(disposePickerKey);
4064
4076
  };
4065
4077
  let hostOwner = null;
4066
4078
  function adaptTheme(theme) {
@@ -4303,6 +4315,7 @@ function createApi(ctx) {
4303
4315
  let cursor;
4304
4316
  const all = [];
4305
4317
  do {
4318
+ if (req.active && !req.active()) break;
4306
4319
  const res = await ctx.client.message.list({
4307
4320
  sessionID: req.sessionID,
4308
4321
  order: req.preview ? "desc" : "asc",