@bojackduy/opencode-learn 0.1.5 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/tui.js CHANGED
@@ -1,20 +1,227 @@
1
1
  // @bun
2
2
  // plugins/learn-tui.tsx
3
- import { use as _$use } from "@opentui/solid";
4
3
  import { createComponent as _$createComponent } from "@opentui/solid";
5
4
  import { effect as _$effect } from "@opentui/solid";
5
+ import { use as _$use } from "@opentui/solid";
6
6
  import { createTextNode as _$createTextNode } from "@opentui/solid";
7
7
  import { insertNode as _$insertNode } from "@opentui/solid";
8
8
  import { insert as _$insert } from "@opentui/solid";
9
9
  import { memo as _$memo } from "@opentui/solid";
10
10
  import { setProp as _$setProp } from "@opentui/solid";
11
11
  import { createElement as _$createElement } from "@opentui/solid";
12
- import { createSignal, For, Show, createEffect } from "solid-js";
12
+ import { createSignal, onCleanup, For, Show, createEffect } from "solid-js";
13
13
  import { useKeyboard, useTerminalDimensions } from "@opentui/solid";
14
14
  import * as fs from "fs";
15
15
  import * as path from "path";
16
16
  import { watch } from "fs";
17
+ import { SyntaxStyle } from "@opentui/core";
17
18
  import { tmpdir } from "os";
19
+ function syntaxStyle(theme) {
20
+ return SyntaxStyle.fromTheme([{
21
+ scope: ["default"],
22
+ style: {
23
+ foreground: theme.text
24
+ }
25
+ }, {
26
+ scope: ["comment", "comment.documentation"],
27
+ style: {
28
+ foreground: theme.syntaxComment,
29
+ italic: true
30
+ }
31
+ }, {
32
+ scope: ["string", "symbol", "character", "character.special"],
33
+ style: {
34
+ foreground: theme.syntaxString
35
+ }
36
+ }, {
37
+ scope: ["number", "boolean", "float", "constant"],
38
+ style: {
39
+ foreground: theme.syntaxNumber
40
+ }
41
+ }, {
42
+ scope: ["keyword.return", "keyword.conditional", "keyword.repeat", "keyword.coroutine", "keyword", "keyword.directive", "keyword.modifier", "keyword.exception"],
43
+ style: {
44
+ foreground: theme.syntaxKeyword,
45
+ italic: true
46
+ }
47
+ }, {
48
+ scope: ["keyword.type"],
49
+ style: {
50
+ foreground: theme.syntaxType,
51
+ bold: true,
52
+ italic: true
53
+ }
54
+ }, {
55
+ scope: ["keyword.import", "keyword.export", "tag.attribute"],
56
+ style: {
57
+ foreground: theme.syntaxKeyword
58
+ }
59
+ }, {
60
+ scope: ["keyword.function", "function.method", "variable.member", "function", "constructor"],
61
+ style: {
62
+ foreground: theme.syntaxFunction
63
+ }
64
+ }, {
65
+ scope: ["operator", "keyword.operator", "punctuation.delimiter", "keyword.conditional.ternary", "punctuation.special", "tag.delimiter"],
66
+ style: {
67
+ foreground: theme.syntaxOperator
68
+ }
69
+ }, {
70
+ scope: ["variable", "variable.parameter", "function.method.call", "function.call", "property", "parameter", "field"],
71
+ style: {
72
+ foreground: theme.syntaxVariable
73
+ }
74
+ }, {
75
+ scope: ["type", "module", "class", "namespace"],
76
+ style: {
77
+ foreground: theme.syntaxType
78
+ }
79
+ }, {
80
+ scope: ["punctuation", "punctuation.bracket"],
81
+ style: {
82
+ foreground: theme.syntaxPunctuation
83
+ }
84
+ }, {
85
+ scope: ["variable.builtin", "type.builtin", "function.builtin", "module.builtin", "constant.builtin", "variable.super", "tag"],
86
+ style: {
87
+ foreground: theme.error
88
+ }
89
+ }, {
90
+ scope: ["string.escape", "string.regexp"],
91
+ style: {
92
+ foreground: theme.syntaxKeyword
93
+ }
94
+ }, {
95
+ scope: ["markup.heading"],
96
+ style: {
97
+ foreground: theme.markdownHeading,
98
+ bold: true
99
+ }
100
+ }, {
101
+ scope: ["markup.heading.1"],
102
+ style: {
103
+ foreground: theme.markdownHeading,
104
+ bold: true,
105
+ underline: true
106
+ }
107
+ }, {
108
+ scope: ["markup.bold", "markup.strong"],
109
+ style: {
110
+ foreground: theme.markdownStrong,
111
+ bold: true
112
+ }
113
+ }, {
114
+ scope: ["markup.italic"],
115
+ style: {
116
+ foreground: theme.markdownEmph,
117
+ italic: true
118
+ }
119
+ }, {
120
+ scope: ["markup.list"],
121
+ style: {
122
+ foreground: theme.markdownListItem
123
+ }
124
+ }, {
125
+ scope: ["markup.quote"],
126
+ style: {
127
+ foreground: theme.markdownBlockQuote,
128
+ italic: true
129
+ }
130
+ }, {
131
+ scope: ["markup.raw", "markup.raw.block"],
132
+ style: {
133
+ foreground: theme.markdownCode
134
+ }
135
+ }, {
136
+ scope: ["markup.raw.inline"],
137
+ style: {
138
+ foreground: theme.markdownCode,
139
+ background: theme.background
140
+ }
141
+ }, {
142
+ scope: ["markup.link", "markup.link.url", "string.special", "string.special.url"],
143
+ style: {
144
+ foreground: theme.markdownLink,
145
+ underline: true
146
+ }
147
+ }, {
148
+ scope: ["markup.link.label", "label"],
149
+ style: {
150
+ foreground: theme.markdownLinkText,
151
+ underline: true
152
+ }
153
+ }, {
154
+ scope: ["spell", "nospell", "markup.underline"],
155
+ style: {
156
+ foreground: theme.text
157
+ }
158
+ }, {
159
+ scope: ["conceal", "markup.strikethrough", "markup.list.unchecked", "debug"],
160
+ style: {
161
+ foreground: theme.textMuted
162
+ }
163
+ }, {
164
+ scope: ["comment.error", "error"],
165
+ style: {
166
+ foreground: theme.error,
167
+ italic: true,
168
+ bold: true
169
+ }
170
+ }, {
171
+ scope: ["comment.warning", "warning"],
172
+ style: {
173
+ foreground: theme.warning,
174
+ italic: true,
175
+ bold: true
176
+ }
177
+ }, {
178
+ scope: ["comment.todo", "comment.note"],
179
+ style: {
180
+ foreground: theme.info,
181
+ italic: true,
182
+ bold: true
183
+ }
184
+ }, {
185
+ scope: ["type.definition"],
186
+ style: {
187
+ foreground: theme.syntaxType,
188
+ bold: true
189
+ }
190
+ }, {
191
+ scope: ["attribute", "annotation"],
192
+ style: {
193
+ foreground: theme.warning
194
+ }
195
+ }, {
196
+ scope: ["markup.list.checked"],
197
+ style: {
198
+ foreground: theme.success
199
+ }
200
+ }, {
201
+ scope: ["diff.plus"],
202
+ style: {
203
+ foreground: theme.diffAdded,
204
+ background: theme.diffAddedBg
205
+ }
206
+ }, {
207
+ scope: ["diff.minus"],
208
+ style: {
209
+ foreground: theme.diffRemoved,
210
+ background: theme.diffRemovedBg
211
+ }
212
+ }, {
213
+ scope: ["diff.delta"],
214
+ style: {
215
+ foreground: theme.diffContext,
216
+ background: theme.diffContextBg
217
+ }
218
+ }, {
219
+ scope: ["info"],
220
+ style: {
221
+ foreground: theme.info
222
+ }
223
+ }]);
224
+ }
18
225
  var PENDING_DIR = ".opencode/learn-pending";
19
226
  var TUI_LOG = path.join(tmpdir(), "learn-tui.log");
20
227
  function tlog(...a) {
@@ -30,6 +237,18 @@ function ensureDir(dir) {
30
237
  });
31
238
  } catch {}
32
239
  }
