opencode-courier 0.7.2 → 0.7.3

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
@@ -797,7 +797,154 @@ import { createTextNode as _$createTextNode } from "@opentui/solid";
797
797
  import { insertNode as _$insertNode } from "@opentui/solid";
798
798
  import { setProp as _$setProp } from "@opentui/solid";
799
799
  import { createElement as _$createElement } from "@opentui/solid";
800
- import { createEffect, createMemo, createResource, createRoot, createSignal, For, on, onCleanup, onMount, Show, untrack } from "solid-js";
800
+ import { MouseButton, RGBA, Timeline } from "@opentui/core";
801
+ import { batch, createEffect, createMemo, createResource, createRoot, createSignal, For, Index, on, onCleanup, onMount, Show, untrack } from "solid-js";
802
+
803
+ // src/tree/mascot.ts
804
+ var MASCOT_EVERY = 5;
805
+ var BLINK_EVERY = 11;
806
+ var GLYPH = {
807
+ idle: [["........", "........", "..gggg..", "gggggggg"]],
808
+ spawn: [
809
+ ["........", "...bb...", "g.bbbb.g", "gggggggg"],
810
+ [".g....g.", "...bb...", "ggbbbbgg", "gggggggg"]
811
+ ],
812
+ running: [
813
+ ["..g..g..", "...bb...", ".gbbbbg.", "gggggggg"],
814
+ [".g....g.", "........", ".gbbbbg.", "gggggggg"]
815
+ ],
816
+ waiting: [
817
+ [".bbbbbbw", ".bkbbkbw", ".bbaabbm", "ggggggg."],
818
+ [".bbbbbbb", ".bkbbkbb", ".bbaabbm", "ggggggg."]
819
+ ],
820
+ stalled: [
821
+ ["..e.....", ".bbbbbb.", ".bkbbkb.", "gbbaabbg"],
822
+ ["..e.e...", ".bbbbbb.", ".bkbbkb.", "gbbaabbg"],
823
+ ["..e.e.e.", ".bbbbbb.", ".bkbbkb.", "gbbaabbg"]
824
+ ],
825
+ report: [
826
+ ["......aa", "bbbbbbaa", "bkbbkbm.", "bbaabbm."],
827
+ ["s.....aa", "bbbbbbaa", "bkbbkbm.", "bbaabbm."]
828
+ ],
829
+ gone: [["........", ".mmmmmm.", ".mkmmkm.", "mmmmmmmm"]]
830
+ };
831
+ var OPEN_EYES = new Set(["waiting", "report"]);
832
+ function glyph(state, frame) {
833
+ const frames = GLYPH[state];
834
+ const pixels = frames[(frame ?? 0) % frames.length];
835
+ if (frame === undefined)
836
+ return pixels;
837
+ if (state === "idle" && breathesOut(frame))
838
+ return [...pixels.slice(0, 2), ".gggggg.", ...pixels.slice(3)];
839
+ return OPEN_EYES.has(state) && blinks(frame) ? pixels.map((row) => row.replaceAll("k", "b")) : pixels;
840
+ }
841
+ var breathesOut = (frame) => Math.floor(frame / 2) % 2 === 1;
842
+ var blinks = (frame) => frame % BLINK_EVERY === BLINK_EVERY - 1;
843
+ function cells(pixels) {
844
+ const lines = [];
845
+ for (let row = 0;row < pixels.length; row += 2) {
846
+ const top = pixels[row];
847
+ const bottom = pixels[row + 1] ?? "";
848
+ lines.push([...top].map((pixel, column) => cell(token(pixel), token(bottom[column]))));
849
+ }
850
+ return lines;
851
+ }
852
+ var token = (pixel) => pixel && pixel !== "." ? pixel : undefined;
853
+ function cell(top, bottom) {
854
+ if (!top && !bottom)
855
+ return { char: " " };
856
+ if (!top)
857
+ return { char: "\u2584", fg: bottom };
858
+ if (top === bottom)
859
+ return { char: "\u2588", fg: top };
860
+ return bottom ? { char: "\u2580", fg: top, bg: bottom } : { char: "\u2580", fg: top };
861
+ }
862
+ var SIZE = 16;
863
+ var SLUMP = [2, 2, 2, 1, 1, 0, 0];
864
+ function digby(rise, { top = 6, eyes = "open", slump = false, shift = 0, mound = "g" } = {}) {
865
+ const grid = Array.from({ length: SIZE }, () => new Array(SIZE).fill("."));
866
+ const span = (row, width, pixel, skip = (_column) => false, by = 0) => {
867
+ if (row < 0 || row >= SIZE)
868
+ return;
869
+ for (let column = (SIZE - width) / 2;column < (SIZE + width) / 2; column++)
870
+ if (!skip(column))
871
+ grid[row][column + by] = pixel;
872
+ };
873
+ const head = Math.round(10 - 8 * rise);
874
+ const lean = (at) => slump ? SLUMP[at] : 0;
875
+ [4, 6, 8, 8, 8, 6, 4].forEach((width, at) => span(head + at, width, "b", undefined, lean(at)));
876
+ for (let row = head + 7;row <= 11; row++)
877
+ span(row, 4, "b");
878
+ const eyeColumns = eyes === "shut" ? [5, 6, 9, 10] : [6, 9];
879
+ if (eyes !== "none")
880
+ span(head + 3, 8, "k", (column) => !eyeColumns.includes(column), lean(3));
881
+ if (eyes === "wide")
882
+ span(head + 2, 8, "k", (column) => !eyeColumns.includes(column), lean(2));
883
+ span(head + 4, 2, "a", undefined, lean(4));
884
+ span(10, SIZE, ".", (column) => column >= 6 && column <= 9);
885
+ span(10, top, mound, (column) => column >= 6 && column <= 9, shift);
886
+ span(11, 10, mound, undefined, shift);
887
+ span(12, 12, mound, undefined, shift);
888
+ for (const row of [13, 14, 15])
889
+ span(row, SIZE, mound);
890
+ return grid.map((row) => row.join(""));
891
+ }
892
+ function paint(pixels, spots) {
893
+ const grid = pixels.map((row) => [...row]);
894
+ for (const [row, column, drawn] of spots)
895
+ [...drawn].forEach((pixel, at) => {
896
+ if (pixel !== "." && grid[row]?.[column + at] !== undefined)
897
+ grid[row][column + at] = pixel;
898
+ });
899
+ return grid.map((row) => row.join(""));
900
+ }
901
+ var post = (row, column, length, pixel) => Array.from({ length }, (_, at) => [row + at, column, pixel]);
902
+ var headTop = (rise) => Math.round(10 - 8 * rise);
903
+ var running = (rise, shift, dirt) => paint(digby(rise, { shift }), [[headTop(rise), 7, "aa"], ...dirt]);
904
+ var peek = (column, up) => [
905
+ ...up ? [[8, column, ".b."], [9, column, "bkb"]] : [[9, column, ".b."]],
906
+ [10, column, "gbg"],
907
+ [11, column, "ggg"]
908
+ ];
909
+ var spawn = (up, dirt) => paint(digby(0.1), [...peek(0, up), ...peek(13, up), [12, 0, "gg"], [12, 14, "gg"], ...dirt]);
910
+ var sign = (shown) => [...shown ? [[2, 13, "www"], [3, 13, "wkw"], [4, 13, "www"]] : [], ...post(5, 14, 7, "m")];
911
+ var waiting = (shown) => (open) => paint(digby(1, { eyes: open ? "wide" : "none" }), [[8, 4, "mm"], [8, 10, "mm"], ...sign(shown)]);
912
+ var stalled = (dots) => () => paint(digby(0.7, { eyes: "shut", slump: true }), [[5, 0, dots]]);
913
+ var report = (rise, spark) => (open) => paint(digby(rise, { eyes: open ? "open" : "none" }), [
914
+ [0, 12, "aaaa"],
915
+ [1, 12, "akka"],
916
+ [2, 12, "aaaa"],
917
+ ...post(3, 13, 8, "m"),
918
+ ...spark.map((row, at) => [1 + at, 0, row])
919
+ ]);
920
+ var ART = {
921
+ spawn: [
922
+ () => spawn(true, [[3, 1, "m"], [5, 3, "m"], [2, 14, "m"], [5, 12, "m"]]),
923
+ () => spawn(false, [[1, 0, "m"], [4, 2, "m"], [3, 15, "m"], [6, 13, "m"]])
924
+ ],
925
+ running: [
926
+ () => running(0.22, 0, [[5, 2, "m"], [7, 1, "m"], [4, 13, "m"], [6, 14, "m"]]),
927
+ () => running(0.12, 1, [[3, 1, "m"], [6, 3, "m"], [5, 12, "m"], [3, 15, "m"]])
928
+ ],
929
+ waiting: [waiting(true), waiting(false)],
930
+ stalled: [stalled("e.e.e"), stalled("e"), stalled("e.e")],
931
+ report: [report(1, [".s.", "sss", ".s."]), report(1.25, ["s.s", ".s.", "s.s"]), report(1.1, [".s.", "sss", ".s."])],
932
+ gone: [() => digby(-0.3, { mound: "m" })]
933
+ };
934
+ var Z_LINES = [3, 2, 1, undefined];
935
+ function idleArt(frame) {
936
+ const lines = cells(digby(-0.3, { top: frame !== undefined && breathesOut(frame) ? 8 : 6 }));
937
+ const line = Z_LINES[(frame ?? 0) % Z_LINES.length];
938
+ if (line === undefined)
939
+ return lines;
940
+ return lines.map((cellsOf, at) => at === line ? cellsOf.map((one, column) => column === 13 ? { char: "z", fg: "m" } : one) : cellsOf);
941
+ }
942
+ function art(state, frame) {
943
+ if (state === "idle")
944
+ return idleArt(frame);
945
+ const frames = ART[state];
946
+ return cells(frames[(frame ?? 0) % frames.length](!(frame !== undefined && OPEN_EYES.has(state) && blinks(frame))));
947
+ }
801
948
 