240
+ function decodeQuizText(s) {
241
+ if (!s || typeof s !== "string")
242
+ return s;
243
+ if (!s.includes("\\"))
244
+ return s;
245
+ let out = s.replace(/\\r\\n/g, `
246
+ `).replace(/\\n/g, `
247
+ `).replace(/\\r/g, "\r").replace(/\\t/g, "\t");
248
+ out = out.replace(/\\"/g, '"').replace(/\\'/g, "'");
249
+ out = out.replace(/\\\\/g, "\\");
250
+ return out;
251
+ }
33
252
  function prevent(e) {
34
253
  try {
35
254
  e.preventDefault?.();
@@ -38,8 +257,10 @@ function prevent(e) {
38
257
  }
39
258
  function QuizDialog(props) {
40
259
  const theme = () => props.api.theme.current;
260
+ const syntax = () => syntaxStyle(theme());
41
261
  const dims = useTerminalDimensions();
42
262
  const popupWidth = () => Math.max(68, Math.min(dims().width - 4, 92));
263
+ const popupHeight = () => Math.max(4, Math.min(24, dims().height - 2));
43
264
  const options = () => props.request.options;
44
265
  const correctSet = new Set(props.request.correctIndices);
45
266
  const isMulti = () => !!props.request.multiSelect;
@@ -53,6 +274,40 @@ function QuizDialog(props) {
53
274
  const [selected, setSelected] = createSignal(new Map);
54
275
  const [feedback, setFeedback] = createSignal(null);
55
276
  let noteInputEl;
277
+ let scrollRef;
278
+ const [canScrollUp, setCanScrollUp] = createSignal(false);
279
+ const [canScrollDown, setCanScrollDown] = createSignal(false);
280
+ const updateScrollIndicators = () => {
281
+ try {
282
+ if (!scrollRef) {
283
+ setCanScrollUp(false);
284
+ setCanScrollDown(false);
285
+ return;
286
+ }
287
+ const st = typeof scrollRef.scrollTop === "number" ? scrollRef.scrollTop : 0;
288
+ const h = typeof scrollRef.height === "number" ? scrollRef.height : scrollRef.viewportHeight ?? popupHeight();
289
+ const sh = typeof scrollRef.scrollHeight === "number" ? scrollRef.scrollHeight : 0;
290
+ let effectiveSh = sh;
291
+ if (!effectiveSh && typeof scrollRef.getChildren === "function") {
292
+ try {
293
+ const kids = scrollRef.getChildren();
294
+ if (kids?.length)
295
+ effectiveSh = Math.max(...kids.map((c) => (c.y || 0) + (c.height || 0)), h);
296
+ } catch {}
297
+ }
298
+ if (!effectiveSh || effectiveSh <= h + 1) {
299
+ setCanScrollUp(false);
300
+ setCanScrollDown(false);
301
+ return;
302
+ }
303
+ setCanScrollUp(st > 0);
304
+ setCanScrollDown(st + h < effectiveSh - 1);
305
+ } catch {
306
+ setCanScrollUp(false);
307
+ setCanScrollDown(false);
308
+ }
309
+ };
310
+ const scrollAmount = () => Math.max(1, Math.floor((scrollRef?.height ?? popupHeight()) / 3));
56
311
  createEffect(() => {
57
312
  if (focused() === "note" && noteInputEl) {
58
313
  try {
@@ -60,6 +315,23 @@ function QuizDialog(props) {
60
315
  } catch {}
61
316
  }
62
317
  });
318
+ createEffect(() => {
319
+ phase();
320
+ feedback();
321
+ dims();
322
+ setTimeout(updateScrollIndicators, 40);
323
+ setTimeout(updateScrollIndicators, 200);
324
+ });
325
+ createEffect(() => {
326
+ note();
327
+ setTimeout(updateScrollIndicators, 40);
328
+ });
329
+ createEffect(() => {
330
+ if (phase() !== "feedback" && phase() !== "select")
331
+ return;
332
+ const id = setInterval(updateScrollIndicators, 200);
333
+ onCleanup(() => clearInterval(id));
334
+ });
63
335
  const toggleOption = (idx) => {
64
336
  const opt = options()[idx];
65
337
  if (!opt)
@@ -90,10 +362,125 @@ function QuizDialog(props) {
90
362
  };
91
363
  const submitSelect = () => {
92
364
  const selMap = selected();
93
- if (!isMulti() && selMap.size === 0 && !dontKnow())
365
+ if (!isMulti() && selMap.size === 0 && !dontKnow() && !note().trim())
94
366
  return;
95
- if (isMulti() && selMap.size === 0 && !dontKnow())
367
+ if (isMulti() && selMap.size === 0 && !dontKnow() && !note().trim())
96
368
  return;
369
+ if (selMap.size === 0 && !dontKnow() && note().trim()) {
370
+ setPhase("classifying");
371
+ try {
372
+ const pDir = globalThis.__learnPendingDir || ".opencode/learn-pending";
373
+ const routeSessionID = props.api.route?.current?.params?.sessionID;
374
+ const pendingClassify = {
375
+ id: props.request.id,
376
+ type: "classify",
377
+ note: note().trim(),
378
+ question: props.request.question,
379
+ options: options().map((o, i) => ({
380
+ label: o.label,
381
+ value: o.value,
382
+ index: i + 1
383
+ })),
384
+ timestamp: Date.now(),
385
+ sessionID: props.request.sessionID || routeSessionID
386
+ };
387
+ fs.writeFileSync(path.join(pDir, `classify-${props.request.id}.json`), JSON.stringify(pendingClassify), "utf8");
388
+ tlog("QuizDialog classify request", props.request.id, note().trim().slice(0, 50));
389
+ const respPath = path.join(pDir, `classify-response-${props.request.id}.json`);
390
+ let attempts = 0;
391
+ const poll = setInterval(() => {
392
+ attempts++;
393
+ if (attempts > 60) {
394
+ clearInterval(poll);
395
+ setPhase("feedback");
396
+ setFeedback({
397
+ correct: false,
398
+ selectedIndices: []
399
+ });
400
+ return;
401
+ }
402
+ try {
403
+ if (fs.existsSync(respPath)) {
404
+ clearInterval(poll);
405
+ const raw = fs.readFileSync(respPath, "utf8");
406
+ const data = JSON.parse(raw);
407
+ try {
408
+ fs.unlinkSync(respPath);
409
+ fs.unlinkSync(path.join(pDir, `classify-${props.request.id}.json`));
410
+ } catch {}
411
+ const inferred = data?.inferredIndices;
412
+ const inferredValues = data?.inferredValues;
413
+ const semanticCorrect = data?.semanticCorrect;
414
+ const reason = data?.reason;
415
+ const computeCorrect = (idxs) => {
416
+ if (typeof semanticCorrect === "boolean")
417
+ return semanticCorrect;
418
+ return idxs.length === props.request.correctIndices.length && idxs.every((v) => correctSet.has(v)) && props.request.correctIndices.every((v) => idxs.includes(v));
419
+ };
420
+ if (inferred && inferred.length) {
421
+ const m = new Map;
422
+ for (let i = 0;i < inferred.length; i++) {
423
+ const idx = inferred[i];
424
+ const opt = options()[idx - 1];
425
+ if (opt)
426
+ m.set(`opt:${idx - 1}`, {
427
+ label: opt.label,
428
+ value: opt.value,
429
+ index: idx
430
+ });
431
+ }
432
+ setSelected(m);
433
+ const correct2 = computeCorrect(inferred);
434
+ setFeedback({
435
+ correct: correct2,
436
+ selectedIndices: inferred
437
+ });
438
+ if (reason)
439
+ setNote((prev) => prev ? `${prev} \u2014 ${reason}` : prev);
440
+ tlog("QuizDialog classify done", inferred.join(","), correct2, reason || "");
441
+ } else if (inferredValues && inferredValues.length) {
442
+ const byVal = new Map(options().map((o, i) => [o.value, i + 1]));
443
+ const idxs = inferredValues.map((v) => byVal.get(v)).filter(Boolean);
444
+ const m = new Map;
445
+ for (const idx of idxs) {
446
+ const opt = options()[idx - 1];
447
+ if (opt)
448
+ m.set(`opt:${idx - 1}`, {
449
+ label: opt.label,
450
+ value: opt.value,
451
+ index: idx
452
+ });
453
+ }
454
+ setSelected(m);
455
+ const correct2 = computeCorrect(idxs);
456
+ setFeedback({
457
+ correct: correct2,
458
+ selectedIndices: idxs
459
+ });
460
+ } else {
461
+ const correct2 = typeof semanticCorrect === "boolean" ? semanticCorrect : false;
462
+ setFeedback({
463
+ correct: correct2,
464
+ selectedIndices: []
465
+ });
466
+ if (reason)
467
+ setNote((prev) => prev ? `${prev} \u2014 ${reason}` : reason);
468
+ }
469
+ setPhase("feedback");
470
+ }
471
+ } catch {}
472
+ }, 500);
473
+ onCleanup(() => clearInterval(poll));
474
+ } catch (e) {
475
+ tlog("classify request failed", String(e));
476
+ setPhase("feedback");
477
+ setFeedback({
478
+ correct: false,
479
+ selectedIndices: []
480
+ });
481
+ }
482
+ return;
483
+ }
97
484
  if (dontKnow()) {
98
485
  setFeedback({
99
486
  correct: false,
@@ -118,11 +505,78 @@ function QuizDialog(props) {
118
505
  note: note().trim() || undefined
119
506
  });
120
507
  };
508
+ const isPlainKey = (evt, want) => {
509
+ try {
510
+ const n = String(evt.name || evt.sequence || "").toLowerCase();
511
+ if (n !== want.toLowerCase())
512
+ return false;
513
+ if (evt.ctrl || evt.meta || evt.option || evt.alt)
514
+ return false;
515
+ return true;
516
+ } catch {
517
+ return false;
518
+ }
519
+ };
121
520
  useKeyboard((evt) => {
122
521
  const key = evt.name || evt.sequence || evt.raw || "";
123
522
  const seq = evt.sequence || "";
523
+ const lower = String(key || "").toLowerCase();
524
+ if (phase() === "classifying") {
525
+ prevent(evt);
526
+ return;
527
+ }
124
528
  if (phase() === "feedback") {
125
- if (key === "enter" || seq === "\r" || key === "escape" || key === "esc") {
529
+ if (isPlainKey(evt, "d") || seq === "\x04") {
530
+ prevent(evt);
531
+ try {
532
+ scrollRef?.scrollBy(scrollAmount());
533
+ setTimeout(updateScrollIndicators, 30);
534
+ setTimeout(updateScrollIndicators, 120);
535
+ } catch {}
536
+ return;
537
+ }
538
+ if (isPlainKey(evt, "u") || seq === "\x15") {
539
+ prevent(evt);
540
+ try {
541
+ scrollRef?.scrollBy(-scrollAmount());
542
+ setTimeout(updateScrollIndicators, 30);
543
+ setTimeout(updateScrollIndicators, 120);
544
+ } catch {}
545
+ return;
546
+ }
547
+ if (isPlainKey(evt, "j") || seq === "\x1B[B") {
548
+ prevent(evt);
549
+ try {
550
+ scrollRef?.scrollBy(1);
551
+ setTimeout(updateScrollIndicators, 30);
552
+ } catch {}
553
+ return;
554
+ }
555
+ if (isPlainKey(evt, "k") || seq === "\x1B[A") {
556
+ prevent(evt);
557
+ try {
558
+ scrollRef?.scrollBy(-1);
559
+ setTimeout(updateScrollIndicators, 30);
560
+ } catch {}
561
+ return;
562
+ }
563
+ if (key === "pageup" || seq === "\x1B[5~") {
564
+ prevent(evt);
565
+ try {
566
+ scrollRef?.scrollBy(-scrollAmount());
567
+ setTimeout(updateScrollIndicators, 30);
568
+ } catch {}
569
+ return;
570
+ }
571
+ if (key === "pagedown" || seq === "\x1B[6~") {
572
+ prevent(evt);
573
+ try {
574
+ scrollRef?.scrollBy(scrollAmount());
575
+ setTimeout(updateScrollIndicators, 30);
576
+ } catch {}
577
+ return;
578
+ }
579
+ if (lower === "enter" || seq === "\r" || lower === "escape" || lower === "esc") {
126
580
  prevent(evt);
127
581
  confirmFeedback();
128
582
  }
@@ -146,6 +600,47 @@ function QuizDialog(props) {
146
600
  }
147
601
  return;
148
602
  }
603
+ if (phase() === "select" && (isPlainKey(evt, "d") || seq === "\x04")) {
604
+ prevent(evt);
605
+ try {
606
+ scrollRef?.scrollBy(scrollAmount());
607
+ setTimeout(updateScrollIndicators, 30);
608
+ setTimeout(updateScrollIndicators, 120);
609
+ } catch {}
610
+ return;
611
+ }
612
+ if (phase() === "select" && (isPlainKey(evt, "u") || seq === "\x15")) {
613
+ prevent(evt);
614
+ try {
615
+ scrollRef?.scrollBy(-scrollAmount());
616
+ setTimeout(updateScrollIndicators, 30);
617
+ setTimeout(updateScrollIndicators, 120);
618
+ } catch {}
619
+ return;
620
+ }
621
+ if (phase() === "select" && (lower === "pageup" || seq === "\x1B[5~")) {
622
+ prevent(evt);
623
+ try {
624
+ scrollRef?.scrollBy(-scrollAmount());
625
+ setTimeout(updateScrollIndicators, 30);
626
+ } catch {}
627
+ return;
628
+ }
629
+ if (phase() === "select" && (lower === "pagedown" || seq === "\x1B[6~")) {
630
+ prevent(evt);
631
+ try {
632
+ scrollRef?.scrollBy(scrollAmount());
633
+ setTimeout(updateScrollIndicators, 30);
634
+ } catch {}
635
+ return;
636
+ }
637
+ const maxIdx = () => {
638
+ if (isMulti())
639
+ return submitIdx();
640
+ if (note().trim() && !selected().size && !dontKnow())
641
+ return dontKnowIdx() + 1;
642
+ return dontKnowIdx();
643
+ };
149
644
  if (key === "up" || key === "k" || seq === "\x1B[A") {
150
645
  prevent(evt);
151
646
  setOptionIndex((i) => Math.max(0, i - 1));
@@ -153,7 +648,7 @@ function QuizDialog(props) {
153
648
  }
154
649
  if (key === "down" || key === "j" || seq === "\x1B[B") {
155
650
  prevent(evt);
156
- setOptionIndex((i) => Math.min(isMulti() ? submitIdx() : dontKnowIdx(), i + 1));
651
+ setOptionIndex((i) => Math.min(maxIdx(), i + 1));
157
652
  return;
158
653
  }
159
654
  if (key === "tab" || seq === "\t") {
@@ -171,6 +666,8 @@ function QuizDialog(props) {
171
666
  const idx = optionIndex();
172
667
  if (idx === dontKnowIdx())
173
668
  handleDontKnow();
669
+ else if (!isMulti() && idx === dontKnowIdx() + 1 && note().trim() && !selected().size && !dontKnow())
670
+ submitSelect();
174
671
  else {
175
672
  if (isMulti())
176
673
  toggleOption(idx);
@@ -194,6 +691,8 @@ function QuizDialog(props) {
194
691
  const idx = optionIndex();
195
692
  if (idx === dontKnowIdx())
196
693
  handleDontKnow();
694
+ else if (!isMulti() && idx === dontKnowIdx() + 1 && note().trim() && !selected().size && !dontKnow())
695
+ submitSelect();
197
696
  else if (isMulti())
198
697
  submitSelect();
199
698
  else {
@@ -217,9 +716,10 @@ function QuizDialog(props) {
217
716
  }
218
717
  });
219
718
  return (() => {
220
- var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$4 = _$createElement("text"), _el$6 = _$createElement("box"), _el$7 = _$createElement("text");
719
+ var _el$ = _$createElement("box"), _el$2 = _$createElement("box"), _el$3 = _$createElement("text"), _el$4 = _$createElement("text"), _el$6 = _$createElement("scrollbox"), _el$7 = _$createElement("box"), _el$8 = _$createElement("markdown"), _el$59 = _$createElement("box"), _el$60 = _$createElement("text");
221
720
  _$insertNode(_el$, _el$2);
222
721
  _$insertNode(_el$, _el$6);
722
+ _$insertNode(_el$, _el$59);
223
723
  _$setProp(_el$, "flexDirection", "column");
224
724
  _$setProp(_el$, "border", true);
225
725
  _$setProp(_el$, "padding", 1);
@@ -240,40 +740,50 @@ function QuizDialog(props) {
240
740
  _$insertNode(_el$4, _$createTextNode(`learn`));
241
741
  _$setProp(_el$4, "dim", true);
242
742
  _$insertNode(_el$6, _el$7);
243
- _$setProp(_el$6, "flexDirection", "column");
244
- _$setProp(_el$6, "gap", 1);
245
- _$setProp(_el$6, "paddingLeft", 1);
246
- _$setProp(_el$6, "paddingRight", 1);
247
- _$setProp(_el$6, "paddingTop", 1);
248
- _$setProp(_el$7, "bold", true);
249
- _$setProp(_el$7, "wrapMode", "wrap");
250
- _$insert(_el$7, () => props.request.question);
251
- _$insert(_el$6, _$createComponent(Show, {
743
+ _$use((el) => scrollRef = el, _el$6);
744
+ _$setProp(_el$6, "flexGrow", 1);
745
+ _$insertNode(_el$7, _el$8);
746
+ _$setProp(_el$7, "flexDirection", "column");
747
+ _$setProp(_el$7, "gap", 1);
748
+ _$setProp(_el$7, "paddingLeft", 1);
749
+ _$setProp(_el$7, "paddingRight", 1);
750
+ _$setProp(_el$7, "paddingTop", 1);
751
+ _$insert(_el$7, _$createComponent(Show, {
252
752
  get when() {
253
753
  return props.request.details;
254
754
  },
255
755
  get children() {
256
- var _el$8 = _$createElement("text");
257
- _$setProp(_el$8, "wrapMode", "wrap");
258
- _$insert(_el$8, () => props.request.details);
259
- _$effect((_$p) => _$setProp(_el$8, "fg", theme().textMuted, _$p));
260
- return _el$8;
756
+ var _el$9 = _$createElement("markdown");
757
+ _$effect((_p$) => {
758
+ var _v$ = syntax(), _v$2 = decodeQuizText(props.request.details), _v$3 = theme().textMuted, _v$4 = theme().backgroundPanel;
759
+ _v$ !== _p$.e && (_p$.e = _$setProp(_el$9, "syntaxStyle", _v$, _p$.e));
760
+ _v$2 !== _p$.t && (_p$.t = _$setProp(_el$9, "content", _v$2, _p$.t));
761
+ _v$3 !== _p$.a && (_p$.a = _$setProp(_el$9, "fg", _v$3, _p$.a));
762
+ _v$4 !== _p$.o && (_p$.o = _$setProp(_el$9, "bg", _v$4, _p$.o));
763
+ return _p$;
764
+ }, {
765
+ e: undefined,
766
+ t: undefined,
767
+ a: undefined,
768
+ o: undefined
769
+ });
770
+ return _el$9;
261
771
  }
262
772
  }), null);
263
- _$insert(_el$, _$createComponent(Show, {
773
+ _$insert(_el$6, _$createComponent(Show, {
264
774
  get when() {
265
775
  return phase() === "select";
266
776
  },
267
777
  get children() {
268
- var _el$9 = _$createElement("box"), _el$10 = _$createElement("box"), _el$11 = _$createElement("box"), _el$12 = _$createElement("text"), _el$13 = _$createElement("box"), _el$14 = _$createElement("text"), _el$15 = _$createElement("box"), _el$16 = _$createElement("text"), _el$18 = _$createElement("box"), _el$19 = _$createElement("box"), _el$20 = _$createElement("text"), _el$24 = _$createElement("box"), _el$26 = _$createElement("box"), _el$27 = _$createElement("text");
269
- _$insertNode(_el$9, _el$10);
270
- _$insertNode(_el$9, _el$18);
271
- _$insertNode(_el$9, _el$26);
272
- _$setProp(_el$9, "flexDirection", "column");
273
- _$setProp(_el$9, "gap", 0);
274
- _$setProp(_el$9, "padding", 1);
275
- _$setProp(_el$9, "border", true);
276
- _$insert(_el$9, _$createComponent(For, {
778
+ var _el$0 = _$createElement("box"), _el$11 = _$createElement("box"), _el$12 = _$createElement("box"), _el$13 = _$createElement("text"), _el$14 = _$createElement("box"), _el$15 = _$createElement("text"), _el$16 = _$createElement("box"), _el$17 = _$createElement("text"), _el$19 = _$createElement("box"), _el$20 = _$createElement("box"), _el$21 = _$createElement("text"), _el$25 = _$createElement("box"), _el$27 = _$createElement("box"), _el$28 = _$createElement("text"), _el$29 = _$createElement("text");
779
+ _$insertNode(_el$0, _el$11);
780
+ _$insertNode(_el$0, _el$19);
781
+ _$insertNode(_el$0, _el$27);
782
+ _$setProp(_el$0, "flexDirection", "column");
783
+ _$setProp(_el$0, "gap", 0);
784
+ _$setProp(_el$0, "padding", 1);
785
+ _$setProp(_el$0, "border", true);
786
+ _$insert(_el$0, _$createComponent(For, {
277
787
  get each() {
278
788
  return options();
279
789
  },
@@ -282,39 +792,39 @@ function QuizDialog(props) {
282
792
  const isFocused = () => focused() === "options" && optionIndex() === idx;
283
793
  const isSelected = () => selected().has(`opt:${idx}`);
284
794
  return (() => {
285
- var _el$51 = _$createElement("box"), _el$52 = _$createElement("box"), _el$53 = _$createElement("text"), _el$54 = _$createElement("box"), _el$55 = _$createElement("text"), _el$56 = _$createElement("box"), _el$57 = _$createElement("text"), _el$58 = _$createTextNode(`. `);
286
- _$insertNode(_el$51, _el$52);
287
- _$insertNode(_el$51, _el$54);
288
- _$insertNode(_el$51, _el$56);
289
- _$setProp(_el$51, "flexDirection", "row");
290
- _$setProp(_el$51, "alignItems", "flexStart");
291
- _$setProp(_el$51, "gap", 1);
292
- _$setProp(_el$51, "paddingLeft", 1);
293
- _$setProp(_el$51, "paddingRight", 1);
294
- _$insertNode(_el$52, _el$53);
295
- _$setProp(_el$52, "width", 2);
296
- _$setProp(_el$52, "alignItems", "center");
297
- _$insert(_el$53, () => isFocused() ? "\u25B8" : " ");
298
- _$insertNode(_el$54, _el$55);
299
- _$setProp(_el$54, "width", 2);
300
- _$setProp(_el$54, "alignItems", "center");
301
- _$insert(_el$55, (() => {
302
- var _c$2 = _$memo(() => !!isMulti());
303
- return () => _c$2() ? isSelected() ? "\u2611" : "\u2610" : isSelected() ? "\u2B22" : "\u25CB";
795
+ var _el$61 = _$createElement("box"), _el$62 = _$createElement("box"), _el$63 = _$createElement("text"), _el$64 = _$createElement("box"), _el$65 = _$createElement("text"), _el$66 = _$createElement("box"), _el$67 = _$createElement("text"), _el$68 = _$createTextNode(`. `);
796
+ _$insertNode(_el$61, _el$62);
797
+ _$insertNode(_el$61, _el$64);
798
+ _$insertNode(_el$61, _el$66);
799
+ _$setProp(_el$61, "flexDirection", "row");
800
+ _$setProp(_el$61, "alignItems", "flexStart");
801
+ _$setProp(_el$61, "gap", 1);
802
+ _$setProp(_el$61, "paddingLeft", 1);
803
+ _$setProp(_el$61, "paddingRight", 1);
804
+ _$insertNode(_el$62, _el$63);
805
+ _$setProp(_el$62, "width", 2);
806
+ _$setProp(_el$62, "alignItems", "center");
807
+ _$insert(_el$63, () => isFocused() ? "\u25B8" : " ");
808
+ _$insertNode(_el$64, _el$65);
809
+ _$setProp(_el$64, "width", 2);
810
+ _$setProp(_el$64, "alignItems", "center");
811
+ _$insert(_el$65, (() => {
812
+ var _c$4 = _$memo(() => !!isMulti());
813
+ return () => _c$4() ? isSelected() ? "\u2611" : "\u2610" : isSelected() ? "\u2B22" : "\u25CB";
304
814
  })());
305
- _$insertNode(_el$56, _el$57);
306
- _$setProp(_el$56, "flexGrow", 1);
307
- _$insertNode(_el$57, _el$58);
308
- _$setProp(_el$57, "wrapMode", "wrap");
309
- _$insert(_el$57, idx + 1, _el$58);
310
- _$insert(_el$57, () => opt.label, null);
815
+ _$insertNode(_el$66, _el$67);
816
+ _$setProp(_el$66, "flexGrow", 1);
817
+ _$insertNode(_el$67, _el$68);
818
+ _$setProp(_el$67, "wrapMode", "wrap");
819
+ _$insert(_el$67, idx + 1, _el$68);
820
+ _$insert(_el$67, () => opt.label, null);
311
821
  _$effect((_p$) => {
312
- var _v$29 = isFocused() ? theme().backgroundElement : undefined, _v$30 = isFocused() ? theme().accent : theme().textMuted, _v$31 = isMulti() ? isSelected() ? theme().success : theme().textMuted : isSelected() ? theme().accent : theme().textMuted, _v$32 = isSelected() ? theme().text : theme().textMuted, _v$33 = isFocused();
313
- _v$29 !== _p$.e && (_p$.e = _$setProp(_el$51, "backgroundColor", _v$29, _p$.e));
314
- _v$30 !== _p$.t && (_p$.t = _$setProp(_el$53, "fg", _v$30, _p$.t));
315
- _v$31 !== _p$.a && (_p$.a = _$setProp(_el$55, "fg", _v$31, _p$.a));
316
- _v$32 !== _p$.o && (_p$.o = _$setProp(_el$57, "fg", _v$32, _p$.o));
317
- _v$33 !== _p$.i && (_p$.i = _$setProp(_el$57, "bold", _v$33, _p$.i));
822
+ var _v$50 = isFocused() ? theme().backgroundElement : undefined, _v$51 = isFocused() ? theme().accent : theme().textMuted, _v$52 = isMulti() ? isSelected() ? theme().success : theme().textMuted : isSelected() ? theme().accent : theme().textMuted, _v$53 = isSelected() ? theme().text : theme().textMuted, _v$54 = isFocused();
823
+ _v$50 !== _p$.e && (_p$.e = _$setProp(_el$61, "backgroundColor", _v$50, _p$.e));
824
+ _v$51 !== _p$.t && (_p$.t = _$setProp(_el$63, "fg", _v$51, _p$.t));
825
+ _v$52 !== _p$.a && (_p$.a = _$setProp(_el$65, "fg", _v$52, _p$.a));
826
+ _v$53 !== _p$.o && (_p$.o = _$setProp(_el$67, "fg", _v$53, _p$.o));
827
+ _v$54 !== _p$.i && (_p$.i = _$setProp(_el$67, "bold", _v$54, _p$.i));
318
828
  return _p$;
319
829
  }, {
320
830
  e: undefined,
@@ -323,158 +833,189 @@ function QuizDialog(props) {
323
833
  o: undefined,
324
834
  i: undefined
325
835
  });
326
- return _el$51;
836
+ return _el$61;
327
837
  })();
328
838
  }
329
- }), _el$10);
330
- _$insert(_el$9, _$createComponent(Show, {
839
+ }), _el$11);
840
+ _$insert(_el$0, _$createComponent(Show, {
331
841
  get when() {
332
842
  return options().length > 0;
333
843
  },
334
844
  get children() {
335
- var _el$0 = _$createElement("box"), _el$1 = _$createElement("text");
336
- _$insertNode(_el$0, _el$1);
337
- _$setProp(_el$0, "height", 1);
338
- _$insert(_el$1, () => "\u2500".repeat(Math.max(20, popupWidth() - 8)));
339
- _$effect((_$p) => _$setProp(_el$1, "fg", theme().borderSubtle, _$p));
340
- return _el$0;
845
+ var _el$1 = _$createElement("box"), _el$10 = _$createElement("text");
846
+ _$insertNode(_el$1, _el$10);
847
+ _$setProp(_el$1, "height", 1);
848
+ _$insert(_el$10, () => "\u2500".repeat(Math.max(20, popupWidth() - 8)));
849
+ _$effect((_$p) => _$setProp(_el$10, "fg", theme().borderSubtle, _$p));
850
+ return _el$1;
341
851
  }
342
- }), _el$10);
343
- _$insertNode(_el$10, _el$11);
344
- _$insertNode(_el$10, _el$13);
345
- _$insertNode(_el$10, _el$15);
346
- _$setProp(_el$10, "flexDirection", "row");
347
- _$setProp(_el$10, "alignItems", "flexStart");
348
- _$setProp(_el$10, "gap", 1);
349
- _$setProp(_el$10, "paddingLeft", 1);
350
- _$setProp(_el$10, "paddingRight", 1);
852
+ }), _el$11);
351
853
  _$insertNode(_el$11, _el$12);
352
- _$setProp(_el$11, "width", 2);
353
- _$setProp(_el$11, "alignItems", "center");
354
- _$insert(_el$12, () => focused() === "options" && optionIndex() === dontKnowIdx() ? "\u25B8" : " ");
355
- _$insertNode(_el$13, _el$14);
356
- _$setProp(_el$13, "width", 2);
357
- _$setProp(_el$13, "alignItems", "center");
358
- _$insert(_el$14, () => dontKnow() ? "\u2611" : "\u2610");
359
- _$insertNode(_el$15, _el$16);
360
- _$setProp(_el$15, "flexGrow", 1);
361
- _$insertNode(_el$16, _$createTextNode(`I don't know \u2014 genuine gap, not a guess`));
362
- _$setProp(_el$16, "italic", true);
363
- _$setProp(_el$16, "wrapMode", "wrap");
364
- _$insertNode(_el$18, _el$19);
365
- _$insertNode(_el$18, _el$24);
366
- _$setProp(_el$18, "flexDirection", "column");
367
- _$setProp(_el$18, "gap", 0);
368
- _$setProp(_el$18, "paddingTop", 1);
854
+ _$insertNode(_el$11, _el$14);
855
+ _$insertNode(_el$11, _el$16);
856
+ _$setProp(_el$11, "flexDirection", "row");
857
+ _$setProp(_el$11, "alignItems", "flexStart");
858
+ _$setProp(_el$11, "gap", 1);
859
+ _$setProp(_el$11, "paddingLeft", 1);
860
+ _$setProp(_el$11, "paddingRight", 1);
861
+ _$insertNode(_el$12, _el$13);
862
+ _$setProp(_el$12, "width", 2);
863
+ _$setProp(_el$12, "alignItems", "center");
864
+ _$insert(_el$13, () => focused() === "options" && optionIndex() === dontKnowIdx() ? "\u25B8" : " ");
865
+ _$insertNode(_el$14, _el$15);
866
+ _$setProp(_el$14, "width", 2);
867
+ _$setProp(_el$14, "alignItems", "center");
868
+ _$insert(_el$15, () => dontKnow() ? "\u2611" : "\u2610");
869
+ _$insertNode(_el$16, _el$17);
870
+ _$setProp(_el$16, "flexGrow", 1);
871
+ _$insertNode(_el$17, _$createTextNode(`I don't know \u2014 genuine gap, not a guess`));
872
+ _$setProp(_el$17, "italic", true);
873
+ _$setProp(_el$17, "wrapMode", "wrap");
369
874
  _$insertNode(_el$19, _el$20);
370
- _$setProp(_el$19, "flexDirection", "row");
371
- _$setProp(_el$19, "alignItems", "center");
372
- _$setProp(_el$19, "gap", 1);
373
- _$insertNode(_el$20, _$createTextNode(`\u270E Note (optional)`));
374
- _$insert(_el$19, _$createComponent(Show, {
875
+ _$insertNode(_el$19, _el$25);
876
+ _$setProp(_el$19, "flexDirection", "column");
877
+ _$setProp(_el$19, "gap", 0);
878
+ _$setProp(_el$19, "paddingTop", 1);
879
+ _$insertNode(_el$20, _el$21);
880
+ _$setProp(_el$20, "flexDirection", "row");
881
+ _$setProp(_el$20, "alignItems", "center");
882
+ _$setProp(_el$20, "gap", 1);
883
+ _$insertNode(_el$21, _$createTextNode(`\u270E Note (optional)`));
884
+ _$insert(_el$20, _$createComponent(Show, {
375
885
  get when() {
376
886
  return focused() === "note";
377
887
  },
378
888
  get children() {
379
- var _el$22 = _$createElement("text");
380
- _$insertNode(_el$22, _$createTextNode(`\u25CF editing`));
381
- _$effect((_$p) => _$setProp(_el$22, "fg", theme().accent, _$p));
382
- return _el$22;
889
+ var _el$23 = _$createElement("text");
890
+ _$insertNode(_el$23, _$createTextNode(`\u25CF editing`));
891
+ _$effect((_$p) => _$setProp(_el$23, "fg", theme().accent, _$p));
892
+ return _el$23;
383
893
  }
384
894
  }), null);
385
- _$setProp(_el$24, "border", true);
386
- _$setProp(_el$24, "paddingLeft", 1);
387
- _$setProp(_el$24, "paddingRight", 1);
388
- _$insert(_el$24, _$createComponent(Show, {
895
+ _$setProp(_el$25, "border", true);
896
+ _$setProp(_el$25, "paddingLeft", 1);
897
+ _$setProp(_el$25, "paddingRight", 1);
898
+ _$insert(_el$25, _$createComponent(Show, {
389
899
  get when() {
390
900
  return focused() === "note";
391
901
  },
392
902
  get fallback() {
393
903
  return (() => {
394
- var _el$59 = _$createElement("text");
395
- _$setProp(_el$59, "wrapMode", "wrap");
396
- _$insert(_el$59, () => note() || "Tab to edit \xB7 share what you were thinking");
397
- _$effect((_$p) => _$setProp(_el$59, "fg", note() ? theme().text : theme().textMuted, _$p));
398
- return _el$59;
904
+ var _el$69 = _$createElement("text");
905
+ _$setProp(_el$69, "wrapMode", "wrap");
906
+ _$insert(_el$69, () => note() || "Tab to edit \xB7 share what you were thinking");
907
+ _$effect((_$p) => _$setProp(_el$69, "fg", note() ? theme().text : theme().textMuted, _$p));
908
+ return _el$69;
399
909
  })();
400
910
  },
401
911
  get children() {
402
- var _el$25 = _$createElement("input");
403
- _$use((el) => noteInputEl = el, _el$25);
404
- _$setProp(_el$25, "onInput", (value) => setNote(typeof value === "string" ? value : value?.target?.value ?? value?.value ?? String(value ?? "")));
405
- _$setProp(_el$25, "onSubmit", () => setFocused("options"));
406
- _$setProp(_el$25, "placeholder", "what was on your mind?");
407
- _$effect((_$p) => _$setProp(_el$25, "value", note(), _$p));
408
- return _el$25;
912
+ var _el$26 = _$createElement("input");
913
+ _$use((el) => noteInputEl = el, _el$26);
914
+ _$setProp(_el$26, "onInput", (value) => setNote(typeof value === "string" ? value : value?.target?.value ?? value?.value ?? String(value ?? "")));
915
+ _$setProp(_el$26, "onSubmit", () => {
916
+ if (!selected().size && !dontKnow() && note().trim())
917
+ submitSelect();
918
+ else
919
+ setFocused("options");
920
+ });
921
+ _$setProp(_el$26, "placeholder", "what was on your mind? (Enter to submit note \u2192 classify)");
922
+ _$effect((_$p) => _$setProp(_el$26, "value", note(), _$p));
923
+ return _el$26;
409
924
  }
410
925
  }));
411
- _$insertNode(_el$26, _el$27);
412
- _$setProp(_el$26, "flexDirection", "row");
413
- _$setProp(_el$26, "justifyContent", "space-between");
414
- _$setProp(_el$26, "paddingTop", 1);
415
- _$insertNode(_el$27, _$createTextNode(`\u2191\u2193/j k \xB7 Space toggle \xB7 \u2193 to Submit \u2192 Enter \xB7 Tab note \xB7 Esc cancel`));
416
- _$insert(_el$26, _$createComponent(Show, {
926
+ _$insertNode(_el$27, _el$28);
927
+ _$insertNode(_el$27, _el$29);
928
+ _$setProp(_el$27, "flexDirection", "row");
929
+ _$setProp(_el$27, "justifyContent", "space-between");
930
+ _$setProp(_el$27, "paddingTop", 1);
931
+ _$insert(_el$28, (() => {
932
+ var _c$2 = _$memo(() => !!isMulti());
933
+ return () => _c$2() ? `${selected().size} selected${dontKnow() ? " \xB7 I don't know" : ""}` : _$memo(() => !!(note().trim() && !selected().size && !dontKnow()))() ? "note \u2192 classify" : dontKnow() ? "I don't know" : "";
934
+ })());
935
+ _$insert(_el$29, () => focused() === "note" ? "Tab/Esc back" : "");
936
+ _$insert(_el$0, _$createComponent(Show, {
417
937
  get when() {
418
938
  return isMulti();
419
939
  },
420
940
  get children() {
421
- var _el$29 = _$createElement("text"), _el$30 = _$createTextNode(` selected `);
422
- _$insertNode(_el$29, _el$30);
423
- _$insert(_el$29, () => selected().size, _el$30);
424
- _$insert(_el$29, () => dontKnow() ? "\xB7 I don't know" : "", null);
425
- _$effect((_$p) => _$setProp(_el$29, "fg", selected().size > 0 || dontKnow() ? theme().success : theme().warning, _$p));
426
- return _el$29;
941
+ var _el$30 = _$createElement("box"), _el$31 = _$createElement("box"), _el$32 = _$createElement("text"), _el$33 = _$createElement("text"), _el$34 = _$createTextNode(`\u21B3 Submit`);
942
+ _$insertNode(_el$30, _el$31);
943
+ _$setProp(_el$30, "justifyContent", "center");
944
+ _$setProp(_el$30, "paddingTop", 1);
945
+ _$insertNode(_el$31, _el$32);
946
+ _$insertNode(_el$31, _el$33);
947
+ _$setProp(_el$31, "flexDirection", "row");
948
+ _$setProp(_el$31, "alignItems", "center");
949
+ _$setProp(_el$31, "gap", 1);
950
+ _$setProp(_el$31, "border", true);
951
+ _$setProp(_el$31, "paddingLeft", 2);
952
+ _$setProp(_el$31, "paddingRight", 2);
953
+ _$insert(_el$32, () => focused() === "options" && optionIndex() === submitIdx() ? "\u25B8" : " ");
954
+ _$insertNode(_el$33, _el$34);
955
+ _$setProp(_el$33, "bold", true);
956
+ _$insert(_el$33, () => note().trim() && !selected().size && !dontKnow() ? " note" : "", null);
957
+ _$effect((_p$) => {
958
+ var _v$5 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : selected().size > 0 || dontKnow() || note().trim() ? theme().success : theme().borderSubtle, _v$6 = focused() === "options" && optionIndex() === submitIdx() ? theme().backgroundElement : selected().size > 0 || dontKnow() || note().trim() ? theme().success : theme().background, _v$7 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : selected().size > 0 || dontKnow() || note().trim() ? theme().background : theme().textMuted, _v$8 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : selected().size > 0 || dontKnow() || note().trim() ? theme().background : theme().textMuted;
959
+ _v$5 !== _p$.e && (_p$.e = _$setProp(_el$31, "borderColor", _v$5, _p$.e));
960
+ _v$6 !== _p$.t && (_p$.t = _$setProp(_el$31, "backgroundColor", _v$6, _p$.t));
961
+ _v$7 !== _p$.a && (_p$.a = _$setProp(_el$32, "fg", _v$7, _p$.a));
962
+ _v$8 !== _p$.o && (_p$.o = _$setProp(_el$33, "fg", _v$8, _p$.o));
963
+ return _p$;
964
+ }, {
965
+ e: undefined,
966
+ t: undefined,
967
+ a: undefined,
968
+ o: undefined
969
+ });
970
+ return _el$30;
427
971
  }
428
972
  }), null);
429
- _$insert(_el$9, _$createComponent(Show, {
973
+ _$insert(_el$0, _$createComponent(Show, {
430
974
  get when() {
431
- return isMulti();
975
+ return _$memo(() => !!(!isMulti() && note().trim() && !selected().size))() && !dontKnow();
432
976
  },
433
977
  get children() {
434
- var _el$31 = _$createElement("box"), _el$32 = _$createElement("box"), _el$33 = _$createElement("text"), _el$34 = _$createElement("text");
435
- _$insertNode(_el$31, _el$32);
436
- _$setProp(_el$31, "justifyContent", "center");
437
- _$setProp(_el$31, "paddingTop", 1);
438
- _$insertNode(_el$32, _el$33);
439
- _$insertNode(_el$32, _el$34);
440
- _$setProp(_el$32, "flexDirection", "row");
441
- _$setProp(_el$32, "alignItems", "center");
442
- _$setProp(_el$32, "gap", 1);
443
- _$setProp(_el$32, "border", true);
444
- _$setProp(_el$32, "paddingLeft", 2);
445
- _$setProp(_el$32, "paddingRight", 2);
446
- _$insert(_el$33, () => focused() === "options" && optionIndex() === submitIdx() ? "\u25B8" : " ");
447
- _$insertNode(_el$34, _$createTextNode(`\u21B3 Submit`));
448
- _$setProp(_el$34, "bold", true);
978
+ var _el$35 = _$createElement("box"), _el$36 = _$createElement("box"), _el$37 = _$createElement("text");
979
+ _$insertNode(_el$35, _el$36);
980
+ _$setProp(_el$35, "justifyContent", "center");
981
+ _$setProp(_el$35, "paddingTop", 1);
982
+ _$insertNode(_el$36, _el$37);
983
+ _$setProp(_el$36, "flexDirection", "row");
984
+ _$setProp(_el$36, "alignItems", "center");
985
+ _$setProp(_el$36, "gap", 1);
986
+ _$setProp(_el$36, "border", true);
987
+ _$setProp(_el$36, "paddingLeft", 2);
988
+ _$setProp(_el$36, "paddingRight", 2);
989
+ _$insertNode(_el$37, _$createTextNode(`\u21B3 Submit note \u2192 classify`));
990
+ _$setProp(_el$37, "bold", true);
449
991
  _$effect((_p$) => {
450
- var _v$ = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : selected().size > 0 || dontKnow() ? theme().success : theme().borderSubtle, _v$2 = focused() === "options" && optionIndex() === submitIdx() ? theme().backgroundElement : selected().size > 0 || dontKnow() ? theme().success : theme().background, _v$3 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : selected().size > 0 || dontKnow() ? theme().background : theme().textMuted, _v$4 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : selected().size > 0 || dontKnow() ? theme().background : theme().textMuted;
451
- _v$ !== _p$.e && (_p$.e = _$setProp(_el$32, "borderColor", _v$, _p$.e));
452
- _v$2 !== _p$.t && (_p$.t = _$setProp(_el$32, "backgroundColor", _v$2, _p$.t));
453
- _v$3 !== _p$.a && (_p$.a = _$setProp(_el$33, "fg", _v$3, _p$.a));
454
- _v$4 !== _p$.o && (_p$.o = _$setProp(_el$34, "fg", _v$4, _p$.o));
992
+ var _v$9 = focused() === "options" && optionIndex() === dontKnowIdx() + 1 ? theme().accent : theme().success, _v$0 = focused() === "options" && optionIndex() === dontKnowIdx() + 1 ? theme().backgroundElement : theme().success, _v$1 = focused() === "options" && optionIndex() === dontKnowIdx() + 1 ? theme().accent : theme().background;
993
+ _v$9 !== _p$.e && (_p$.e = _$setProp(_el$36, "borderColor", _v$9, _p$.e));
994
+ _v$0 !== _p$.t && (_p$.t = _$setProp(_el$36, "backgroundColor", _v$0, _p$.t));
995
+ _v$1 !== _p$.a && (_p$.a = _$setProp(_el$37, "fg", _v$1, _p$.a));
455
996
  return _p$;
456
997
  }, {
457
998
  e: undefined,
458
999
  t: undefined,
459
- a: undefined,
460
- o: undefined
1000
+ a: undefined
461
1001
  });
462
- return _el$31;
1002
+ return _el$35;
463
1003
  }
464
1004
  }), null);
465
1005
  _$effect((_p$) => {
466
- var _v$5 = theme().borderSubtle, _v$6 = theme().background, _v$7 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().backgroundElement : undefined, _v$8 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().accent : theme().textMuted, _v$9 = dontKnow() ? theme().warning : theme().textMuted, _v$0 = dontKnow() ? theme().warning : theme().textMuted, _v$1 = focused() === "note" ? theme().accent : theme().textMuted, _v$10 = focused() === "note", _v$11 = focused() === "note" ? theme().accent : theme().borderSubtle, _v$12 = theme().backgroundElement, _v$13 = theme().textMuted;
467
- _v$5 !== _p$.e && (_p$.e = _$setProp(_el$9, "borderColor", _v$5, _p$.e));
468
- _v$6 !== _p$.t && (_p$.t = _$setProp(_el$9, "backgroundColor", _v$6, _p$.t));
469
- _v$7 !== _p$.a && (_p$.a = _$setProp(_el$10, "backgroundColor", _v$7, _p$.a));
470
- _v$8 !== _p$.o && (_p$.o = _$setProp(_el$12, "fg", _v$8, _p$.o));
471
- _v$9 !== _p$.i && (_p$.i = _$setProp(_el$14, "fg", _v$9, _p$.i));
472
- _v$0 !== _p$.n && (_p$.n = _$setProp(_el$16, "fg", _v$0, _p$.n));
473
- _v$1 !== _p$.s && (_p$.s = _$setProp(_el$20, "fg", _v$1, _p$.s));
474
- _v$10 !== _p$.h && (_p$.h = _$setProp(_el$20, "bold", _v$10, _p$.h));
475
- _v$11 !== _p$.r && (_p$.r = _$setProp(_el$24, "borderColor", _v$11, _p$.r));
476
- _v$12 !== _p$.d && (_p$.d = _$setProp(_el$24, "backgroundColor", _v$12, _p$.d));
477
- _v$13 !== _p$.l && (_p$.l = _$setProp(_el$27, "fg", _v$13, _p$.l));
1006
+ var _v$10 = theme().borderSubtle, _v$11 = theme().background, _v$12 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().backgroundElement : undefined, _v$13 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().accent : theme().textMuted, _v$14 = dontKnow() ? theme().warning : theme().textMuted, _v$15 = dontKnow() ? theme().warning : theme().textMuted, _v$16 = focused() === "note" ? theme().accent : theme().textMuted, _v$17 = focused() === "note", _v$18 = focused() === "note" ? theme().accent : theme().borderSubtle, _v$19 = theme().backgroundElement, _v$20 = theme().textMuted, _v$21 = theme().textMuted;
1007
+ _v$10 !== _p$.e && (_p$.e = _$setProp(_el$0, "borderColor", _v$10, _p$.e));
1008
+ _v$11 !== _p$.t && (_p$.t = _$setProp(_el$0, "backgroundColor", _v$11, _p$.t));
1009
+ _v$12 !== _p$.a && (_p$.a = _$setProp(_el$11, "backgroundColor", _v$12, _p$.a));
1010
+ _v$13 !== _p$.o && (_p$.o = _$setProp(_el$13, "fg", _v$13, _p$.o));
1011
+ _v$14 !== _p$.i && (_p$.i = _$setProp(_el$15, "fg", _v$14, _p$.i));
1012
+ _v$15 !== _p$.n && (_p$.n = _$setProp(_el$17, "fg", _v$15, _p$.n));
1013
+ _v$16 !== _p$.s && (_p$.s = _$setProp(_el$21, "fg", _v$16, _p$.s));
1014
+ _v$17 !== _p$.h && (_p$.h = _$setProp(_el$21, "bold", _v$17, _p$.h));
1015
+ _v$18 !== _p$.r && (_p$.r = _$setProp(_el$25, "borderColor", _v$18, _p$.r));
1016
+ _v$19 !== _p$.d && (_p$.d = _$setProp(_el$25, "backgroundColor", _v$19, _p$.d));
1017
+ _v$20 !== _p$.l && (_p$.l = _$setProp(_el$28, "fg", _v$20, _p$.l));
1018
+ _v$21 !== _p$.u && (_p$.u = _$setProp(_el$29, "fg", _v$21, _p$.u));
478
1019
  return _p$;
479
1020
  }, {
480
1021
  e: undefined,
@@ -487,26 +1028,65 @@ function QuizDialog(props) {
487
1028
  h: undefined,
488
1029
  r: undefined,
489
1030
  d: undefined,
490
- l: undefined
1031
+ l: undefined,
1032
+ u: undefined
491
1033
  });
492
- return _el$9;
1034
+ return _el$0;
493
1035
  }
494
1036
  }), null);
495
- _$insert(_el$, _$createComponent(Show, {
1037
+ _$insert(_el$6, _$createComponent(Show, {
1038
+ get when() {
1039
+ return phase() === "classifying";
1040
+ },
1041
+ get children() {
1042
+ var _el$39 = _$createElement("box"), _el$40 = _$createElement("text"), _el$42 = _$createElement("text"), _el$43 = _$createTextNode(`"`), _el$44 = _$createTextNode(`"`), _el$45 = _$createElement("text");
1043
+ _$insertNode(_el$39, _el$40);
1044
+ _$insertNode(_el$39, _el$42);
1045
+ _$insertNode(_el$39, _el$45);
1046
+ _$setProp(_el$39, "flexDirection", "column");
1047
+ _$setProp(_el$39, "gap", 1);
1048
+ _$setProp(_el$39, "padding", 1);
1049
+ _$setProp(_el$39, "border", true);
1050
+ _$setProp(_el$39, "alignItems", "center");
1051
+ _$insertNode(_el$40, _$createTextNode(`\u25D0 Classifying your note...`));
1052
+ _$setProp(_el$40, "bold", true);
1053
+ _$insertNode(_el$42, _el$43);
1054
+ _$insertNode(_el$42, _el$44);
1055
+ _$setProp(_el$42, "wrapMode", "wrap");
1056
+ _$insert(_el$42, note, _el$44);
1057
+ _$insertNode(_el$45, _$createTextNode(`Mapping to options \u2014 please wait`));
1058
+ _$effect((_p$) => {
1059
+ var _v$22 = theme().accent, _v$23 = theme().background, _v$24 = theme().accent, _v$25 = theme().textMuted, _v$26 = theme().textMuted;
1060
+ _v$22 !== _p$.e && (_p$.e = _$setProp(_el$39, "borderColor", _v$22, _p$.e));
1061
+ _v$23 !== _p$.t && (_p$.t = _$setProp(_el$39, "backgroundColor", _v$23, _p$.t));
1062
+ _v$24 !== _p$.a && (_p$.a = _$setProp(_el$40, "fg", _v$24, _p$.a));
1063
+ _v$25 !== _p$.o && (_p$.o = _$setProp(_el$42, "fg", _v$25, _p$.o));
1064
+ _v$26 !== _p$.i && (_p$.i = _$setProp(_el$45, "fg", _v$26, _p$.i));
1065
+ return _p$;
1066
+ }, {
1067
+ e: undefined,
1068
+ t: undefined,
1069
+ a: undefined,
1070
+ o: undefined,
1071
+ i: undefined
1072
+ });
1073
+ return _el$39;
1074
+ }
1075
+ }), null);
1076
+ _$insert(_el$6, _$createComponent(Show, {
496
1077
  get when() {
497
1078
  return phase() === "feedback";
498
1079
  },
499
1080
  get children() {
500
- var _el$36 = _$createElement("box"), _el$37 = _$createElement("box"), _el$38 = _$createElement("text"), _el$42 = _$createElement("text"), _el$43 = _$createTextNode(`Correct: `), _el$46 = _$createElement("box"), _el$47 = _$createElement("text"), _el$48 = _$createElement("box"), _el$49 = _$createElement("text");
501
- _$insertNode(_el$36, _el$37);
502
- _$insertNode(_el$36, _el$42);
503
- _$insertNode(_el$36, _el$46);
504
- _$insertNode(_el$36, _el$48);
505
- _$setProp(_el$36, "flexDirection", "column");
506
- _$setProp(_el$36, "gap", 1);
507
- _$setProp(_el$36, "padding", 1);
508
- _$setProp(_el$36, "border", true);
509
- _$insert(_el$36, _$createComponent(For, {
1081
+ var _el$47 = _$createElement("box"), _el$48 = _$createElement("box"), _el$49 = _$createElement("text"), _el$53 = _$createElement("text"), _el$54 = _$createTextNode(`Correct: `), _el$57 = _$createElement("box"), _el$58 = _$createElement("markdown");
1082
+ _$insertNode(_el$47, _el$48);
1083
+ _$insertNode(_el$47, _el$53);
1084
+ _$insertNode(_el$47, _el$57);
1085
+ _$setProp(_el$47, "flexDirection", "column");
1086
+ _$setProp(_el$47, "gap", 1);
1087
+ _$setProp(_el$47, "padding", 1);
1088
+ _$setProp(_el$47, "border", true);
1089
+ _$insert(_el$47, _$createComponent(For, {
510
1090
  get each() {
511
1091
  return options();
512
1092
  },
@@ -535,90 +1115,86 @@ function QuizDialog(props) {
535
1115
  bg = theme().warning;
536
1116
  }
537
1117
  return (() => {
538
- var _el$60 = _$createElement("box"), _el$61 = _$createElement("box"), _el$62 = _$createElement("text"), _el$63 = _$createElement("box"), _el$64 = _$createElement("text"), _el$65 = _$createTextNode(`. `);
539
- _$insertNode(_el$60, _el$61);
540
- _$insertNode(_el$60, _el$63);
541
- _$setProp(_el$60, "flexDirection", "row");
542
- _$setProp(_el$60, "alignItems", "flexStart");
543
- _$setProp(_el$60, "gap", 1);
544
- _$setProp(_el$60, "paddingLeft", 1);
545
- _$setProp(_el$60, "backgroundColor", bg);
546
- _$insertNode(_el$61, _el$62);
547
- _$setProp(_el$61, "width", 2);
548
- _$setProp(_el$61, "alignItems", "center");
549
- _$setProp(_el$62, "fg", fg);
550
- _$setProp(_el$62, "bold", true);
551
- _$insert(_el$62, icon);
552
- _$insertNode(_el$63, _el$64);
553
- _$setProp(_el$63, "flexGrow", 1);
554
- _$insertNode(_el$64, _el$65);
555
- _$setProp(_el$64, "fg", fg);
556
- _$setProp(_el$64, "wrapMode", "wrap");
557
- _$insert(_el$64, idx, _el$65);
558
- _$insert(_el$64, () => opt.label, null);
559
- return _el$60;
1118
+ var _el$70 = _$createElement("box"), _el$71 = _$createElement("box"), _el$72 = _$createElement("text"), _el$73 = _$createElement("box"), _el$74 = _$createElement("text"), _el$75 = _$createTextNode(`. `);
1119
+ _$insertNode(_el$70, _el$71);
1120
+ _$insertNode(_el$70, _el$73);
1121
+ _$setProp(_el$70, "flexDirection", "row");
1122
+ _$setProp(_el$70, "alignItems", "flexStart");
1123
+ _$setProp(_el$70, "gap", 1);
1124
+ _$setProp(_el$70, "paddingLeft", 1);
1125
+ _$setProp(_el$70, "backgroundColor", bg);
1126
+ _$insertNode(_el$71, _el$72);
1127
+ _$setProp(_el$71, "width", 2);
1128
+ _$setProp(_el$71, "alignItems", "center");
1129
+ _$setProp(_el$72, "fg", fg);
1130
+ _$setProp(_el$72, "bold", true);
1131
+ _$insert(_el$72, icon);
1132
+ _$insertNode(_el$73, _el$74);
1133
+ _$setProp(_el$73, "flexGrow", 1);
1134
+ _$insertNode(_el$74, _el$75);
1135
+ _$setProp(_el$74, "fg", fg);
1136
+ _$setProp(_el$74, "wrapMode", "wrap");
1137
+ _$insert(_el$74, idx, _el$75);
1138
+ _$insert(_el$74, () => opt.label, null);
1139
+ return _el$70;
560
1140
  })();
561
1141
  }
562
- }), _el$37);
563
- _$insertNode(_el$37, _el$38);
564
- _$setProp(_el$37, "height", 1);
565
- _$insert(_el$38, () => "\u2500".repeat(Math.max(20, popupWidth() - 12)));
566
- _$insert(_el$36, _$createComponent(Show, {
1142
+ }), _el$48);
1143
+ _$insertNode(_el$48, _el$49);
1144
+ _$setProp(_el$48, "height", 1);
1145
+ _$insert(_el$49, () => "\u2500".repeat(Math.max(20, popupWidth() - 12)));
1146
+ _$insert(_el$47, _$createComponent(Show, {
567
1147
  get when() {
568
1148
  return dontKnow();
569
1149
  },
570
1150
  get children() {
571
- var _el$39 = _$createElement("text");
572
- _$insertNode(_el$39, _$createTextNode(`\u25CF You said: I don't know \u2014 genuine gap`));
573
- _$effect((_$p) => _$setProp(_el$39, "fg", theme().warning, _$p));
574
- return _el$39;
1151
+ var _el$50 = _$createElement("text");
1152
+ _$insertNode(_el$50, _$createTextNode(`\u25CF You said: I don't know \u2014 genuine gap`));
1153
+ _$effect((_$p) => _$setProp(_el$50, "fg", theme().warning, _$p));
1154
+ return _el$50;
575
1155
  }
576
- }), _el$42);
577
- _$insert(_el$36, _$createComponent(Show, {
1156
+ }), _el$53);
1157
+ _$insert(_el$47, _$createComponent(Show, {
578
1158
  get when() {
579
1159
  return !dontKnow();
580
1160
  },
581
1161
  get children() {
582
- var _el$41 = _$createElement("text");
583
- _$setProp(_el$41, "bold", true);
584
- _$insert(_el$41, () => feedback()?.correct ? "\u2713 Correct! Well located." : "\u2717 Incorrect \u2014 nice try, let's fix the edge.");
585
- _$effect((_$p) => _$setProp(_el$41, "fg", feedback()?.correct ? theme().success : theme().error, _$p));
586
- return _el$41;
1162
+ var _el$52 = _$createElement("text");
1163
+ _$setProp(_el$52, "bold", true);
1164
+ _$insert(_el$52, () => feedback()?.correct ? "\u2713 Correct! Well located." : "\u2717 Incorrect \u2014 nice try, let's fix the edge.");
1165
+ _$effect((_$p) => _$setProp(_el$52, "fg", feedback()?.correct ? theme().success : theme().error, _$p));
1166
+ return _el$52;
587
1167
  }
588
- }), _el$42);
589
- _$insertNode(_el$42, _el$43);
590
- _$insert(_el$42, () => props.request.correctIndices.map((i) => `${i}. ${options()[i - 1]?.label}`).join(", "), null);
591
- _$insert(_el$36, _$createComponent(Show, {
1168
+ }), _el$53);
1169
+ _$insertNode(_el$53, _el$54);
1170
+ _$insert(_el$53, () => props.request.correctIndices.map((i) => `${i}. ${options()[i - 1]?.label}`).join(", "), null);
1171
+ _$insert(_el$47, _$createComponent(Show, {
592
1172
  get when() {
593
1173
  return note();
594
1174
  },
595
1175
  get children() {
596
- var _el$44 = _$createElement("text"), _el$45 = _$createTextNode(`Your note: `);
597
- _$insertNode(_el$44, _el$45);
598
- _$insert(_el$44, note, null);
599
- _$effect((_$p) => _$setProp(_el$44, "fg", theme().textMuted, _$p));
600
- return _el$44;
1176
+ var _el$55 = _$createElement("text"), _el$56 = _$createTextNode(`Your note: `);
1177
+ _$insertNode(_el$55, _el$56);
1178
+ _$insert(_el$55, note, null);
1179
+ _$effect((_$p) => _$setProp(_el$55, "fg", theme().textMuted, _$p));
1180
+ return _el$55;
601
1181
  }
602
- }), _el$46);
603
- _$insertNode(_el$46, _el$47);
604
- _$setProp(_el$46, "border", true);
605
- _$setProp(_el$46, "padding", 1);
606
- _$setProp(_el$47, "wrapMode", "wrap");
607
- _$insert(_el$47, () => props.request.explanation);
608
- _$insertNode(_el$48, _el$49);
609
- _$setProp(_el$48, "justifyContent", "center");
610
- _$setProp(_el$48, "paddingTop", 1);
611
- _$insertNode(_el$49, _$createTextNode(`\u21B5 Enter / Esc to continue \u2192 next probe`));
1182
+ }), _el$57);
1183
+ _$insertNode(_el$57, _el$58);
1184
+ _$setProp(_el$57, "border", true);
1185
+ _$setProp(_el$57, "padding", 1);
612
1186
  _$effect((_p$) => {
613
- var _v$14 = feedback()?.correct ? theme().success : theme().error, _v$15 = theme().background, _v$16 = theme().borderSubtle, _v$17 = theme().textMuted, _v$18 = theme().borderSubtle, _v$19 = theme().backgroundPanel, _v$20 = theme().text, _v$21 = theme().textMuted;
614
- _v$14 !== _p$.e && (_p$.e = _$setProp(_el$36, "borderColor", _v$14, _p$.e));
615
- _v$15 !== _p$.t && (_p$.t = _$setProp(_el$36, "backgroundColor", _v$15, _p$.t));
616
- _v$16 !== _p$.a && (_p$.a = _$setProp(_el$38, "fg", _v$16, _p$.a));
617
- _v$17 !== _p$.o && (_p$.o = _$setProp(_el$42, "fg", _v$17, _p$.o));
618
- _v$18 !== _p$.i && (_p$.i = _$setProp(_el$46, "borderColor", _v$18, _p$.i));
619
- _v$19 !== _p$.n && (_p$.n = _$setProp(_el$46, "backgroundColor", _v$19, _p$.n));
620
- _v$20 !== _p$.s && (_p$.s = _$setProp(_el$47, "fg", _v$20, _p$.s));
621
- _v$21 !== _p$.h && (_p$.h = _$setProp(_el$49, "fg", _v$21, _p$.h));
1187
+ var _v$27 = feedback()?.correct ? theme().success : theme().error, _v$28 = theme().background, _v$29 = theme().borderSubtle, _v$30 = theme().textMuted, _v$31 = theme().borderSubtle, _v$32 = theme().backgroundPanel, _v$33 = syntax(), _v$34 = decodeQuizText(props.request.explanation), _v$35 = theme().text, _v$36 = theme().backgroundPanel;
1188
+ _v$27 !== _p$.e && (_p$.e = _$setProp(_el$47, "borderColor", _v$27, _p$.e));
1189
+ _v$28 !== _p$.t && (_p$.t = _$setProp(_el$47, "backgroundColor", _v$28, _p$.t));
1190
+ _v$29 !== _p$.a && (_p$.a = _$setProp(_el$49, "fg", _v$29, _p$.a));
1191
+ _v$30 !== _p$.o && (_p$.o = _$setProp(_el$53, "fg", _v$30, _p$.o));
1192
+ _v$31 !== _p$.i && (_p$.i = _$setProp(_el$57, "borderColor", _v$31, _p$.i));
1193
+ _v$32 !== _p$.n && (_p$.n = _$setProp(_el$57, "backgroundColor", _v$32, _p$.n));
1194
+ _v$33 !== _p$.s && (_p$.s = _$setProp(_el$58, "syntaxStyle", _v$33, _p$.s));
1195
+ _v$34 !== _p$.h && (_p$.h = _$setProp(_el$58, "content", _v$34, _p$.h));
1196
+ _v$35 !== _p$.r && (_p$.r = _$setProp(_el$58, "fg", _v$35, _p$.r));
1197
+ _v$36 !== _p$.d && (_p$.d = _$setProp(_el$58, "bg", _v$36, _p$.d));
622
1198
  return _p$;
623
1199
  }, {
624
1200
  e: undefined,
@@ -628,20 +1204,42 @@ function QuizDialog(props) {
628
1204
  i: undefined,
629
1205
  n: undefined,
630
1206
  s: undefined,
631
- h: undefined
1207
+ h: undefined,
1208
+ r: undefined,
1209
+ d: undefined
632
1210
  });
633
- return _el$36;
1211
+ return _el$47;
634
1212
  }
635
1213
  }), null);
1214
+ _$insertNode(_el$59, _el$60);
1215
+ _$setProp(_el$59, "height", 1);
1216
+ _$setProp(_el$59, "justifyContent", "center");
1217
+ _$setProp(_el$60, "wrapMode", "wrap");
1218
+ _$insert(_el$60, (() => {
1219
+ var _c$3 = _$memo(() => phase() === "feedback");
1220
+ return () => _c$3() ? _$memo(() => !!(canScrollUp() && canScrollDown()))() ? "\u25B2 more above \xB7 \u25BC more below \u2014 d/u to scroll \xB7 Enter to continue" : _$memo(() => !!canScrollDown())() ? "\u25BC more below \u2014 d to scroll \xB7 Enter to continue" : canScrollUp() ? "\u25B2 more above \u2014 u to scroll \xB7 Enter to continue" : "\u21B5 Enter / Esc to continue \u2192 next probe" : _$memo(() => phase() === "classifying")() ? "Classifying your note..." : _$memo(() => focused() === "note")() ? "Enter submit note \u2192 classify \xB7 Tab/Esc back" : canScrollUp() || canScrollDown() ? "j/k or \u2191\u2193 move \xB7 Space toggle \xB7 Tab note \xB7 Enter submit \xB7 Esc cancel \xB7 d/u scroll" : "j/k or \u2191\u2193 move \xB7 Space toggle \xB7 Tab note \xB7 Enter submit \xB7 Esc cancel";
1221
+ })());
636
1222
  _$effect((_p$) => {
637
- var _v$22 = popupWidth(), _v$23 = phase() === "feedback" ? feedback()?.correct ? theme().success : theme().error : theme().accent, _v$24 = theme().backgroundPanel, _v$25 = phase() === "feedback" ? feedback()?.correct ? theme().success : theme().error : theme().accent, _v$26 = theme().background, _v$27 = theme().background, _v$28 = theme().text;
638
- _v$22 !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$22, _p$.e));
639
- _v$23 !== _p$.t && (_p$.t = _$setProp(_el$, "borderColor", _v$23, _p$.t));
640
- _v$24 !== _p$.a && (_p$.a = _$setProp(_el$, "backgroundColor", _v$24, _p$.a));
641
- _v$25 !== _p$.o && (_p$.o = _$setProp(_el$2, "backgroundColor", _v$25, _p$.o));
642
- _v$26 !== _p$.i && (_p$.i = _$setProp(_el$3, "fg", _v$26, _p$.i));
643
- _v$27 !== _p$.n && (_p$.n = _$setProp(_el$4, "fg", _v$27, _p$.n));
644
- _v$28 !== _p$.s && (_p$.s = _$setProp(_el$7, "fg", _v$28, _p$.s));
1223
+ var _v$37 = popupWidth(), _v$38 = popupHeight(), _v$39 = phase() === "feedback" ? feedback()?.correct ? theme().success : theme().error : theme().accent, _v$40 = theme().backgroundPanel, _v$41 = phase() === "feedback" ? feedback()?.correct ? theme().success : theme().error : theme().accent, _v$42 = theme().background, _v$43 = theme().background, _v$44 = {
1224
+ visible: true,
1225
+ trackOptions: {
1226
+ backgroundColor: theme().background,
1227
+ foregroundColor: theme().borderActive
1228
+ }
1229
+ }, _v$45 = syntax(), _v$46 = decodeQuizText(props.request.question), _v$47 = theme().text, _v$48 = theme().backgroundPanel, _v$49 = theme().textMuted;
1230
+ _v$37 !== _p$.e && (_p$.e = _$setProp(_el$, "width", _v$37, _p$.e));
1231
+ _v$38 !== _p$.t && (_p$.t = _$setProp(_el$, "height", _v$38, _p$.t));
1232
+ _v$39 !== _p$.a && (_p$.a = _$setProp(_el$, "borderColor", _v$39, _p$.a));
1233
+ _v$40 !== _p$.o && (_p$.o = _$setProp(_el$, "backgroundColor", _v$40, _p$.o));
1234
+ _v$41 !== _p$.i && (_p$.i = _$setProp(_el$2, "backgroundColor", _v$41, _p$.i));
1235
+ _v$42 !== _p$.n && (_p$.n = _$setProp(_el$3, "fg", _v$42, _p$.n));
1236
+ _v$43 !== _p$.s && (_p$.s = _$setProp(_el$4, "fg", _v$43, _p$.s));
1237
+ _v$44 !== _p$.h && (_p$.h = _$setProp(_el$6, "verticalScrollbarOptions", _v$44, _p$.h));
1238
+ _v$45 !== _p$.r && (_p$.r = _$setProp(_el$8, "syntaxStyle", _v$45, _p$.r));
1239
+ _v$46 !== _p$.d && (_p$.d = _$setProp(_el$8, "content", _v$46, _p$.d));
1240
+ _v$47 !== _p$.l && (_p$.l = _$setProp(_el$8, "fg", _v$47, _p$.l));
1241
+ _v$48 !== _p$.u && (_p$.u = _$setProp(_el$8, "bg", _v$48, _p$.u));
1242
+ _v$49 !== _p$.c && (_p$.c = _$setProp(_el$60, "fg", _v$49, _p$.c));
645
1243
  return _p$;
646
1244
  }, {
647
1245
  e: undefined,
@@ -650,15 +1248,23 @@ function QuizDialog(props) {
650
1248
  o: undefined,
651
1249
  i: undefined,
652
1250
  n: undefined,
653
- s: undefined
1251
+ s: undefined,
1252
+ h: undefined,
1253
+ r: undefined,
1254
+ d: undefined,
1255
+ l: undefined,
1256
+ u: undefined,
1257
+ c: undefined
654
1258
  });
655
1259
  return _el$;
656
1260
  })();
657
1261
  }
658
1262
  function QuizBatchDialog(props) {
659
1263
  const theme = () => props.api.theme.current;
1264
+ const syntax = () => syntaxStyle(theme());
660
1265
  const dims = useTerminalDimensions();
661
1266
  const popupWidth = () => Math.max(68, Math.min(dims().width - 4, 96));
1267
+ const popupHeight = () => Math.max(4, Math.min(24, dims().height - 2));
662
1268
  const [idx, setIdx] = createSignal(0);
663
1269
  if (!props.request.quizzes || props.request.quizzes.length === 0) {
664
1270
  tlog("QuizBatchDialog empty quizzes, cancelling", props.request.id);
@@ -678,6 +1284,40 @@ function QuizBatchDialog(props) {
678
1284
  const dontKnowIdx = () => cur().options.length;
679
1285
  const submitIdx = () => isMulti() ? cur().options.length + 1 : -1;
680
1286
  let noteEl;
1287
+ let scrollRefBatch;
1288
+ const [canScrollUpBatch, setCanScrollUpBatch] = createSignal(false);
1289
+ const [canScrollDownBatch, setCanScrollDownBatch] = createSignal(false);
1290
+ const updateScrollBatch = () => {
1291
+ try {
1292
+ if (!scrollRefBatch) {
1293
+ setCanScrollUpBatch(false);
1294
+ setCanScrollDownBatch(false);
1295
+ return;
1296
+ }
1297
+ const st = typeof scrollRefBatch.scrollTop === "number" ? scrollRefBatch.scrollTop : 0;
1298
+ const h = typeof scrollRefBatch.height === "number" ? scrollRefBatch.height : scrollRefBatch.viewportHeight ?? popupHeight();
1299
+ const sh = typeof scrollRefBatch.scrollHeight === "number" ? scrollRefBatch.scrollHeight : 0;
1300
+ let effectiveSh = sh;
1301
+ if (!effectiveSh && typeof scrollRefBatch.getChildren === "function") {
1302
+ try {
1303
+ const kids = scrollRefBatch.getChildren();
1304
+ if (kids?.length)
1305
+ effectiveSh = Math.max(...kids.map((c) => (c.y || 0) + (c.height || 0)), h);
1306
+ } catch {}
1307
+ }
1308
+ if (!effectiveSh || effectiveSh <= h + 1) {
1309
+ setCanScrollUpBatch(false);
1310
+ setCanScrollDownBatch(false);
1311
+ return;
1312
+ }
1313
+ setCanScrollUpBatch(st > 0);
1314
+ setCanScrollDownBatch(st + h < effectiveSh - 1);
1315
+ } catch {
1316
+ setCanScrollUpBatch(false);
1317
+ setCanScrollDownBatch(false);
1318
+ }
1319
+ };
1320
+ const scrollAmountBatch = () => Math.max(1, Math.floor((scrollRefBatch?.height ?? popupHeight()) / 3));
681
1321
  createEffect(() => {
682
1322
  if (focused() === "note" && noteEl)
683
1323
  try {
@@ -686,6 +1326,24 @@ function QuizBatchDialog(props) {
686
1326
  tlog("note focus failed", String(e));
687
1327
  }
688
1328
  });
1329
+ createEffect(() => {
1330
+ phase();
1331
+ feedback();
1332
+ dims();
1333
+ idx();
1334
+ setTimeout(updateScrollBatch, 40);
1335
+ setTimeout(updateScrollBatch, 200);
1336
+ });
1337
+ createEffect(() => {
1338
+ note();
1339
+ setTimeout(updateScrollBatch, 40);
1340
+ });
1341
+ createEffect(() => {
1342
+ if (phase() !== "feedback" && phase() !== "select")
1343
+ return;
1344
+ const id = setInterval(updateScrollBatch, 200);
1345
+ onCleanup(() => clearInterval(id));
1346
+ });
689
1347
  const toggle = (i) => {
690
1348
  try {
691
1349
  const o = cur().options[i];
@@ -747,10 +1405,106 @@ function QuizBatchDialog(props) {
747
1405
  const submitSelect = () => {
748
1406
  try {
749
1407
  const m = selected();
750
- if (!isMulti() && m.size === 0 && !dontKnow())
1408
+ if (!isMulti() && m.size === 0 && !dontKnow() && !note().trim())
751
1409
  return;
752
- if (isMulti() && m.size === 0 && !dontKnow())
1410
+ if (isMulti() && m.size === 0 && !dontKnow() && !note().trim())
753
1411
  return;
1412
+ if (m.size === 0 && !dontKnow() && note().trim()) {
1413
+ setPhase("classifying");
1414
+ try {
1415
+ const pDir = globalThis.__learnPendingDir || ".opencode/learn-pending";
1416
+ const cid = `${props.request.id}-${idx()}`;
1417
+ const routeSessionID = props.api.route?.current?.params?.sessionID;
1418
+ const pendingClassify = {
1419
+ id: cid,
1420
+ type: "classify",
1421
+ note: note().trim(),
1422
+ question: cur().question,
1423
+ options: cur().options.map((o, i) => ({
1424
+ label: o.label,
1425
+ value: o.value,
1426
+ index: i + 1
1427
+ })),
1428
+ timestamp: Date.now(),
1429
+ sessionID: props.request.sessionID || routeSessionID
1430
+ };
1431
+ fs.writeFileSync(path.join(pDir, `classify-${cid}.json`), JSON.stringify(pendingClassify), "utf8");
1432
+ tlog("QuizBatchDialog classify request", cid, note().trim().slice(0, 50));
1433
+ const respPath = path.join(pDir, `classify-response-${cid}.json`);
1434
+ let attempts = 0;
1435
+ const poll = setInterval(() => {
1436
+ attempts++;
1437
+ if (attempts > 60) {
1438
+ clearInterval(poll);
1439
+ setFeedback({
1440
+ correct: false,
1441
+ selectedIndices: []
1442
+ });
1443
+ setPhase("feedback");
1444
+ return;
1445
+ }
1446
+ try {
1447
+ if (fs.existsSync(respPath)) {
1448
+ clearInterval(poll);
1449
+ const raw = fs.readFileSync(respPath, "utf8");
1450
+ const data = JSON.parse(raw);
1451
+ try {
1452
+ fs.unlinkSync(respPath);
1453
+ fs.unlinkSync(path.join(pDir, `classify-${cid}.json`));
1454
+ } catch {}
1455
+ const inferred = data?.inferredIndices;
1456
+ const semanticCorrect = data?.semanticCorrect;
1457
+ const reason = data?.reason;
1458
+ const computeOk2 = (idxs) => {
1459
+ if (typeof semanticCorrect === "boolean")
1460
+ return semanticCorrect;
1461
+ const correctSet2 = new Set(cur().correctIndices);
1462
+ return idxs.length === cur().correctIndices.length && idxs.every((v) => correctSet2.has(v)) && cur().correctIndices.every((v) => idxs.includes(v));
1463
+ };
1464
+ if (inferred && inferred.length) {
1465
+ const mm = new Map;
1466
+ for (const idx2 of inferred) {
1467
+ const opt = cur().options[idx2 - 1];
1468
+ if (opt)
1469
+ mm.set(`opt:${idx2 - 1}`, {
1470
+ label: opt.label,
1471
+ value: opt.value,
1472
+ index: idx2
1473
+ });
1474
+ }
1475
+ setSelected(mm);
1476
+ const ok2 = computeOk2(inferred);
1477
+ setFeedback({
1478
+ correct: ok2,
1479
+ selectedIndices: inferred
1480
+ });
1481
+ if (reason)
1482
+ setNote((prev) => prev ? `${prev} \u2014 ${reason}` : prev);
1483
+ tlog("QuizBatchDialog classify done", inferred.join(","), ok2, reason || "");
1484
+ } else {
1485
+ const ok2 = typeof semanticCorrect === "boolean" ? semanticCorrect : false;
1486
+ setFeedback({
1487
+ correct: ok2,
1488
+ selectedIndices: []
1489
+ });
1490
+ if (reason)
1491
+ setNote((prev) => prev ? `${prev} \u2014 ${reason}` : reason);
1492
+ }
1493
+ setPhase("feedback");
1494
+ }
1495
+ } catch {}
1496
+ }, 500);
1497
+ onCleanup(() => clearInterval(poll));
1498
+ } catch (e) {
1499
+ tlog("classify batch failed", String(e));
1500
+ setFeedback({
1501
+ correct: false,
1502
+ selectedIndices: []
1503
+ });
1504
+ setPhase("feedback");
1505
+ }
1506
+ return;
1507
+ }
754
1508
  const sel = Array.from(m.values());
755
1509
  const dk = dontKnow();
756
1510
  const correctSet = new Set(cur().correctIndices);
@@ -766,12 +1520,63 @@ function QuizBatchDialog(props) {
766
1520
  tlog("submitSelect failed", String(e));
767
1521
  }
768
1522
  };
1523
+ const isPlainKeyBatch = (evt, want) => {
1524
+ try {
1525
+ const n = String(evt.name || evt.sequence || "").toLowerCase();
1526
+ if (n !== want.toLowerCase())
1527
+ return false;
1528
+ if (evt.ctrl || evt.meta || evt.option || evt.alt)
1529
+ return false;
1530
+ return true;
1531
+ } catch {
1532
+ return false;
1533
+ }
1534
+ };
769
1535
  useKeyboard((evt) => {
770
1536
  try {
771
1537
  const k = evt.name || evt.sequence || evt.raw || "";
772
1538
  const seq = evt.sequence || "";
1539
+ const lower = String(k || "").toLowerCase();
1540
+ if (phase() === "classifying") {
1541
+ prevent(evt);
1542
+ return;
1543
+ }
773
1544
  if (phase() === "feedback") {
774
- if (k === "enter" || seq === "\r" || k === "escape" || k === "esc") {
1545
+ if (isPlainKeyBatch(evt, "d") || seq === "\x04") {
1546
+ prevent(evt);
1547
+ try {
1548
+ scrollRefBatch?.scrollBy(scrollAmountBatch());
1549
+ setTimeout(updateScrollBatch, 30);
1550
+ setTimeout(updateScrollBatch, 120);
1551
+ } catch {}
1552
+ return;
1553
+ }
1554
+ if (isPlainKeyBatch(evt, "u") || seq === "\x15") {
1555
+ prevent(evt);
1556
+ try {
1557
+ scrollRefBatch?.scrollBy(-scrollAmountBatch());
1558
+ setTimeout(updateScrollBatch, 30);
1559
+ setTimeout(updateScrollBatch, 120);
1560
+ } catch {}
1561
+ return;
1562
+ }
1563
+ if (lower === "pageup" || seq === "\x1B[5~") {
1564
+ prevent(evt);
1565
+ try {
1566
+ scrollRefBatch?.scrollBy(-scrollAmountBatch());
1567
+ setTimeout(updateScrollBatch, 30);
1568
+ } catch {}
1569
+ return;
1570
+ }
1571
+ if (lower === "pagedown" || seq === "\x1B[6~") {
1572
+ prevent(evt);
1573
+ try {
1574
+ scrollRefBatch?.scrollBy(scrollAmountBatch());
1575
+ setTimeout(updateScrollBatch, 30);
1576
+ } catch {}
1577
+ return;
1578
+ }
1579
+ if (lower === "enter" || seq === "\r" || lower === "escape" || lower === "esc") {
775
1580
  prevent(evt);
776
1581
  goNext();
777
1582
  }
@@ -790,6 +1595,24 @@ function QuizBatchDialog(props) {
790
1595
  }
791
1596
  return;
792
1597
  }
1598
+ if (phase() === "select" && (isPlainKeyBatch(evt, "d") || seq === "\x04")) {
1599
+ prevent(evt);
1600
+ try {
1601
+ scrollRefBatch?.scrollBy(scrollAmountBatch());
1602
+ setTimeout(updateScrollBatch, 30);
1603
+ setTimeout(updateScrollBatch, 120);
1604
+ } catch {}
1605
+ return;
1606
+ }
1607
+ if (phase() === "select" && (isPlainKeyBatch(evt, "u") || seq === "\x15")) {
1608
+ prevent(evt);
1609
+ try {
1610
+ scrollRefBatch?.scrollBy(-scrollAmountBatch());
1611
+ setTimeout(updateScrollBatch, 30);
1612
+ setTimeout(updateScrollBatch, 120);
1613
+ } catch {}
1614
+ return;
1615
+ }
793
1616
  if (k === "up" || k === "k" || seq === "\x1B[A") {
794
1617
  prevent(evt);
795
1618
  setOptionIndex((i) => Math.max(0, i - 1));
@@ -870,62 +1693,73 @@ function QuizBatchDialog(props) {
870
1693
  }
871
1694
  });
872
1695
  return (() => {
873
- var _el$66 = _$createElement("box"), _el$67 = _$createElement("box"), _el$68 = _$createElement("text"), _el$69 = _$createTextNode(` decks.quiz batch `), _el$70 = _$createTextNode(`/`), _el$71 = _$createTextNode(` `), _el$72 = _$createElement("text"), _el$74 = _$createElement("text");
874
- _$insertNode(_el$66, _el$67);
875
- _$insertNode(_el$66, _el$74);
876
- _$setProp(_el$66, "flexDirection", "column");
877
- _$setProp(_el$66, "border", true);
878
- _$setProp(_el$66, "padding", 1);
879
- _$setProp(_el$66, "gap", 1);
880
- _$insertNode(_el$67, _el$68);
881
- _$insertNode(_el$67, _el$72);
882
- _$setProp(_el$67, "flexDirection", "row");
883
- _$setProp(_el$67, "justifyContent", "space-between");
884
- _$setProp(_el$67, "paddingLeft", 1);
885
- _$setProp(_el$67, "paddingRight", 1);
886
- _$setProp(_el$67, "height", 1);
887
- _$insertNode(_el$68, _el$69);
888
- _$insertNode(_el$68, _el$70);
889
- _$insertNode(_el$68, _el$71);
890
- _$setProp(_el$68, "bold", true);
891
- _$insert(_el$68, () => idx() + 1, _el$70);
892
- _$insert(_el$68, () => props.request.quizzes.length, _el$71);
893
- _$insert(_el$68, (() => {
894
- var _c$3 = _$memo(() => phase() === "feedback");
895
- return () => _c$3() ? feedback()?.correct ? "\u2713" : "\u2717" : "";
1696
+ var _el$76 = _$createElement("box"), _el$77 = _$createElement("box"), _el$78 = _$createElement("text"), _el$79 = _$createTextNode(` decks.quiz batch `), _el$80 = _$createTextNode(`/`), _el$81 = _$createTextNode(` `), _el$82 = _$createElement("text"), _el$84 = _$createElement("scrollbox"), _el$85 = _$createElement("markdown"), _el$126 = _$createElement("box"), _el$127 = _$createElement("text");
1697
+ _$insertNode(_el$76, _el$77);
1698
+ _$insertNode(_el$76, _el$84);
1699
+ _$insertNode(_el$76, _el$126);
1700
+ _$setProp(_el$76, "flexDirection", "column");
1701
+ _$setProp(_el$76, "border", true);
1702
+ _$setProp(_el$76, "padding", 1);
1703
+ _$setProp(_el$76, "gap", 1);
1704
+ _$insertNode(_el$77, _el$78);
1705
+ _$insertNode(_el$77, _el$82);
1706
+ _$setProp(_el$77, "flexDirection", "row");
1707
+ _$setProp(_el$77, "justifyContent", "space-between");
1708
+ _$setProp(_el$77, "paddingLeft", 1);
1709
+ _$setProp(_el$77, "paddingRight", 1);
1710
+ _$setProp(_el$77, "height", 1);
1711
+ _$insertNode(_el$78, _el$79);
1712
+ _$insertNode(_el$78, _el$80);
1713
+ _$insertNode(_el$78, _el$81);
1714
+ _$setProp(_el$78, "bold", true);
1715
+ _$insert(_el$78, () => idx() + 1, _el$80);
1716
+ _$insert(_el$78, () => props.request.quizzes.length, _el$81);
1717
+ _$insert(_el$78, (() => {
1718
+ var _c$5 = _$memo(() => phase() === "feedback");
1719
+ return () => _c$5() ? feedback()?.correct ? "\u2713" : "\u2717" : "";
896
1720
  })(), null);
897
- _$insertNode(_el$72, _$createTextNode(`learn`));
898
- _$setProp(_el$72, "dim", true);
899
- _$setProp(_el$74, "bold", true);
900
- _$setProp(_el$74, "wrapMode", "wrap");
901
- _$insert(_el$74, () => cur().question);
902
- _$insert(_el$66, _$createComponent(Show, {
1721
+ _$insertNode(_el$82, _$createTextNode(`learn`));
1722
+ _$setProp(_el$82, "dim", true);
1723
+ _$insertNode(_el$84, _el$85);
1724
+ _$use((el) => scrollRefBatch = el, _el$84);
1725
+ _$setProp(_el$84, "flexGrow", 1);
1726
+ _$insert(_el$84, _$createComponent(Show, {
903
1727
  get when() {
904
1728
  return cur().details;
905
1729
  },
906
1730
  get children() {
907
- var _el$75 = _$createElement("text");
908
- _$setProp(_el$75, "wrapMode", "wrap");
909
- _$insert(_el$75, () => cur().details);
910
- _$effect((_$p) => _$setProp(_el$75, "fg", theme().textMuted, _$p));
911
- return _el$75;
1731
+ var _el$86 = _$createElement("markdown");
1732
+ _$effect((_p$) => {
1733
+ var _v$55 = syntax(), _v$56 = decodeQuizText(cur().details), _v$57 = theme().textMuted, _v$58 = theme().backgroundPanel;
1734
+ _v$55 !== _p$.e && (_p$.e = _$setProp(_el$86, "syntaxStyle", _v$55, _p$.e));
1735
+ _v$56 !== _p$.t && (_p$.t = _$setProp(_el$86, "content", _v$56, _p$.t));
1736
+ _v$57 !== _p$.a && (_p$.a = _$setProp(_el$86, "fg", _v$57, _p$.a));
1737
+ _v$58 !== _p$.o && (_p$.o = _$setProp(_el$86, "bg", _v$58, _p$.o));
1738
+ return _p$;
1739
+ }, {
1740
+ e: undefined,
1741
+ t: undefined,
1742
+ a: undefined,
1743
+ o: undefined
1744
+ });
1745
+ return _el$86;
912
1746
  }
913
1747
  }), null);
914
- _$insert(_el$66, _$createComponent(Show, {
1748
+ _$insert(_el$84, _$createComponent(Show, {
915
1749
  get when() {
916
1750
  return phase() === "select";
917
1751
  },
918
1752
  get children() {
919
- var _el$76 = _$createElement("box"), _el$77 = _$createElement("box"), _el$78 = _$createElement("text"), _el$79 = _$createElement("box"), _el$80 = _$createElement("box"), _el$81 = _$createElement("text"), _el$82 = _$createElement("box"), _el$83 = _$createElement("text"), _el$84 = _$createElement("box"), _el$85 = _$createElement("text"), _el$87 = _$createElement("box"), _el$88 = _$createElement("text"), _el$90 = _$createElement("box"), _el$92 = _$createElement("box"), _el$93 = _$createElement("text"), _el$95 = _$createElement("text"), _el$96 = _$createTextNode(`/`);
920
- _$insertNode(_el$76, _el$77);
921
- _$insertNode(_el$76, _el$79);
922
- _$insertNode(_el$76, _el$87);
923
- _$insertNode(_el$76, _el$92);
924
- _$setProp(_el$76, "flexDirection", "column");
925
- _$setProp(_el$76, "gap", 0);
926
- _$setProp(_el$76, "padding", 1);
927
- _$setProp(_el$76, "border", true);
928
- _$insert(_el$76, _$createComponent(For, {
1753
+ var _el$87 = _$createElement("box"), _el$88 = _$createElement("box"), _el$89 = _$createElement("text"), _el$90 = _$createElement("box"), _el$91 = _$createElement("box"), _el$92 = _$createElement("text"), _el$93 = _$createElement("box"), _el$94 = _$createElement("text"), _el$95 = _$createElement("box"), _el$96 = _$createElement("text"), _el$98 = _$createElement("box"), _el$99 = _$createElement("text"), _el$101 = _$createElement("box"), _el$103 = _$createElement("box"), _el$104 = _$createElement("text"), _el$105 = _$createElement("text"), _el$106 = _$createTextNode(`/`);
1754
+ _$insertNode(_el$87, _el$88);
1755
+ _$insertNode(_el$87, _el$90);
1756
+ _$insertNode(_el$87, _el$98);
1757
+ _$insertNode(_el$87, _el$103);
1758
+ _$setProp(_el$87, "flexDirection", "column");
1759
+ _$setProp(_el$87, "gap", 0);
1760
+ _$setProp(_el$87, "padding", 1);
1761
+ _$setProp(_el$87, "border", true);
1762
+ _$insert(_el$87, _$createComponent(For, {
929
1763
  get each() {
930
1764
  return cur().options;
931
1765
  },
@@ -934,36 +1768,36 @@ function QuizBatchDialog(props) {
934
1768
  const foc = () => focused() === "options" && optionIndex() === id;
935
1769
  const sel = () => selected().has(`opt:${id}`);
936
1770
  return (() => {
937
- var _el$113 = _$createElement("box"), _el$114 = _$createElement("box"), _el$115 = _$createElement("text"), _el$116 = _$createElement("box"), _el$117 = _$createElement("text"), _el$118 = _$createElement("box"), _el$119 = _$createElement("text"), _el$120 = _$createTextNode(`. `);
938
- _$insertNode(_el$113, _el$114);
939
- _$insertNode(_el$113, _el$116);
940
- _$insertNode(_el$113, _el$118);
941
- _$setProp(_el$113, "flexDirection", "row");
942
- _$setProp(_el$113, "alignItems", "flexStart");
943
- _$setProp(_el$113, "gap", 1);
944
- _$setProp(_el$113, "paddingLeft", 1);
945
- _$insertNode(_el$114, _el$115);
946
- _$setProp(_el$114, "width", 2);
947
- _$insert(_el$115, () => foc() ? "\u25B8" : " ");
948
- _$insertNode(_el$116, _el$117);
949
- _$setProp(_el$116, "width", 2);
950
- _$insert(_el$117, (() => {
951
- var _c$4 = _$memo(() => !!isMulti());
952
- return () => _c$4() ? sel() ? "\u2611" : "\u2610" : sel() ? "\u2B22" : "\u25CB";
1771
+ var _el$128 = _$createElement("box"), _el$129 = _$createElement("box"), _el$130 = _$createElement("text"), _el$131 = _$createElement("box"), _el$132 = _$createElement("text"), _el$133 = _$createElement("box"), _el$134 = _$createElement("text"), _el$135 = _$createTextNode(`. `);
1772
+ _$insertNode(_el$128, _el$129);
1773
+ _$insertNode(_el$128, _el$131);
1774
+ _$insertNode(_el$128, _el$133);
1775
+ _$setProp(_el$128, "flexDirection", "row");
1776
+ _$setProp(_el$128, "alignItems", "flexStart");
1777
+ _$setProp(_el$128, "gap", 1);
1778
+ _$setProp(_el$128, "paddingLeft", 1);
1779
+ _$insertNode(_el$129, _el$130);
1780
+ _$setProp(_el$129, "width", 2);
1781
+ _$insert(_el$130, () => foc() ? "\u25B8" : " ");
1782
+ _$insertNode(_el$131, _el$132);
1783
+ _$setProp(_el$131, "width", 2);
1784
+ _$insert(_el$132, (() => {
1785
+ var _c$8 = _$memo(() => !!isMulti());
1786
+ return () => _c$8() ? sel() ? "\u2611" : "\u2610" : sel() ? "\u2B22" : "\u25CB";
953
1787
  })());
954
- _$insertNode(_el$118, _el$119);
955
- _$setProp(_el$118, "flexGrow", 1);
956
- _$insertNode(_el$119, _el$120);
957
- _$setProp(_el$119, "wrapMode", "wrap");
958
- _$insert(_el$119, id + 1, _el$120);
959
- _$insert(_el$119, () => opt.label, null);
1788
+ _$insertNode(_el$133, _el$134);
1789
+ _$setProp(_el$133, "flexGrow", 1);
1790
+ _$insertNode(_el$134, _el$135);
1791
+ _$setProp(_el$134, "wrapMode", "wrap");
1792
+ _$insert(_el$134, id + 1, _el$135);
1793
+ _$insert(_el$134, () => opt.label, null);
960
1794
  _$effect((_p$) => {
961
- var _v$64 = foc() ? theme().backgroundElement : undefined, _v$65 = foc() ? theme().accent : theme().textMuted, _v$66 = isMulti() ? sel() ? theme().success : theme().textMuted : sel() ? theme().accent : theme().textMuted, _v$67 = sel() ? theme().text : theme().textMuted, _v$68 = foc();
962
- _v$64 !== _p$.e && (_p$.e = _$setProp(_el$113, "backgroundColor", _v$64, _p$.e));
963
- _v$65 !== _p$.t && (_p$.t = _$setProp(_el$115, "fg", _v$65, _p$.t));
964
- _v$66 !== _p$.a && (_p$.a = _$setProp(_el$117, "fg", _v$66, _p$.a));
965
- _v$67 !== _p$.o && (_p$.o = _$setProp(_el$119, "fg", _v$67, _p$.o));
966
- _v$68 !== _p$.i && (_p$.i = _$setProp(_el$119, "bold", _v$68, _p$.i));
1795
+ var _v$102 = foc() ? theme().backgroundElement : undefined, _v$103 = foc() ? theme().accent : theme().textMuted, _v$104 = isMulti() ? sel() ? theme().success : theme().textMuted : sel() ? theme().accent : theme().textMuted, _v$105 = sel() ? theme().text : theme().textMuted, _v$106 = foc();
1796
+ _v$102 !== _p$.e && (_p$.e = _$setProp(_el$128, "backgroundColor", _v$102, _p$.e));
1797
+ _v$103 !== _p$.t && (_p$.t = _$setProp(_el$130, "fg", _v$103, _p$.t));
1798
+ _v$104 !== _p$.a && (_p$.a = _$setProp(_el$132, "fg", _v$104, _p$.a));
1799
+ _v$105 !== _p$.o && (_p$.o = _$setProp(_el$134, "fg", _v$105, _p$.o));
1800
+ _v$106 !== _p$.i && (_p$.i = _$setProp(_el$134, "bold", _v$106, _p$.i));
967
1801
  return _p$;
968
1802
  }, {
969
1803
  e: undefined,
@@ -972,115 +1806,123 @@ function QuizBatchDialog(props) {
972
1806
  o: undefined,
973
1807
  i: undefined
974
1808
  });
975
- return _el$113;
1809
+ return _el$128;
976
1810
  })();
977
1811
  }
978
- }), _el$77);
979
- _$insertNode(_el$77, _el$78);
980
- _$setProp(_el$77, "height", 1);
981
- _$insert(_el$78, () => "\u2500".repeat(Math.max(20, popupWidth() - 8)));
982
- _$insertNode(_el$79, _el$80);
983
- _$insertNode(_el$79, _el$82);
984
- _$insertNode(_el$79, _el$84);
985
- _$setProp(_el$79, "flexDirection", "row");
986
- _$setProp(_el$79, "gap", 1);
987
- _$setProp(_el$79, "paddingLeft", 1);
988
- _$insertNode(_el$80, _el$81);
989
- _$setProp(_el$80, "width", 2);
990
- _$insert(_el$81, () => focused() === "options" && optionIndex() === dontKnowIdx() ? "\u25B8" : " ");
991
- _$insertNode(_el$82, _el$83);
992
- _$setProp(_el$82, "width", 2);
993
- _$insert(_el$83, () => dontKnow() ? "\u2611" : "\u2610");
994
- _$insertNode(_el$84, _el$85);
995
- _$setProp(_el$84, "flexGrow", 1);
996
- _$insertNode(_el$85, _$createTextNode(`I don't know`));
997
- _$setProp(_el$85, "italic", true);
998
- _$insertNode(_el$87, _el$88);
999
- _$insertNode(_el$87, _el$90);
1000
- _$setProp(_el$87, "flexDirection", "column");
1001
- _$setProp(_el$87, "paddingTop", 1);
1002
- _$insertNode(_el$88, _$createTextNode(`\u270E Note`));
1003
- _$setProp(_el$90, "border", true);
1812
+ }), _el$88);
1813
+ _$insertNode(_el$88, _el$89);
1814
+ _$setProp(_el$88, "height", 1);
1815
+ _$insert(_el$89, () => "\u2500".repeat(Math.max(20, popupWidth() - 8)));
1816
+ _$insertNode(_el$90, _el$91);
1817
+ _$insertNode(_el$90, _el$93);
1818
+ _$insertNode(_el$90, _el$95);
1819
+ _$setProp(_el$90, "flexDirection", "row");
1820
+ _$setProp(_el$90, "gap", 1);
1004
1821
  _$setProp(_el$90, "paddingLeft", 1);
1005
- _$setProp(_el$90, "paddingRight", 1);
1006
- _$insert(_el$90, _$createComponent(Show, {
1822
+ _$insertNode(_el$91, _el$92);
1823
+ _$setProp(_el$91, "width", 2);
1824
+ _$insert(_el$92, () => focused() === "options" && optionIndex() === dontKnowIdx() ? "\u25B8" : " ");
1825
+ _$insertNode(_el$93, _el$94);
1826
+ _$setProp(_el$93, "width", 2);
1827
+ _$insert(_el$94, () => dontKnow() ? "\u2611" : "\u2610");
1828
+ _$insertNode(_el$95, _el$96);
1829
+ _$setProp(_el$95, "flexGrow", 1);
1830
+ _$insertNode(_el$96, _$createTextNode(`I don't know`));
1831
+ _$setProp(_el$96, "italic", true);
1832
+ _$insertNode(_el$98, _el$99);
1833
+ _$insertNode(_el$98, _el$101);
1834
+ _$setProp(_el$98, "flexDirection", "column");
1835
+ _$setProp(_el$98, "paddingTop", 1);
1836
+ _$insertNode(_el$99, _$createTextNode(`\u270E Note`));
1837
+ _$setProp(_el$101, "border", true);
1838
+ _$setProp(_el$101, "paddingLeft", 1);
1839
+ _$setProp(_el$101, "paddingRight", 1);
1840
+ _$insert(_el$101, _$createComponent(Show, {
1007
1841
  get when() {
1008
1842
  return focused() === "note";
1009
1843
  },
1010
1844
  get fallback() {
1011
1845
  return (() => {
1012
- var _el$121 = _$createElement("text");
1013
- _$insert(_el$121, () => note() || "Tab to edit");
1014
- _$effect((_$p) => _$setProp(_el$121, "fg", theme().textMuted, _$p));
1015
- return _el$121;
1846
+ var _el$136 = _$createElement("text");
1847
+ _$insert(_el$136, () => note() || "Tab to edit \xB7 share what you were thinking");
1848
+ _$effect((_$p) => _$setProp(_el$136, "fg", theme().textMuted, _$p));
1849
+ return _el$136;
1016
1850
  })();
1017
1851
  },
1018
1852
  get children() {
1019
- var _el$91 = _$createElement("input");
1020
- _$use((el) => noteEl = el, _el$91);
1021
- _$setProp(_el$91, "onInput", (v) => setNote(typeof v === "string" ? v : v?.target?.value ?? ""));
1022
- _$setProp(_el$91, "onSubmit", () => setFocused("options"));
1023
- _$setProp(_el$91, "placeholder", "note");
1024
- _$effect((_$p) => _$setProp(_el$91, "value", note(), _$p));
1025
- return _el$91;
1853
+ var _el$102 = _$createElement("input");
1854
+ _$use((el) => noteEl = el, _el$102);
1855
+ _$setProp(_el$102, "onInput", (v) => setNote(typeof v === "string" ? v : v?.target?.value ?? ""));
1856
+ _$setProp(_el$102, "onSubmit", () => {
1857
+ if (!selected().size && !dontKnow() && note().trim())
1858
+ submitSelect();
1859
+ else
1860
+ setFocused("options");
1861
+ });
1862
+ _$setProp(_el$102, "placeholder", "note (Enter to submit note \u2192 classify)");
1863
+ _$effect((_$p) => _$setProp(_el$102, "value", note(), _$p));
1864
+ return _el$102;
1026
1865
  }
1027
1866
  }));
1028
- _$insertNode(_el$92, _el$93);
1029
- _$insertNode(_el$92, _el$95);
1030
- _$setProp(_el$92, "flexDirection", "row");
1031
- _$setProp(_el$92, "justifyContent", "space-between");
1032
- _$setProp(_el$92, "paddingTop", 1);
1033
- _$insertNode(_el$93, _$createTextNode(`Space toggle \xB7 \u2193 to Submit \u2192 Enter \xB7 Tab note \xB7 Ctrl+Enter submit`));
1034
- _$insertNode(_el$95, _el$96);
1035
- _$insert(_el$95, () => idx() + 1, _el$96);
1036
- _$insert(_el$95, () => props.request.quizzes.length, null);
1037
- _$insert(_el$76, _$createComponent(Show, {
1867
+ _$insertNode(_el$103, _el$104);
1868
+ _$insertNode(_el$103, _el$105);
1869
+ _$setProp(_el$103, "flexDirection", "row");
1870
+ _$setProp(_el$103, "justifyContent", "space-between");
1871
+ _$setProp(_el$103, "paddingTop", 1);
1872
+ _$insert(_el$104, (() => {
1873
+ var _c$6 = _$memo(() => !!isMulti());
1874
+ return () => _c$6() ? `${selected().size} selected` : note().trim() && !selected().size ? "note \u2192 classify" : "";
1875
+ })());
1876
+ _$insertNode(_el$105, _el$106);
1877
+ _$insert(_el$105, () => idx() + 1, _el$106);
1878
+ _$insert(_el$105, () => props.request.quizzes.length, null);
1879
+ _$insert(_el$87, _$createComponent(Show, {
1038
1880
  get when() {
1039
1881
  return isMulti();
1040
1882
  },
1041
1883
  get children() {
1042
- var _el$97 = _$createElement("box"), _el$98 = _$createElement("box"), _el$99 = _$createElement("text"), _el$100 = _$createElement("text");
1043
- _$insertNode(_el$97, _el$98);
1044
- _$setProp(_el$97, "justifyContent", "center");
1045
- _$setProp(_el$97, "paddingTop", 1);
1046
- _$insertNode(_el$98, _el$99);
1047
- _$insertNode(_el$98, _el$100);
1048
- _$setProp(_el$98, "flexDirection", "row");
1049
- _$setProp(_el$98, "gap", 1);
1050
- _$setProp(_el$98, "border", true);
1051
- _$setProp(_el$98, "paddingLeft", 2);
1052
- _$setProp(_el$98, "paddingRight", 2);
1053
- _$insert(_el$99, () => focused() === "options" && optionIndex() === submitIdx() ? "\u25B8" : " ");
1054
- _$insertNode(_el$100, _$createTextNode(`\u21B3 Submit`));
1055
- _$setProp(_el$100, "bold", true);
1884
+ var _el$107 = _$createElement("box"), _el$108 = _$createElement("box"), _el$109 = _$createElement("text"), _el$110 = _$createElement("text");
1885
+ _$insertNode(_el$107, _el$108);
1886
+ _$setProp(_el$107, "justifyContent", "center");
1887
+ _$setProp(_el$107, "paddingTop", 1);
1888
+ _$insertNode(_el$108, _el$109);
1889
+ _$insertNode(_el$108, _el$110);
1890
+ _$setProp(_el$108, "flexDirection", "row");
1891
+ _$setProp(_el$108, "gap", 1);
1892
+ _$setProp(_el$108, "border", true);
1893
+ _$setProp(_el$108, "paddingLeft", 2);
1894
+ _$setProp(_el$108, "paddingRight", 2);
1895
+ _$insert(_el$109, () => focused() === "options" && optionIndex() === submitIdx() ? "\u25B8" : " ");
1896
+ _$insertNode(_el$110, _$createTextNode(`\u21B3 Submit`));
1897
+ _$setProp(_el$110, "bold", true);
1056
1898
  _$effect((_p$) => {
1057
- var _v$34 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : theme().borderSubtle, _v$35 = focused() === "options" && optionIndex() === submitIdx() ? theme().backgroundElement : theme().background, _v$36 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : theme().textMuted;
1058
- _v$34 !== _p$.e && (_p$.e = _$setProp(_el$98, "borderColor", _v$34, _p$.e));
1059
- _v$35 !== _p$.t && (_p$.t = _$setProp(_el$98, "backgroundColor", _v$35, _p$.t));
1060
- _v$36 !== _p$.a && (_p$.a = _$setProp(_el$99, "fg", _v$36, _p$.a));
1899
+ var _v$59 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : theme().borderSubtle, _v$60 = focused() === "options" && optionIndex() === submitIdx() ? theme().backgroundElement : theme().background, _v$61 = focused() === "options" && optionIndex() === submitIdx() ? theme().accent : theme().textMuted;
1900
+ _v$59 !== _p$.e && (_p$.e = _$setProp(_el$108, "borderColor", _v$59, _p$.e));
1901
+ _v$60 !== _p$.t && (_p$.t = _$setProp(_el$108, "backgroundColor", _v$60, _p$.t));
1902
+ _v$61 !== _p$.a && (_p$.a = _$setProp(_el$109, "fg", _v$61, _p$.a));
1061
1903
  return _p$;
1062
1904
  }, {
1063
1905
  e: undefined,
1064
1906
  t: undefined,
1065
1907
  a: undefined
1066
1908
  });
1067
- return _el$97;
1909
+ return _el$107;
1068
1910
  }
1069
1911
  }), null);
1070
1912
  _$effect((_p$) => {
1071
- var _v$37 = theme().borderSubtle, _v$38 = theme().background, _v$39 = theme().borderSubtle, _v$40 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().backgroundElement : undefined, _v$41 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().accent : theme().textMuted, _v$42 = dontKnow() ? theme().warning : theme().textMuted, _v$43 = dontKnow() ? theme().warning : theme().textMuted, _v$44 = focused() === "note" ? theme().accent : theme().textMuted, _v$45 = focused() === "note" ? theme().accent : theme().borderSubtle, _v$46 = theme().backgroundElement, _v$47 = theme().textMuted, _v$48 = theme().textMuted;
1072
- _v$37 !== _p$.e && (_p$.e = _$setProp(_el$76, "borderColor", _v$37, _p$.e));
1073
- _v$38 !== _p$.t && (_p$.t = _$setProp(_el$76, "backgroundColor", _v$38, _p$.t));
1074
- _v$39 !== _p$.a && (_p$.a = _$setProp(_el$78, "fg", _v$39, _p$.a));
1075
- _v$40 !== _p$.o && (_p$.o = _$setProp(_el$79, "backgroundColor", _v$40, _p$.o));
1076
- _v$41 !== _p$.i && (_p$.i = _$setProp(_el$81, "fg", _v$41, _p$.i));
1077
- _v$42 !== _p$.n && (_p$.n = _$setProp(_el$83, "fg", _v$42, _p$.n));
1078
- _v$43 !== _p$.s && (_p$.s = _$setProp(_el$85, "fg", _v$43, _p$.s));
1079
- _v$44 !== _p$.h && (_p$.h = _$setProp(_el$88, "fg", _v$44, _p$.h));
1080
- _v$45 !== _p$.r && (_p$.r = _$setProp(_el$90, "borderColor", _v$45, _p$.r));
1081
- _v$46 !== _p$.d && (_p$.d = _$setProp(_el$90, "backgroundColor", _v$46, _p$.d));
1082
- _v$47 !== _p$.l && (_p$.l = _$setProp(_el$93, "fg", _v$47, _p$.l));
1083
- _v$48 !== _p$.u && (_p$.u = _$setProp(_el$95, "fg", _v$48, _p$.u));
1913
+ var _v$62 = theme().borderSubtle, _v$63 = theme().background, _v$64 = theme().borderSubtle, _v$65 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().backgroundElement : undefined, _v$66 = focused() === "options" && optionIndex() === dontKnowIdx() ? theme().accent : theme().textMuted, _v$67 = dontKnow() ? theme().warning : theme().textMuted, _v$68 = dontKnow() ? theme().warning : theme().textMuted, _v$69 = focused() === "note" ? theme().accent : theme().textMuted, _v$70 = focused() === "note" ? theme().accent : theme().borderSubtle, _v$71 = theme().backgroundElement, _v$72 = theme().textMuted, _v$73 = theme().textMuted;
1914
+ _v$62 !== _p$.e && (_p$.e = _$setProp(_el$87, "borderColor", _v$62, _p$.e));
1915
+ _v$63 !== _p$.t && (_p$.t = _$setProp(_el$87, "backgroundColor", _v$63, _p$.t));
1916
+ _v$64 !== _p$.a && (_p$.a = _$setProp(_el$89, "fg", _v$64, _p$.a));
1917
+ _v$65 !== _p$.o && (_p$.o = _$setProp(_el$90, "backgroundColor", _v$65, _p$.o));
1918
+ _v$66 !== _p$.i && (_p$.i = _$setProp(_el$92, "fg", _v$66, _p$.i));
1919
+ _v$67 !== _p$.n && (_p$.n = _$setProp(_el$94, "fg", _v$67, _p$.n));
1920
+ _v$68 !== _p$.s && (_p$.s = _$setProp(_el$96, "fg", _v$68, _p$.s));
1921
+ _v$69 !== _p$.h && (_p$.h = _$setProp(_el$99, "fg", _v$69, _p$.h));
1922
+ _v$70 !== _p$.r && (_p$.r = _$setProp(_el$101, "borderColor", _v$70, _p$.r));
1923
+ _v$71 !== _p$.d && (_p$.d = _$setProp(_el$101, "backgroundColor", _v$71, _p$.d));
1924
+ _v$72 !== _p$.l && (_p$.l = _$setProp(_el$104, "fg", _v$72, _p$.l));
1925
+ _v$73 !== _p$.u && (_p$.u = _$setProp(_el$105, "fg", _v$73, _p$.u));
1084
1926
  return _p$;
1085
1927
  }, {
1086
1928
  e: undefined,
@@ -1096,24 +1938,62 @@ function QuizBatchDialog(props) {
1096
1938
  l: undefined,
1097
1939
  u: undefined
1098
1940
  });
1099
- return _el$76;
1941
+ return _el$87;
1100
1942
  }
1101
1943
  }), null);
1102
- _$insert(_el$66, _$createComponent(Show, {
1944
+ _$insert(_el$84, _$createComponent(Show, {
1945
+ get when() {
1946
+ return phase() === "classifying";
1947
+ },
1948
+ get children() {
1949
+ var _el$112 = _$createElement("box"), _el$113 = _$createElement("text"), _el$115 = _$createElement("text"), _el$116 = _$createTextNode(`"`), _el$117 = _$createTextNode(`"`), _el$118 = _$createElement("text");
1950
+ _$insertNode(_el$112, _el$113);
1951
+ _$insertNode(_el$112, _el$115);
1952
+ _$insertNode(_el$112, _el$118);
1953
+ _$setProp(_el$112, "flexDirection", "column");
1954
+ _$setProp(_el$112, "gap", 1);
1955
+ _$setProp(_el$112, "padding", 1);
1956
+ _$setProp(_el$112, "border", true);
1957
+ _$setProp(_el$112, "alignItems", "center");
1958
+ _$insertNode(_el$113, _$createTextNode(`\u25D0 Classifying your note...`));
1959
+ _$setProp(_el$113, "bold", true);
1960
+ _$insertNode(_el$115, _el$116);
1961
+ _$insertNode(_el$115, _el$117);
1962
+ _$setProp(_el$115, "wrapMode", "wrap");
1963
+ _$insert(_el$115, note, _el$117);
1964
+ _$insertNode(_el$118, _$createTextNode(`Mapping to options \u2014 please wait`));
1965
+ _$effect((_p$) => {
1966
+ var _v$74 = theme().accent, _v$75 = theme().background, _v$76 = theme().accent, _v$77 = theme().textMuted, _v$78 = theme().textMuted;
1967
+ _v$74 !== _p$.e && (_p$.e = _$setProp(_el$112, "borderColor", _v$74, _p$.e));
1968
+ _v$75 !== _p$.t && (_p$.t = _$setProp(_el$112, "backgroundColor", _v$75, _p$.t));
1969
+ _v$76 !== _p$.a && (_p$.a = _$setProp(_el$113, "fg", _v$76, _p$.a));
1970
+ _v$77 !== _p$.o && (_p$.o = _$setProp(_el$115, "fg", _v$77, _p$.o));
1971
+ _v$78 !== _p$.i && (_p$.i = _$setProp(_el$118, "fg", _v$78, _p$.i));
1972
+ return _p$;
1973
+ }, {
1974
+ e: undefined,
1975
+ t: undefined,
1976
+ a: undefined,
1977
+ o: undefined,
1978
+ i: undefined
1979
+ });
1980
+ return _el$112;
1981
+ }
1982
+ }), null);
1983
+ _$insert(_el$84, _$createComponent(Show, {
1103
1984
  get when() {
1104
1985
  return phase() === "feedback";
1105
1986
  },
1106
1987
  get children() {
1107
- var _el$102 = _$createElement("box"), _el$103 = _$createElement("text"), _el$104 = _$createElement("text"), _el$105 = _$createTextNode(`Correct: `), _el$106 = _$createElement("box"), _el$107 = _$createElement("text"), _el$108 = _$createElement("box"), _el$109 = _$createElement("text"), _el$110 = _$createTextNode(`Enter \u2192 next (`), _el$111 = _$createTextNode(`/`), _el$112 = _$createTextNode(`)`);
1108
- _$insertNode(_el$102, _el$103);
1109
- _$insertNode(_el$102, _el$104);
1110
- _$insertNode(_el$102, _el$106);
1111
- _$insertNode(_el$102, _el$108);
1112
- _$setProp(_el$102, "flexDirection", "column");
1113
- _$setProp(_el$102, "gap", 1);
1114
- _$setProp(_el$102, "padding", 1);
1115
- _$setProp(_el$102, "border", true);
1116
- _$insert(_el$102, _$createComponent(For, {
1988
+ var _el$120 = _$createElement("box"), _el$121 = _$createElement("text"), _el$122 = _$createElement("text"), _el$123 = _$createTextNode(`Correct: `), _el$124 = _$createElement("box"), _el$125 = _$createElement("markdown");
1989
+ _$insertNode(_el$120, _el$121);
1990
+ _$insertNode(_el$120, _el$122);
1991
+ _$insertNode(_el$120, _el$124);
1992
+ _$setProp(_el$120, "flexDirection", "column");
1993
+ _$setProp(_el$120, "gap", 1);
1994
+ _$setProp(_el$120, "padding", 1);
1995
+ _$setProp(_el$120, "border", true);
1996
+ _$insert(_el$120, _$createComponent(For, {
1117
1997
  get each() {
1118
1998
  return cur().options;
1119
1999
  },
@@ -1142,55 +2022,48 @@ function QuizBatchDialog(props) {
1142
2022
  bg = theme().warning;
1143
2023
  }
1144
2024
  return (() => {
1145
- var _el$122 = _$createElement("box"), _el$123 = _$createElement("box"), _el$124 = _$createElement("text"), _el$125 = _$createElement("box"), _el$126 = _$createElement("text"), _el$127 = _$createTextNode(`. `);
1146
- _$insertNode(_el$122, _el$123);
1147
- _$insertNode(_el$122, _el$125);
1148
- _$setProp(_el$122, "flexDirection", "row");
1149
- _$setProp(_el$122, "gap", 1);
1150
- _$setProp(_el$122, "paddingLeft", 1);
1151
- _$setProp(_el$122, "backgroundColor", bg);
1152
- _$insertNode(_el$123, _el$124);
1153
- _$setProp(_el$123, "width", 2);
1154
- _$setProp(_el$124, "fg", fg);
1155
- _$setProp(_el$124, "bold", true);
1156
- _$insert(_el$124, ic);
1157
- _$insertNode(_el$125, _el$126);
1158
- _$setProp(_el$125, "flexGrow", 1);
1159
- _$insertNode(_el$126, _el$127);
1160
- _$setProp(_el$126, "fg", fg);
1161
- _$setProp(_el$126, "wrapMode", "wrap");
1162
- _$insert(_el$126, id, _el$127);
1163
- _$insert(_el$126, () => opt.label, null);
1164
- return _el$122;
2025
+ var _el$137 = _$createElement("box"), _el$138 = _$createElement("box"), _el$139 = _$createElement("text"), _el$140 = _$createElement("box"), _el$141 = _$createElement("text"), _el$142 = _$createTextNode(`. `);
2026
+ _$insertNode(_el$137, _el$138);
2027
+ _$insertNode(_el$137, _el$140);
2028
+ _$setProp(_el$137, "flexDirection", "row");
2029
+ _$setProp(_el$137, "gap", 1);
2030
+ _$setProp(_el$137, "paddingLeft", 1);
2031
+ _$setProp(_el$137, "backgroundColor", bg);
2032
+ _$insertNode(_el$138, _el$139);
2033
+ _$setProp(_el$138, "width", 2);
2034
+ _$setProp(_el$139, "fg", fg);
2035
+ _$setProp(_el$139, "bold", true);
2036
+ _$insert(_el$139, ic);
2037
+ _$insertNode(_el$140, _el$141);
2038
+ _$setProp(_el$140, "flexGrow", 1);
2039
+ _$insertNode(_el$141, _el$142);
2040
+ _$setProp(_el$141, "fg", fg);
2041
+ _$setProp(_el$141, "wrapMode", "wrap");
2042
+ _$insert(_el$141, id, _el$142);
2043
+ _$insert(_el$141, () => opt.label, null);
2044
+ return _el$137;
1165
2045
  })();
1166
2046
  }
1167
- }), _el$103);
1168
- _$setProp(_el$103, "bold", true);
1169
- _$insert(_el$103, () => feedback()?.correct ? "\u2713 Correct" : "\u2717 Incorrect");
1170
- _$insertNode(_el$104, _el$105);
1171
- _$insert(_el$104, () => cur().correctIndices.map((i) => `${i}. ${cur().options[i - 1]?.label}`).join(", "), null);
1172
- _$insertNode(_el$106, _el$107);
1173
- _$setProp(_el$106, "border", true);
1174
- _$setProp(_el$106, "padding", 1);
1175
- _$setProp(_el$107, "wrapMode", "wrap");
1176
- _$insert(_el$107, () => cur().explanation);
1177
- _$insertNode(_el$108, _el$109);
1178
- _$setProp(_el$108, "justifyContent", "center");
1179
- _$insertNode(_el$109, _el$110);
1180
- _$insertNode(_el$109, _el$111);
1181
- _$insertNode(_el$109, _el$112);
1182
- _$insert(_el$109, () => idx() + 1, _el$111);
1183
- _$insert(_el$109, () => props.request.quizzes.length, _el$112);
2047
+ }), _el$121);
2048
+ _$setProp(_el$121, "bold", true);
2049
+ _$insert(_el$121, () => feedback()?.correct ? "\u2713 Correct" : "\u2717 Incorrect");
2050
+ _$insertNode(_el$122, _el$123);
2051
+ _$insert(_el$122, () => cur().correctIndices.map((i) => `${i}. ${cur().options[i - 1]?.label}`).join(", "), null);
2052
+ _$insertNode(_el$124, _el$125);
2053
+ _$setProp(_el$124, "border", true);
2054
+ _$setProp(_el$124, "padding", 1);
1184
2055
  _$effect((_p$) => {
1185
- var _v$49 = feedback()?.correct ? theme().success : theme().error, _v$50 = theme().background, _v$51 = feedback()?.correct ? theme().success : theme().error, _v$52 = theme().textMuted, _v$53 = theme().borderSubtle, _v$54 = theme().backgroundPanel, _v$55 = theme().text, _v$56 = theme().textMuted;
1186
- _v$49 !== _p$.e && (_p$.e = _$setProp(_el$102, "borderColor", _v$49, _p$.e));
1187
- _v$50 !== _p$.t && (_p$.t = _$setProp(_el$102, "backgroundColor", _v$50, _p$.t));
1188
- _v$51 !== _p$.a && (_p$.a = _$setProp(_el$103, "fg", _v$51, _p$.a));
1189
- _v$52 !== _p$.o && (_p$.o = _$setProp(_el$104, "fg", _v$52, _p$.o));
1190
- _v$53 !== _p$.i && (_p$.i = _$setProp(_el$106, "borderColor", _v$53, _p$.i));
1191
- _v$54 !== _p$.n && (_p$.n = _$setProp(_el$106, "backgroundColor", _v$54, _p$.n));
1192
- _v$55 !== _p$.s && (_p$.s = _$setProp(_el$107, "fg", _v$55, _p$.s));
1193
- _v$56 !== _p$.h && (_p$.h = _$setProp(_el$109, "fg", _v$56, _p$.h));
2056
+ var _v$79 = feedback()?.correct ? theme().success : theme().error, _v$80 = theme().background, _v$81 = feedback()?.correct ? theme().success : theme().error, _v$82 = theme().textMuted, _v$83 = theme().borderSubtle, _v$84 = theme().backgroundPanel, _v$85 = syntax(), _v$86 = decodeQuizText(cur().explanation), _v$87 = theme().text, _v$88 = theme().backgroundPanel;
2057
+ _v$79 !== _p$.e && (_p$.e = _$setProp(_el$120, "borderColor", _v$79, _p$.e));
2058
+ _v$80 !== _p$.t && (_p$.t = _$setProp(_el$120, "backgroundColor", _v$80, _p$.t));
2059
+ _v$81 !== _p$.a && (_p$.a = _$setProp(_el$121, "fg", _v$81, _p$.a));
2060
+ _v$82 !== _p$.o && (_p$.o = _$setProp(_el$122, "fg", _v$82, _p$.o));
2061
+ _v$83 !== _p$.i && (_p$.i = _$setProp(_el$124, "borderColor", _v$83, _p$.i));
2062
+ _v$84 !== _p$.n && (_p$.n = _$setProp(_el$124, "backgroundColor", _v$84, _p$.n));
2063
+ _v$85 !== _p$.s && (_p$.s = _$setProp(_el$125, "syntaxStyle", _v$85, _p$.s));
2064
+ _v$86 !== _p$.h && (_p$.h = _$setProp(_el$125, "content", _v$86, _p$.h));
2065
+ _v$87 !== _p$.r && (_p$.r = _$setProp(_el$125, "fg", _v$87, _p$.r));
2066
+ _v$88 !== _p$.d && (_p$.d = _$setProp(_el$125, "bg", _v$88, _p$.d));
1194
2067
  return _p$;
1195
2068
  }, {
1196
2069
  e: undefined,
@@ -1200,20 +2073,42 @@ function QuizBatchDialog(props) {
1200
2073
  i: undefined,
1201
2074
  n: undefined,
1202
2075
  s: undefined,
1203
- h: undefined
2076
+ h: undefined,
2077
+ r: undefined,
2078
+ d: undefined
1204
2079
  });
1205
- return _el$102;
2080
+ return _el$120;
1206
2081
  }
1207
2082
  }), null);
2083
+ _$insertNode(_el$126, _el$127);
2084
+ _$setProp(_el$126, "height", 1);
2085
+ _$setProp(_el$126, "justifyContent", "center");
2086
+ _$setProp(_el$127, "wrapMode", "wrap");
2087
+ _$insert(_el$127, (() => {
2088
+ var _c$7 = _$memo(() => phase() === "feedback");
2089
+ return () => _c$7() ? _$memo(() => !!(canScrollUpBatch() && canScrollDownBatch()))() ? `\u25B2 more above \xB7 \u25BC more below \u2014 d/u to scroll \xB7 Enter \u2192 next (${idx() + 1}/${props.request.quizzes.length})` : _$memo(() => !!canScrollDownBatch())() ? `\u25BC more below \u2014 d to scroll \xB7 Enter \u2192 next (${idx() + 1}/${props.request.quizzes.length})` : _$memo(() => !!canScrollUpBatch())() ? `\u25B2 more above \u2014 u to scroll \xB7 Enter \u2192 next (${idx() + 1}/${props.request.quizzes.length})` : `Enter \u2192 next (${idx() + 1}/${props.request.quizzes.length})` : _$memo(() => phase() === "classifying")() ? "Classifying your note..." : _$memo(() => focused() === "note")() ? "Enter submit note \u2192 classify \xB7 Tab/Esc back" : canScrollUpBatch() || canScrollDownBatch() ? "j/k or \u2191\u2193 move \xB7 Space toggle \xB7 Tab note \xB7 Enter submit \xB7 Esc cancel \xB7 d/u scroll" : "j/k or \u2191\u2193 move \xB7 Space toggle \xB7 Tab note \xB7 Enter submit \xB7 Esc cancel";
2090
+ })());
1208
2091
  _$effect((_p$) => {
1209
- var _v$57 = popupWidth(), _v$58 = phase() === "feedback" ? feedback()?.correct ? theme().success : theme().error : theme().accent, _v$59 = theme().backgroundPanel, _v$60 = theme().accent, _v$61 = theme().background, _v$62 = theme().background, _v$63 = theme().text;
1210
- _v$57 !== _p$.e && (_p$.e = _$setProp(_el$66, "width", _v$57, _p$.e));
1211
- _v$58 !== _p$.t && (_p$.t = _$setProp(_el$66, "borderColor", _v$58, _p$.t));
1212
- _v$59 !== _p$.a && (_p$.a = _$setProp(_el$66, "backgroundColor", _v$59, _p$.a));
1213
- _v$60 !== _p$.o && (_p$.o = _$setProp(_el$67, "backgroundColor", _v$60, _p$.o));
1214
- _v$61 !== _p$.i && (_p$.i = _$setProp(_el$68, "fg", _v$61, _p$.i));
1215
- _v$62 !== _p$.n && (_p$.n = _$setProp(_el$72, "fg", _v$62, _p$.n));
1216
- _v$63 !== _p$.s && (_p$.s = _$setProp(_el$74, "fg", _v$63, _p$.s));
2092
+ var _v$89 = popupWidth(), _v$90 = popupHeight(), _v$91 = phase() === "feedback" ? feedback()?.correct ? theme().success : theme().error : theme().accent, _v$92 = theme().backgroundPanel, _v$93 = theme().accent, _v$94 = theme().background, _v$95 = theme().background, _v$96 = {
2093
+ visible: true,
2094
+ trackOptions: {
2095
+ backgroundColor: theme().background,
2096
+ foregroundColor: theme().borderActive
2097
+ }
2098
+ }, _v$97 = syntax(), _v$98 = decodeQuizText(cur().question), _v$99 = theme().text, _v$100 = theme().backgroundPanel, _v$101 = theme().textMuted;
2099
+ _v$89 !== _p$.e && (_p$.e = _$setProp(_el$76, "width", _v$89, _p$.e));
2100
+ _v$90 !== _p$.t && (_p$.t = _$setProp(_el$76, "height", _v$90, _p$.t));
2101
+ _v$91 !== _p$.a && (_p$.a = _$setProp(_el$76, "borderColor", _v$91, _p$.a));
2102
+ _v$92 !== _p$.o && (_p$.o = _$setProp(_el$76, "backgroundColor", _v$92, _p$.o));
2103
+ _v$93 !== _p$.i && (_p$.i = _$setProp(_el$77, "backgroundColor", _v$93, _p$.i));
2104
+ _v$94 !== _p$.n && (_p$.n = _$setProp(_el$78, "fg", _v$94, _p$.n));
2105
+ _v$95 !== _p$.s && (_p$.s = _$setProp(_el$82, "fg", _v$95, _p$.s));
2106
+ _v$96 !== _p$.h && (_p$.h = _$setProp(_el$84, "verticalScrollbarOptions", _v$96, _p$.h));
2107
+ _v$97 !== _p$.r && (_p$.r = _$setProp(_el$85, "syntaxStyle", _v$97, _p$.r));
2108
+ _v$98 !== _p$.d && (_p$.d = _$setProp(_el$85, "content", _v$98, _p$.d));
2109
+ _v$99 !== _p$.l && (_p$.l = _$setProp(_el$85, "fg", _v$99, _p$.l));
2110
+ _v$100 !== _p$.u && (_p$.u = _$setProp(_el$85, "bg", _v$100, _p$.u));
2111
+ _v$101 !== _p$.c && (_p$.c = _$setProp(_el$127, "fg", _v$101, _p$.c));
1217
2112
  return _p$;
1218
2113
  }, {
1219
2114
  e: undefined,
@@ -1222,14 +2117,21 @@ function QuizBatchDialog(props) {
1222
2117
  o: undefined,
1223
2118
  i: undefined,
1224
2119
  n: undefined,
1225
- s: undefined
2120
+ s: undefined,
2121
+ h: undefined,
2122
+ r: undefined,
2123
+ d: undefined,
2124
+ l: undefined,
2125
+ u: undefined,
2126
+ c: undefined
1226
2127
  });
1227
- return _el$66;
2128
+ return _el$76;
1228
2129
  })();
1229
2130
  }
1230
2131
  var tui = async (api) => {
1231
2132
  const dir = api.state.path.directory || api.state.path.worktree || process.cwd();
1232
2133
  const pendingDir = path.join(dir, PENDING_DIR);
2134
+ globalThis.__learnPendingDir = pendingDir;
1233
2135
  ensureDir(pendingDir);
1234
2136
  const heartbeatPath = path.join(pendingDir, ".tui-alive");
1235
2137
  try {
@@ -1265,7 +2167,7 @@ var tui = async (api) => {
1265
2167
  return;
1266
2168
  let files = [];
1267
2169
  try {
1268
- files = fs.readdirSync(pendingDir).filter((f) => f.endsWith(".json") && !f.startsWith("response-") && !f.startsWith(".")).sort();
2170
+ files = fs.readdirSync(pendingDir).filter((f) => f.endsWith(".json") && !f.startsWith("response-") && !f.startsWith(".") && !f.startsWith("classify")).sort();
1269
2171
  } catch {
1270
2172
  return;
1271
2173
  }
@@ -1300,6 +2202,8 @@ var tui = async (api) => {
1300
2202
  } catch {}
1301
2203
  return;
1302
2204
  }
2205
+ if (!data.sessionID)
2206
+ data.sessionID = curSid;
1303
2207
  try {
1304
2208
  const cur = api.route?.current;
1305
2209
  const curSid2 = cur?.params?.sessionID || cur?.sessionID;