802
949
  // src/tree/rpc.ts
803
950
  import { Rpc as Rpc2 } from "@opencode/plugin/rpc";
@@ -831,6 +978,7 @@ var Row = Schema2.Struct({
831
978
  created: Schema2.Number,
832
979
  idle: Schema2.optionalKey(Schema2.Number),
833
980
  cost: Schema2.optionalKey(Schema2.Number),
981
+ context: Schema2.optionalKey(Schema2.Number),
834
982
  tool: Schema2.optionalKey(Schema2.Struct({ name: Schema2.String, at: Schema2.Number })),
835
983
  waits: Schema2.Array(Wait)
836
984
  });
@@ -879,6 +1027,176 @@ var SETTLE_MS2 = 250;
879
1027
  var PANEL_SETTLE_MS = 1000;
880
1028
  var PANEL = "courier-tree";
881
1029
  var TICK_MS = 1000;
1030
+ var FRAME_MS = 90;
1031
+ var FLASH_MS = 1500;
1032
+ var BAR_MS = 450;
1033
+ function animationsOn(options) {
1034
+ return options?.animations !== false;
1035
+ }
1036
+ function createMotion(enabled) {
1037
+ const [frame, setFrame] = createSignal(0);
1038
+ const [keepers, setKeepers] = createSignal([]);
1039
+ const [moving, setMoving] = createSignal([]);
1040
+ const cadence = createMemo(() => {
1041
+ if (!enabled)
1042
+ return;
1043
+ if (moving().length)
1044
+ return 1;
1045
+ const wanted = keepers().filter((one) => one.when());
1046
+ return wanted.length ? Math.min(...wanted.map((one) => one.every)) : undefined;
1047
+ });
1048
+ createEffect(() => {
1049
+ const every = cadence();
1050
+ if (every === undefined)
1051
+ return;
1052
+ const timer = setInterval(() => batch(() => {
1053
+ const now = untrack(moving);
1054
+ for (const one of now)
1055
+ one.step(FRAME_MS * every);
1056
+ setFrame((count) => count + every);
1057
+ const left = now.filter((one) => !one.done());
1058
+ if (left.length !== now.length)
1059
+ setMoving(left);
1060
+ }), FRAME_MS * every);
1061
+ onCleanup(() => clearInterval(timer));
1062
+ });
1063
+ const tween = (from, to, duration, ease) => {
1064
+ if (!enabled || from === to)
1065
+ return {
1066
+ value: () => to,
1067
+ done: () => true
1068
+ };
1069
+ const target = {
1070
+ value: from
1071
+ };
1072
+ const timeline = new Timeline({
1073
+ duration,
1074
+ autoplay: false
1075
+ });
1076
+ timeline.add(target, {
1077
+ duration,
1078
+ ease,
1079
+ value: to
1080
+ });
1081
+ timeline.play();
1082
+ let elapsed = 0;
1083
+ const one = {
1084
+ value: () => {
1085
+ frame();
1086
+ return target.value;
1087
+ },
1088
+ done: () => {
1089
+ frame();
1090
+ return elapsed >= duration;
1091
+ },
1092
+ step: (ms) => {
1093
+ elapsed += ms;
1094
+ timeline.update(ms);
1095
+ }
1096
+ };
1097
+ setMoving((all) => [...all, one]);
1098
+ return one;
1099
+ };
1100
+ return {
1101
+ enabled,
1102
+ frame,
1103
+ animates: (when, every = 1) => setKeepers((all) => [...all, {
1104
+ when,
1105
+ every
1106
+ }]),
1107
+ tween
1108
+ };
1109
+ }
1110
+ function createFlashes(motion, rows) {
1111
+ const [flashes, setFlashes] = createSignal(new Map);
1112
+ let seen;
1113
+ createEffect(() => {
1114
+ const read = rows();
1115
+ const before = seen;
1116
+ seen = new Map(read.map((row) => [row.sessionID, row.report?.state]));
1117
+ if (!before || !motion.enabled)
1118
+ return;
1119
+ const arrived = read.filter((row) => row.report?.state === "reported" && before.has(row.sessionID) && before.get(row.sessionID) !== "reported");
1120
+ if (!arrived.length)
1121
+ return;
1122
+ const next = new Map([...untrack(flashes)].filter(([, one]) => !untrack(one.done)));
1123
+ for (const row of arrived)
1124
+ next.set(row.sessionID, motion.tween(1, 0, FLASH_MS, "outQuad"));
1125
+ setFlashes(next);
1126
+ });
1127
+ const strength = (sessionID) => {
1128
+ const one = flashes().get(sessionID);
1129
+ return one && !one.done() ? one.value() : 0;
1130
+ };
1131
+ const reported = () => [...flashes().values()].some((one) => !one.done());
1132
+ return {
1133
+ strength,
1134
+ reported
1135
+ };
1136
+ }
1137
+ function createBarFill(motion, counts) {
1138
+ const target = createMemo(() => filledCells(counts()));
1139
+ const [easing, setEasing] = createSignal();
1140
+ let last;
1141
+ createEffect(() => {
1142
+ const cells2 = target();
1143
+ const shown = counts().started > 0;
1144
+ if (last && cells2 !== last.cells) {
1145
+ const from = untrack(() => easing()?.value()) ?? last.cells;
1146
+ setEasing(last.shown ? motion.tween(from, cells2, BAR_MS, "outQuad") : undefined);
1147
+ }
1148
+ last = {
1149
+ cells: cells2,
1150
+ shown
1151
+ };
1152
+ });
1153
+ return () => easing()?.value() ?? target();
1154
+ }
1155
+ function createSpawns(motion, rows) {
1156
+ const [hold, setHold] = createSignal();
1157
+ let seen;
1158
+ createEffect(() => {
1159
+ const read = rows();
1160
+ if (!read)
1161
+ return;
1162
+ const before = seen;
1163
+ seen = new Set(read.map((row) => row.sessionID));
1164
+ if (before && motion.enabled && read.some((row) => !before.has(row.sessionID)))
1165
+ setHold(motion.tween(1, 0, FLASH_MS, "linear"));
1166
+ });
1167
+ return () => {
1168
+ const one = hold();
1169
+ return one !== undefined && !one.done();
1170
+ };
1171
+ }
1172
+ function mascotState(rows, {
1173
+ reported = false,
1174
+ spawned = false
1175
+ } = {}) {
1176
+ if (reported)
1177
+ return "report";
1178
+ if (spawned)
1179
+ return "spawn";
1180
+ if (rows.some((row) => row.state === "waiting"))
1181
+ return "waiting";
1182
+ if (rows.some((row) => row.state === "stalled"))
1183
+ return "stalled";
1184
+ if (rows.some((row) => row.state === "running"))
1185
+ return "running";
1186
+ return rows.length && rows.every((row) => row.state === "gone") ? "gone" : "idle";
1187
+ }
1188
+ function countsLine(rows) {
1189
+ const count = (state) => rows.filter((row) => row.state === state).length;
1190
+ return [count("waiting") ? `${count("waiting")} waiting on you` : "", count("stalled") ? `${count("stalled")} stalled` : "", count("running") ? `${count("running")} running` : "", count("idle") ? `${count("idle")} idle` : ""].filter(Boolean).join(" \xB7 ");
1191
+ }
1192
+ var GLYPH_ROWS = 12;
1193
+ var GLYPH_COLUMNS = 54;
1194
+ var ART_ROWS = 14;
1195
+ var BELOW_ROWS = 10;
1196
+ function blend(tint, rest, amount) {
1197
+ const mix = (a, b) => b + (a - b) * amount;
1198
+ return RGBA.fromValues(mix(tint.r, rest.r), mix(tint.g, rest.g), mix(tint.b, rest.b), mix(tint.a, rest.a));
1199
+ }
882
1200
  function summaryLine(summary, maxWidth = Infinity) {
883
1201
  const groups = summary.groups.map((group) => `group ${group.name} ${group.reported}/${group.members}`);
884
1202
  const parts = [summary.waiting ? `${summary.waiting} waiting on you` : "", summary.stalled ? `${summary.stalled} stalled` : "", summary.running ? `${summary.running} running` : "", ...groups, summary.idle ? `${summary.idle} idle` : ""].filter(Boolean);
@@ -909,12 +1227,15 @@ function parts(rows, parentID) {
909
1227
  started: children.length
910
1228
  };
911
1229
  }
912
- function bar({
1230
+ function filledCells({
913
1231
  reported,
914
1232
  started
915
1233
  }, width = 10) {
916
- const filled = started ? Math.round(reported / started * width) : 0;
917
- return `[${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}] ${reported}/${started} reported`;
1234
+ return started ? Math.round(reported / started * width) : 0;
1235
+ }
1236
+ function bar(counts, width = 10, filled = filledCells(counts, width)) {
1237
+ const cells2 = Math.max(0, Math.min(width, Math.round(filled)));
1238
+ return `[${"\u2588".repeat(cells2)}${"\u2591".repeat(width - cells2)}] ${counts.reported}/${counts.started} reported`;
918
1239
  }
919
1240
  function waitLine(wait) {
920
1241
  if (wait.type === "permission")
@@ -922,7 +1243,66 @@ function waitLine(wait) {
922
1243
  return wait.type === "form" ? `shows a form: ${wait.title}` : `asks: ${wait.question}`;
923
1244
  }
924
1245
  function statusLine(row) {
925
- return [stateWord(row), reportWords(row.report, row.stopped), row.group ? `group ${row.group.name} ${row.group.standing}` : "", row.isolated ? "isolated" : ""].filter(Boolean).join(" \xB7 ");
1246
+ return statusParts(row).map((part) => part.text).join(" \xB7 ");
1247
+ }
1248
+ function statusParts(row) {
1249
+ const parts2 = [{
1250
+ text: stateWord(row),
1251
+ kind: "state"
1252
+ }, {
1253
+ text: reportWords(row.report, row.stopped),
1254
+ kind: "report"
1255
+ }, {
1256
+ text: row.group ? `group ${row.group.name} ${row.group.standing}` : "",
1257
+ kind: "plain"
1258
+ }, {
1259
+ text: row.isolated ? "isolated" : "",
1260
+ kind: "plain"
1261
+ }];
1262
+ return parts2.filter((part) => part.text);
1263
+ }
1264
+ var SPINNER = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
1265
+ function rowMark(row, theme, frame) {
1266
+ const {
1267
+ error,
1268
+ warning,
1269
+ success,
1270
+ info
1271
+ } = theme.text.feedback;
1272
+ if (row.state === "gone")
1273
+ return {
1274
+ mark: " ",
1275
+ color: undefined
1276
+ };
1277
+ if (row.state === "stalled")
1278
+ return {
1279
+ mark: "!",
1280
+ color: error.base
1281
+ };
1282
+ if (row.state === "waiting")
1283
+ return {
1284
+ mark: "\u25CF",
1285
+ color: warning.base
1286
+ };
1287
+ if (row.state === "running")
1288
+ return {
1289
+ mark: frame === undefined ? "\u2022" : SPINNER[frame % SPINNER.length],
1290
+ color: info.base
1291
+ };
1292
+ if (!row.stopped && (row.outcome === "failed" || row.outcome === "interrupted"))
1293
+ return {
1294
+ mark: "\u2717",
1295
+ color: error.base
1296
+ };
1297
+ if (row.report?.state === "reported")
1298
+ return {
1299
+ mark: "\u2713",
1300
+ color: success.base
1301
+ };
1302
+ return {
1303
+ mark: " ",
1304
+ color: undefined
1305
+ };
926
1306
  }
927
1307
  function stateWord(row) {
928
1308
  if (row.state === "waiting")
@@ -935,19 +1315,21 @@ function stateWord(row) {
935
1315
  return row.outcome;
936
1316
  return row.state;
937
1317
  }
938
- function reportWords(report, stopped) {
939
- if (!report)
1318
+ function reportWords(report2, stopped) {
1319
+ if (!report2)
940
1320
  return "";
941
- if (report.state === "owed")
1321
+ if (report2.state === "owed")
942
1322
  return "owes a report";
943
- if (report.state === "ended")
1323
+ if (report2.state === "ended")
944
1324
  return stopped ? "" : "ended without a report";
945
- return ["reported", report.status].filter(Boolean).join(" ");
1325
+ return ["reported", report2.status].filter(Boolean).join(" ");
946
1326
  }
947
1327
  var counted = (count, noun) => `${count} ${noun}${count === 1 ? "" : "s"}`;
948
- function activityLine(row, now) {
949
- return [`ran ${duration((row.idle ?? now) - row.created)}`, row.tool ? `last ${row.tool.name} ${duration(now - row.tool.at)} ago` : "no tool call yet", row.cost !== undefined ? `$${row.cost.toFixed(2)}` : ""].filter(Boolean).join(" \xB7 ");
1328
+ var CONTEXT_WARN = 0.8;
1329
+ function activityParts(row, now) {
1330
+ return [`ran ${duration((row.idle ?? now) - row.created)}`, row.tool ? `last ${row.tool.name} ${duration(now - row.tool.at)} ago` : "no tool call yet", row.context !== undefined ? `ctx ${Math.round(row.context * 100)}%` : "", row.cost !== undefined ? `$${row.cost.toFixed(2)}` : ""].filter(Boolean);
950
1331
  }
1332
+ var activityLine = (row, now) => activityParts(row, now).join(" \xB7 ");
951
1333
  function stalledLine(since, now) {
952
1334
  return `a message waits in its inbox since ${duration(now - since)}, woken again in vain`;
953
1335
  }
@@ -1153,6 +1535,24 @@ async function confirmForget(ctx, courier, location, by, target, done) {
1153
1535
  var FOCUS_PROMPT = "pane.focus.left";
1154
1536
  var SPLIT_WIDTH = 108;
1155
1537
  var oneLine = (title) => title.replace(/[\r\n]+/g, " ");
1538
+ var digbyColours = (theme) => ({
1539
+ b: theme.text.base,
1540
+ k: theme.background.base,
1541
+ g: theme.background.raised.max,
1542
+ m: theme.text.muted,
1543
+ a: theme.text.action.primary.selected,
1544
+ w: theme.text.feedback.warning.base,
1545
+ e: theme.text.feedback.error.base,
1546
+ s: theme.text.feedback.success.base
1547
+ });
1548
+ function restBackground(theme, {
1549
+ selected,
1550
+ hovered
1551
+ }) {
1552
+ if (selected)
1553
+ return theme.background.raised.high;
1554
+ return hovered ? theme.background.raised.base : undefined;
1555
+ }
1156
1556
  function TreePanel(props) {
1157
1557
  const {
1158
1558
  ctx,
@@ -1246,13 +1646,25 @@ function TreePanel(props) {
1246
1646
  if (next)
1247
1647
  setSelectedID(next.sessionID);
1248
1648
  };
1649
+ const openRow = (row) => ctx.ui.router.navigate({
1650
+ type: "session",
1651
+ sessionID: row.sessionID
1652
+ });
1249
1653
  const open = () => {
1250
1654
  const row = current();
1251
1655
  if (row)
1252
- ctx.ui.router.navigate({
1253
- type: "session",
1254
- sessionID: row.sessionID
1255
- });
1656
+ openRow(row);
1657
+ };
1658
+ const [hovered, setHovered] = createSignal();
1659
+ createEffect(() => {
1660
+ const id = hovered();
1661
+ if (id !== undefined && !rows().some((row) => row.sessionID === id))
1662
+ setHovered(undefined);
1663
+ });
1664
+ let pressed;
1665
+ const click = (row) => {
1666
+ setSelectedID(row.sessionID);
1667
+ openRow(row);
1256
1668
  };
1257
1669
  const stopSelected = () => {
1258
1670
  const row = current();
@@ -1335,6 +1747,61 @@ function TreePanel(props) {
1335
1747
  }]
1336
1748
  }));
1337
1749
  const root = () => parts(rows(), view.root);
1750
+ const motion = createMotion(props.animations);
1751
+ motion.animates(() => rows().some((row) => row.state === "running"));
1752
+ const flashes = createFlashes(motion, rows);
1753
+ const filled = createBarFill(motion, root);
1754
+ const frame = () => motion.enabled ? motion.frame() : undefined;
1755
+ const spawned = createSpawns(motion, () => latest()?.tree?.rows);
1756
+ const [size, setSize] = createSignal({
1757
+ width: 0,
1758
+ height: 0
1759
+ });
1760
+ const height = () => size().height;
1761
+ const empty = () => Boolean(latest()?.tree && !rows().length);
1762
+ const glyphShown = () => height() >= GLYPH_ROWS && size().width >= GLYPH_COLUMNS;
1763
+ const artShown = () => empty() && height() >= ART_ROWS;
1764
+ const [listHeight, setListHeight] = createSignal(0);
1765
+ const treeLines = () => rows().reduce((lines, row) => lines + 1 + detailLines(row, rows(), now()).length, 0);
1766
+ const belowShown = () => rows().length > 0 && listHeight() - treeLines() >= BELOW_ROWS;
1767
+ const headerGlyph = () => glyphShown() && !artShown() && !belowShown();
1768
+ const mascot = createMemo(() => mascotState(rows(), {
1769
+ reported: flashes.reported(),
1770
+ spawned: spawned()
1771
+ }));
1772
+ motion.animates(() => (glyphShown() || artShown() || belowShown()) && mascot() !== "gone", MASCOT_EVERY);
1773
+ const mascotFrame = () => motion.enabled ? Math.floor(motion.frame() / MASCOT_EVERY) : undefined;
1774
+ const header = createMemo(() => cells(glyph(mascot(), mascotFrame())));
1775
+ const art2 = createMemo(() => art(mascot(), mascotFrame()));
1776
+ const tokens = digbyColours(theme);
1777
+ const drawn = (line) => (() => {
1778
+ var _el$4 = _$createElement("text");
1779
+ _$setProp(_el$4, "wrapMode", "none");
1780
+ _$setProp(_el$4, "flexShrink", 0);
1781
+ _$insert(_el$4, _$createComponent(Index, {
1782
+ get each() {
1783
+ return line();
1784
+ },
1785
+ children: (one) => (() => {
1786
+ var _el$5 = _$createElement("span");
1787
+ _$insert(_el$5, () => one().char);
1788
+ _$effect((_$p) => _$setProp(_el$5, "style", {
1789
+ fg: one().fg && tokens[one().fg],
1790
+ bg: one().bg && tokens[one().bg]
1791
+ }, _$p));
1792
+ return _el$5;
1793
+ })()
1794
+ }));
1795
+ return _el$4;
1796
+ })();
1797
+ const rowBackground = (row, chosen) => {
1798
+ const rest = restBackground(theme, {
1799
+ selected: chosen && input.focused,
1800
+ hovered: hovered() === row.sessionID
1801
+ });
1802
+ const strength = flashes.strength(row.sessionID);
1803
+ return strength > 0 ? blend(theme.background.feedback.success.base, rest ?? theme.background.base, strength) : rest;
1804
+ };
1338
1805
  const rowColor = (row) => {
1339
1806
  if (row.state === "stalled")
1340
1807
  return theme.text.feedback.error.base;
@@ -1342,84 +1809,153 @@ function TreePanel(props) {
1342
1809
  return theme.text.feedback.warning.base;
1343
1810
  return row.state === "gone" ? theme.text.muted : theme.text.base;
1344
1811
  };
1812
+ const partColor = (row, kind) => {
1813
+ const marked = rowMark(row, theme);
1814
+ if (kind === "state" && row.state === "running")
1815
+ return marked.color;
1816
+ if (kind === "report" && row.report?.state === "reported")
1817
+ return theme.text.feedback.success.base;
1818
+ return theme.text.muted;
1819
+ };
1345
1820
  return (() => {
1346
- var _el$4 = _$createElement("box"), _el$5 = _$createElement("box"), _el$6 = _$createElement("text"), _el$15 = _$createElement("scrollbox"), _el$16 = _$createElement("text");
1347
- _$insertNode(_el$4, _el$5);
1348
- _$insertNode(_el$4, _el$15);
1349
- _$insertNode(_el$4, _el$16);
1350
- _$setProp(_el$4, "flexDirection", "column");
1351
- _$setProp(_el$4, "flexGrow", 1);
1352
- _$setProp(_el$4, "paddingLeft", 1);
1353
- _$setProp(_el$4, "paddingRight", 1);
1354
- _$insertNode(_el$5, _el$6);
1355
- _$setProp(_el$5, "flexDirection", "row");
1356
- _$setProp(_el$5, "flexShrink", 0);
1357
- _$setProp(_el$5, "gap", 2);
1358
- _$insertNode(_el$6, _$createTextNode(`courier tree`));
1359
- _$setProp(_el$6, "wrapMode", "none");
1360
- _$insert(_el$5, _$createComponent(Show, {
1821
+ var _el$6 = _$createElement("box"), _el$7 = _$createElement("box"), _el$8 = _$createElement("text"), _el$20 = _$createElement("scrollbox"), _el$22 = _$createElement("text");
1822
+ _$insertNode(_el$6, _el$7);
1823
+ _$insertNode(_el$6, _el$20);
1824
+ _$insertNode(_el$6, _el$22);
1825
+ _$setProp(_el$6, "flexDirection", "column");
1826
+ _$setProp(_el$6, "flexGrow", 1);
1827
+ _$setProp(_el$6, "paddingLeft", 1);
1828
+ _$setProp(_el$6, "paddingRight", 1);
1829
+ _$setProp(_el$6, "onSizeChange", function() {
1830
+ setSize({
1831
+ width: this.width,
1832
+ height: this.height
1833
+ });
1834
+ });
1835
+ _$setProp(_el$6, "onMouseDrag", () => pressed = undefined);
1836
+ _$insertNode(_el$7, _el$8);
1837
+ _$setProp(_el$7, "flexDirection", "row");
1838
+ _$setProp(_el$7, "flexShrink", 0);
1839
+ _$setProp(_el$7, "gap", 2);
1840
+ _$insert(_el$7, _$createComponent(Show, {
1841
+ get when() {
1842
+ return headerGlyph();
1843
+ },
1844
+ get children() {
1845
+ return drawn(() => header()[0]);
1846
+ }
1847
+ }), _el$8);
1848
+ _$insertNode(_el$8, _$createTextNode(`courier tree`));
1849
+ _$setProp(_el$8, "wrapMode", "none");
1850
+ _$insert(_el$7, _$createComponent(Show, {
1361
1851
  get when() {
1362
1852
  return root().started;
1363
1853
  },
1364
1854
  get children() {
1365
- var _el$8 = _$createElement("text");
1366
- _$setProp(_el$8, "wrapMode", "none");
1367
- _$insert(_el$8, () => bar(root()));
1368
- _$effect((_$p) => _$setProp(_el$8, "fg", theme.text.muted, _$p));
1369
- return _el$8;
1855
+ var _el$0 = _$createElement("text");
1856
+ _$setProp(_el$0, "wrapMode", "none");
1857
+ _$insert(_el$0, () => bar(root(), 10, filled()));
1858
+ _$effect((_$p) => _$setProp(_el$0, "fg", tokens.a, _$p));
1859
+ return _el$0;
1370
1860
  }
1371
1861
  }), null);
1372
- _$insert(_el$5, _$createComponent(Show, {
1862
+ _$insert(_el$7, _$createComponent(Show, {
1373
1863
  get when() {
1374
1864
  return latest()?.tree?.truncated;
1375
1865
  },
1376
1866
  get children() {
1377
- var _el$9 = _$createElement("text"), _el$0 = _$createTextNode(` older left out`);
1378
- _$insertNode(_el$9, _el$0);
1379
- _$setProp(_el$9, "wrapMode", "none");
1380
- _$insert(_el$9, () => latest()?.tree?.truncated, _el$0);
1381
- _$effect((_$p) => _$setProp(_el$9, "fg", theme.text.feedback.warning.base, _$p));
1382
- return _el$9;
1867
+ var _el$1 = _$createElement("text"), _el$10 = _$createTextNode(` older left out`);
1868
+ _$insertNode(_el$1, _el$10);
1869
+ _$setProp(_el$1, "wrapMode", "none");
1870
+ _$insert(_el$1, () => latest()?.tree?.truncated, _el$10);
1871
+ _$effect((_$p) => _$setProp(_el$1, "fg", theme.text.feedback.warning.base, _$p));
1872
+ return _el$1;
1383
1873
  }
1384
1874
  }), null);
1385
- _$insert(_el$4, _$createComponent(Show, {
1875
+ _$insert(_el$6, _$createComponent(Show, {
1876
+ get when() {
1877
+ return glyphShown();
1878
+ },
1879
+ get children() {
1880
+ var _el$11 = _$createElement("box"), _el$12 = _$createElement("text");
1881
+ _$insertNode(_el$11, _el$12);
1882
+ _$setProp(_el$11, "flexDirection", "row");
1883
+ _$setProp(_el$11, "flexShrink", 0);
1884
+ _$setProp(_el$11, "gap", 2);
1885
+ _$insert(_el$11, _$createComponent(Show, {
1886
+ get when() {
1887
+ return headerGlyph();
1888
+ },
1889
+ get children() {
1890
+ return drawn(() => header()[1]);
1891
+ }
1892
+ }), _el$12);
1893
+ _$setProp(_el$12, "wrapMode", "none");
1894
+ _$insert(_el$12, () => countsLine(rows()));
1895
+ _$effect((_$p) => _$setProp(_el$12, "fg", theme.text.muted, _$p));
1896
+ return _el$11;
1897
+ }
1898
+ }), _el$20);
1899
+ _$insert(_el$6, _$createComponent(Show, {
1386
1900
  get when() {
1387
1901
  return latest()?.error;
1388
1902
  },
1389
1903
  get children() {
1390
- var _el$1 = _$createElement("text"), _el$10 = _$createTextNode(`courier RPC failed: `);
1391
- _$insertNode(_el$1, _el$10);
1392
- _$insert(_el$1, () => latest()?.error, null);
1393
- _$effect((_$p) => _$setProp(_el$1, "fg", theme.text.feedback.error.base, _$p));
1394
- return _el$1;
1904
+ var _el$13 = _$createElement("text"), _el$14 = _$createTextNode(`courier RPC failed: `);
1905
+ _$insertNode(_el$13, _el$14);
1906
+ _$insert(_el$13, () => latest()?.error, null);
1907
+ _$effect((_$p) => _$setProp(_el$13, "fg", theme.text.feedback.error.base, _$p));
1908
+ return _el$13;
1395
1909
  }
1396
- }), _el$15);
1397
- _$insert(_el$4, _$createComponent(Show, {
1910
+ }), _el$20);
1911
+ _$insert(_el$6, _$createComponent(Show, {
1398
1912
  get when() {
1399
1913
  return latest()?.tree?.stalled;
1400
1914
  },
1401
1915
  get children() {
1402
- var _el$11 = _$createElement("text"), _el$12 = _$createTextNode(`This session is stalled: `);
1403
- _$insertNode(_el$11, _el$12);
1404
- _$insert(_el$11, () => stalledLine(latest().tree.stalled, now()), null);
1405
- _$effect((_$p) => _$setProp(_el$11, "fg", theme.text.feedback.error.base, _$p));
1406
- return _el$11;
1916
+ var _el$15 = _$createElement("text"), _el$16 = _$createTextNode(`This session is stalled: `);
1917
+ _$insertNode(_el$15, _el$16);
1918
+ _$insert(_el$15, () => stalledLine(latest().tree.stalled, now()), null);
1919
+ _$effect((_$p) => _$setProp(_el$15, "fg", theme.text.feedback.error.base, _$p));
1920
+ return _el$15;
1407
1921
  }
1408
- }), _el$15);
1409
- _$insert(_el$4, _$createComponent(Show, {
1922
+ }), _el$20);
1923
+ _$insert(_el$6, _$createComponent(Show, {
1410
1924
  get when() {
1411
1925
  return _$memo(() => !!latest()?.tree)() && !rows().length;
1412
1926
  },
1413
1927
  get children() {
1414
- var _el$13 = _$createElement("text");
1415
- _$insertNode(_el$13, _$createTextNode(`No session started with courier_spawn under this one.`));
1416
- _$effect((_$p) => _$setProp(_el$13, "fg", theme.text.muted, _$p));
1417
- return _el$13;
1928
+ return [(() => {
1929
+ var _el$17 = _$createElement("text");
1930
+ _$insertNode(_el$17, _$createTextNode(`No session started with courier_spawn under this one.`));
1931
+ _$effect((_$p) => _$setProp(_el$17, "fg", theme.text.muted, _$p));
1932
+ return _el$17;
1933
+ })(), _$createComponent(Show, {
1934
+ get when() {
1935
+ return artShown();
1936
+ },
1937
+ get children() {
1938
+ var _el$19 = _$createElement("box");
1939
+ _$setProp(_el$19, "flexDirection", "column");
1940
+ _$setProp(_el$19, "flexShrink", 0);
1941
+ _$setProp(_el$19, "paddingTop", 1);
1942
+ _$insert(_el$19, _$createComponent(Index, {
1943
+ get each() {
1944
+ return art2();
1945
+ },
1946
+ children: (line) => drawn(line)
1947
+ }));
1948
+ return _el$19;
1949
+ }
1950
+ })];
1418
1951
  }
1419
- }), _el$15);
1420
- _$use((value) => scroll = value, _el$15);
1421
- _$setProp(_el$15, "flexGrow", 1);
1422
- _$insert(_el$15, _$createComponent(For, {
1952
+ }), _el$20);
1953
+ _$use((value) => scroll = value, _el$20);
1954
+ _$setProp(_el$20, "flexGrow", 1);
1955
+ _$setProp(_el$20, "onSizeChange", function() {
1956
+ setListHeight(this.height);
1957
+ });
1958
+ _$insert(_el$20, _$createComponent(For, {
1423
1959
  get each() {
1424
1960
  return rows();
1425
1961
  },
@@ -1427,69 +1963,155 @@ function TreePanel(props) {
1427
1963
  const chosen = () => index() === selected();
1428
1964
  const indent = " ".repeat(row.depth - 1);
1429
1965
  return (() => {
1430
- var _el$18 = _$createElement("box"), _el$19 = _$createElement("box"), _el$20 = _$createElement("text"), _el$21 = _$createElement("text"), _el$22 = _$createTextNode(` `);
1431
- _$insertNode(_el$18, _el$19);
1432
- _$setProp(_el$18, "flexDirection", "column");
1433
- _$setProp(_el$18, "flexShrink", 0);
1434
- _$insertNode(_el$19, _el$20);
1435
- _$insertNode(_el$19, _el$21);
1436
- _$setProp(_el$19, "flexDirection", "row");
1437
- _$setProp(_el$19, "flexShrink", 0);
1438
- _$setProp(_el$20, "wrapMode", "none");
1439
- _$setProp(_el$20, "flexShrink", 1);
1440
- _$setProp(_el$20, "minWidth", 0);
1441
- _$insert(_el$20, indent, null);
1442
- _$insert(_el$20, () => chosen() ? "\u25B8 " : " ", null);
1443
- _$insert(_el$20, () => oneLine(row.title), null);
1444
- _$insert(_el$20, () => row.sessionID === input.sessionID ? " (on screen)" : "", null);
1445
- _$insertNode(_el$21, _el$22);
1446
- _$setProp(_el$21, "wrapMode", "none");
1447
- _$setProp(_el$21, "flexShrink", 0);
1448
- _$insert(_el$21, () => statusLine(row), null);
1449
- _$insert(_el$18, _$createComponent(For, {
1966
+ var _el$24 = _$createElement("box"), _el$25 = _$createElement("box"), _el$26 = _$createElement("text"), _el$27 = _$createElement("text"), _el$28 = _$createTextNode(` `), _el$29 = _$createElement("text"), _el$30 = _$createElement("text");
1967
+ _$insertNode(_el$24, _el$25);
1968
+ _$setProp(_el$24, "flexDirection", "column");
1969
+ _$setProp(_el$24, "flexShrink", 0);
1970
+ _$setProp(_el$24, "onMouseOver", () => setHovered(row.sessionID));
1971
+ _$setProp(_el$24, "onMouseOut", () => setHovered((id) => id === row.sessionID ? undefined : id));
1972
+ _$setProp(_el$24, "onMouseDown", (event) => pressed = event.button === MouseButton.LEFT ? row.sessionID : undefined);
1973
+ _$setProp(_el$24, "onMouseUp", (event) => {
1974
+ if (event.button !== MouseButton.LEFT)
1975
+ return;
1976
+ event.stopPropagation();
1977
+ const down = pressed;
1978
+ pressed = undefined;
1979
+ if (down === row.sessionID)
1980
+ click(row);
1981
+ });
1982
+ _$insertNode(_el$25, _el$26);
1983
+ _$insertNode(_el$25, _el$27);
1984
+ _$insertNode(_el$25, _el$29);
1985
+ _$insertNode(_el$25, _el$30);
1986
+ _$setProp(_el$25, "flexDirection", "row");
1987
+ _$setProp(_el$25, "flexShrink", 0);
1988
+ _$setProp(_el$26, "wrapMode", "none");
1989
+ _$setProp(_el$26, "flexShrink", 0);
1990
+ _$insert(_el$26, indent, null);
1991
+ _$insert(_el$26, () => chosen() ? "\u25B8 " : " ", null);
1992
+ _$insertNode(_el$27, _el$28);
1993
+ _$setProp(_el$27, "wrapMode", "none");
1994
+ _$setProp(_el$27, "flexShrink", 0);
1995
+ _$insert(_el$27, () => rowMark(row, theme, frame()).mark, _el$28);
1996
+ _$setProp(_el$29, "wrapMode", "none");
1997
+ _$setProp(_el$29, "flexShrink", 1);
1998
+ _$setProp(_el$29, "minWidth", 0);
1999
+ _$insert(_el$29, () => oneLine(row.title), null);
2000
+ _$insert(_el$29, () => row.sessionID === input.sessionID ? " (on screen)" : "", null);
2001
+ _$insertNode(_el$30, _$createTextNode(` `));
2002
+ _$setProp(_el$30, "wrapMode", "none");
2003
+ _$setProp(_el$30, "flexShrink", 0);
2004
+ _$insert(_el$25, _$createComponent(For, {
2005
+ get each() {
2006
+ return statusParts(row);
2007
+ },
2008
+ children: (part, at2) => [_$createComponent(Show, {
2009
+ get when() {
2010
+ return at2();
2011
+ },
2012
+ get children() {
2013
+ var _el$32 = _$createElement("text");
2014
+ _$insertNode(_el$32, _$createTextNode(` \xB7 `));
2015
+ _$setProp(_el$32, "wrapMode", "none");
2016
+ _$setProp(_el$32, "flexShrink", 0);
2017
+ _$effect((_$p) => _$setProp(_el$32, "fg", theme.text.muted, _$p));
2018
+ return _el$32;
2019
+ }
2020
+ }), (() => {
2021
+ var _el$34 = _$createElement("text");
2022
+ _$setProp(_el$34, "wrapMode", "none");
2023
+ _$setProp(_el$34, "flexShrink", 0);
2024
+ _$insert(_el$34, () => part.text);
2025
+ _$effect((_$p) => _$setProp(_el$34, "fg", partColor(row, part.kind), _$p));
2026
+ return _el$34;
2027
+ })()]
2028
+ }), null);
2029
+ _$insert(_el$24, _$createComponent(For, {
1450
2030
  get each() {
1451
2031
  return detailLines(row, rows(), now());
1452
2032
  },
1453
2033
  children: (line) => (() => {
1454
- var _el$23 = _$createElement("text"), _el$24 = _$createTextNode(` `);
1455
- _$insertNode(_el$23, _el$24);
1456
- _$setProp(_el$23, "wrapMode", "none");
1457
- _$insert(_el$23, indent, _el$24);
1458
- _$insert(_el$23, line, null);
1459
- _$effect((_$p) => _$setProp(_el$23, "fg", theme.text.muted, _$p));
1460
- return _el$23;
2034
+ var _el$35 = _$createElement("text"), _el$36 = _$createTextNode(` `);
2035
+ _$insertNode(_el$35, _el$36);
2036
+ _$setProp(_el$35, "wrapMode", "none");
2037
+ _$insert(_el$35, indent, _el$36);
2038
+ _$insert(_el$35, _$createComponent(Show, {
2039
+ get when() {
2040
+ return _$memo(() => row.context !== undefined)() && Math.round(row.context * 100) > CONTEXT_WARN * 100;
2041
+ },
2042
+ fallback: line,
2043
+ get children() {
2044
+ return _$createComponent(For, {
2045
+ get each() {
2046
+ return line.split(" \xB7 ");
2047
+ },
2048
+ children: (part, at2) => [_$memo(() => at2() ? " \xB7 " : ""), _$memo(() => _$memo(() => part === `ctx ${Math.round(row.context * 100)}%`)() ? (() => {
2049
+ var _el$37 = _$createElement("span");
2050
+ _$insert(_el$37, part);
2051
+ _$effect((_$p) => _$setProp(_el$37, "style", {
2052
+ fg: theme.text.feedback.warning.base
2053
+ }, _$p));
2054
+ return _el$37;
2055
+ })() : part)]
2056
+ });
2057
+ }
2058
+ }), null);
2059
+ _$effect((_$p) => _$setProp(_el$35, "fg", theme.text.muted, _$p));
2060
+ return _el$35;
1461
2061
  })()
1462
2062
  }), null);
1463
2063
  _$effect((_p$) => {
1464
- var _v$3 = `courier-row-${index()}`, _v$4 = chosen() && input.focused ? theme.background.raised.high : undefined, _v$5 = rowColor(row), _v$6 = theme.text.muted;
1465
- _v$3 !== _p$.e && (_p$.e = _$setProp(_el$18, "id", _v$3, _p$.e));
1466
- _v$4 !== _p$.t && (_p$.t = _$setProp(_el$18, "backgroundColor", _v$4, _p$.t));
1467
- _v$5 !== _p$.a && (_p$.a = _$setProp(_el$20, "fg", _v$5, _p$.a));
1468
- _v$6 !== _p$.o && (_p$.o = _$setProp(_el$21, "fg", _v$6, _p$.o));
2064
+ var _v$3 = `courier-row-${index()}`, _v$4 = rowBackground(row, chosen()), _v$5 = rowColor(row), _v$6 = rowMark(row, theme).color, _v$7 = rowColor(row), _v$8 = theme.text.muted;
2065
+ _v$3 !== _p$.e && (_p$.e = _$setProp(_el$24, "id", _v$3, _p$.e));
2066
+ _v$4 !== _p$.t && (_p$.t = _$setProp(_el$24, "backgroundColor", _v$4, _p$.t));
2067
+ _v$5 !== _p$.a && (_p$.a = _$setProp(_el$26, "fg", _v$5, _p$.a));
2068
+ _v$6 !== _p$.o && (_p$.o = _$setProp(_el$27, "fg", _v$6, _p$.o));
2069
+ _v$7 !== _p$.i && (_p$.i = _$setProp(_el$29, "fg", _v$7, _p$.i));
2070
+ _v$8 !== _p$.n && (_p$.n = _$setProp(_el$30, "fg", _v$8, _p$.n));
1469
2071
  return _p$;
1470
2072
  }, {
1471
2073
  e: undefined,
1472
2074
  t: undefined,
1473
2075
  a: undefined,
1474
- o: undefined
2076
+ o: undefined,
2077
+ i: undefined,
2078
+ n: undefined
1475
2079
  });
1476
- return _el$18;
2080
+ return _el$24;
1477
2081
  })();
1478
2082
  }
1479
- }));
1480
- _$insertNode(_el$16, _$createTextNode(`\u2191\u2193 select \xB7 enter open \xB7 s stop \xB7 x forget \xB7 r refresh \xB7 f fullscreen \xB7 q close`));
1481
- _$setProp(_el$16, "wrapMode", "none");
1482
- _$setProp(_el$16, "flexShrink", 0);
2083
+ }), null);
2084
+ _$insert(_el$20, _$createComponent(Show, {
2085
+ get when() {
2086
+ return belowShown();
2087
+ },
2088
+ get children() {
2089
+ var _el$21 = _$createElement("box");
2090
+ _$setProp(_el$21, "flexDirection", "column");
2091
+ _$setProp(_el$21, "flexShrink", 0);
2092
+ _$setProp(_el$21, "paddingTop", 1);
2093
+ _$insert(_el$21, _$createComponent(Index, {
2094
+ get each() {
2095
+ return art2();
2096
+ },
2097
+ children: (line) => drawn(line)
2098
+ }));
2099
+ return _el$21;
2100
+ }
2101
+ }), null);
2102
+ _$insertNode(_el$22, _$createTextNode(`\u2191\u2193 select \xB7 enter open \xB7 s stop \xB7 x forget \xB7 r refresh \xB7 f fullscreen \xB7 q close`));
2103
+ _$setProp(_el$22, "wrapMode", "none");
2104
+ _$setProp(_el$22, "flexShrink", 0);
1483
2105
  _$effect((_p$) => {
1484
- var _v$ = theme.text.base, _v$2 = theme.text.muted;
1485
- _v$ !== _p$.e && (_p$.e = _$setProp(_el$6, "fg", _v$, _p$.e));
1486
- _v$2 !== _p$.t && (_p$.t = _$setProp(_el$16, "fg", _v$2, _p$.t));
2106
+ var _v$ = tokens.a, _v$2 = theme.text.muted;
2107
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$8, "fg", _v$, _p$.e));
2108
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$22, "fg", _v$2, _p$.t));
1487
2109
  return _p$;
1488
2110
  }, {
1489
2111
  e: undefined,
1490
2112
  t: undefined
1491
2113
  });
1492
- return _el$4;
2114
+ return _el$6;
1493
2115
  })();
1494
2116
  }
1495
2117
  var USAGE = "/courier tree opens the session tree; /courier stop [session] stops a session and those under it";
@@ -1498,6 +2120,7 @@ function addTreePanel(ctx) {
1498
2120
  courier,
1499
2121
  location
1500
2122
  } = courierOf(ctx);
2123
+ const animations = animationsOn(ctx.options);
1501
2124
  const [changed, stopListening] = changes(ctx, PANEL_CHANGES, PANEL_SETTLE_MS);
1502
2125
  let following;
1503
2126
  let attempt = 0;
@@ -1531,7 +2154,8 @@ function addTreePanel(ctx) {
1531
2154
  },
1532
2155
  courier,
1533
2156
  location,
1534
- changed
2157
+ changed,
2158
+ animations
1535
2159
  });
1536
2160
  }
1537
2161
  })
@@ -1557,7 +2181,7 @@ function addTreePanel(ctx) {
1557
2181
  return;
1558
2182
  });
1559
2183
  const follow = (from, sessionID) => {
1560
- const token = ++attempt;
2184
+ const token2 = ++attempt;
1561
2185
  const under = (tree) => tree?.rows.some((row) => row.sessionID === sessionID) === true;
1562
2186
  Object.assign(from, {
1563
2187
  at: undefined,
@@ -1568,7 +2192,7 @@ function addTreePanel(ctx) {
1568
2192
  (async () => {
1569
2193
  const inside = await treeOf(from.root);
1570
2194
  const own = under(inside) ? undefined : await treeOf(sessionID);
1571
- if (token !== attempt || following !== from)
2195
+ if (token2 !== attempt || following !== from)
1572
2196
  return;
1573
2197
  if (under(inside))
1574
2198
  show(from, sessionID, from.root, inside);