koneck 2.59.0 → 2.60.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ui-client.d.ts","sourceRoot":"","sources":["../../src/web/ui-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,MAAM,CA+nIrC"}
1
+ {"version":3,"file":"ui-client.d.ts","sourceRoot":"","sources":["../../src/web/ui-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAizIrC"}
@@ -2703,7 +2703,9 @@ function newPane() {
2703
2703
  /** Where this command's output begins, so a catch-up can replace exactly that. */
2704
2704
  outputStart: 0,
2705
2705
  /** How many output lines have arrived on the stream, for the same reason. */
2706
- received: 0 };
2706
+ received: 0,
2707
+ /** Lines waiting for the next frame, so output faster than the screen costs nothing. */
2708
+ queue: [], flushing: false };
2707
2709
  }
2708
2710
 
2709
2711
  /** The pane a job's output belongs to, or null when nothing here started it. */
@@ -2764,24 +2766,104 @@ function markActivePane() {
2764
2766
  });
2765
2767
  }
2766
2768
 
2767
- /** Everything this pane has printed, as one column of text. */
2769
+ /** Whether the reader is watching the tail, or has scrolled up to look at something. */
2770
+ function atTail(pane) {
2771
+ return pane.el.scroll.scrollHeight - pane.el.scroll.scrollTop
2772
+ - pane.el.scroll.clientHeight < 60;
2773
+ }
2774
+
2775
+ /**
2776
+ * Everything this pane has printed, rebuilt from scratch.
2777
+ *
2778
+ * For the cases where the whole buffer really did change — a fresh pane, a catch-up read, a clear.
2779
+ * A single new line does not come through here; see appendLine for why that matters.
2780
+ */
2768
2781
  function paintPane(index) {
2769
2782
  const pane = term.panes[index];
2770
2783
  if (!pane || !pane.el) return;
2771
- const atEnd = pane.el.scroll.scrollHeight - pane.el.scroll.scrollTop
2772
- - pane.el.scroll.clientHeight < 60;
2773
- pane.el.body.innerHTML = ansiToHtml(pane.lines.join('\n'));
2784
+ const wasAtTail = atTail(pane);
2785
+ pane.el.body.innerHTML = '';
2786
+ for (const line of pane.lines) pane.el.body.appendChild(lineNode(line));
2774
2787
  pane.el.stop.hidden = !pane.running;
2775
- if (atEnd) pane.el.scroll.scrollTop = pane.el.scroll.scrollHeight;
2788
+ if (wasAtTail) pane.el.scroll.scrollTop = pane.el.scroll.scrollHeight;
2776
2789
  }
2777
2790
 
2791
+ /** One line of output, as its own element so it can be added without touching the others. */
2792
+ function lineNode(line) {
2793
+ const node = document.createElement('span');
2794
+ node.className = 'tl';
2795
+ node.innerHTML = ansiToHtml(line);
2796
+ return node;
2797
+ }
2798
+
2799
+ /** Lines a pane keeps. A dev server left running overnight must not become the document. */
2800
+ const TERM_SCROLLBACK = 4000;
2801
+
2802
+ /*
2803
+ * Lines land in the document once a frame, however fast they arrive.
2804
+ *
2805
+ * Two wrong answers came before this one, and both were measured on the same two thousand lines.
2806
+ *
2807
+ * Rebuilding the whole scrollback per line — joining the buffer, reparsing it, assigning innerHTML
2808
+ * — took 929ms. Appending one element per line instead took 6831ms: seven times *worse*, because
2809
+ * deciding whether to auto-scroll reads scrollHeight, and reading layout after every write forces a
2810
+ * synchronous reflow. Two thousand forced reflows cost far more than two thousand innerHTML writes,
2811
+ * which the browser is free to batch because nothing in between asks it a question about layout.
2812
+ *
2813
+ * So the fix is not a cheaper write, it is fewer layout reads. Lines queue and go in together on the
2814
+ * next animation frame: one fragment appended, one measurement taken, one scroll set, at most sixty
2815
+ * times a second no matter how loud the command is. Output faster than the screen can show it stops
2816
+ * costing anything extra, which is what smooth means here.
2817
+ */
2778
2818
  function pushPane(index, line, redraw) {
2779
2819
  const pane = term.panes[index];
2780
2820
  if (!pane) return;
2781
2821
  if (redraw && pane.lines.length > 0) pane.lines[pane.lines.length - 1] = line;
2782
2822
  else pane.lines.push(line);
2783
- while (pane.lines.length > 4000) pane.lines.shift();
2784
- paintPane(index);
2823
+ while (pane.lines.length > TERM_SCROLLBACK) pane.lines.shift();
2824
+ if (!pane.el) return;
2825
+ pane.queue.push({ line: line, redraw: redraw === true });
2826
+ scheduleFlush(index);
2827
+ }
2828
+
2829
+ function scheduleFlush(index) {
2830
+ const pane = term.panes[index];
2831
+ if (!pane || pane.flushing) return;
2832
+ pane.flushing = true;
2833
+ requestAnimationFrame(() => flushPane(index));
2834
+ }
2835
+
2836
+ function flushPane(index) {
2837
+ const pane = term.panes[index];
2838
+ if (!pane) return;
2839
+ pane.flushing = false;
2840
+ if (!pane.el || pane.queue.length === 0) return;
2841
+
2842
+ // The one layout read of the frame, taken before anything is written.
2843
+ const wasAtTail = atTail(pane);
2844
+ const queued = pane.queue;
2845
+ pane.queue = [];
2846
+
2847
+ const batch = document.createDocumentFragment();
2848
+ for (const item of queued) {
2849
+ if (item.redraw) {
2850
+ // A progress bar rewriting its own line. If the batch already holds it, replace within the
2851
+ // batch; otherwise the last line already in the document is the one being redrawn.
2852
+ if (batch.lastChild) batch.replaceChild(lineNode(item.line), batch.lastChild);
2853
+ else if (pane.el.body.lastChild) {
2854
+ pane.el.body.replaceChild(lineNode(item.line), pane.el.body.lastChild);
2855
+ } else batch.appendChild(lineNode(item.line));
2856
+ continue;
2857
+ }
2858
+ batch.appendChild(lineNode(item.line));
2859
+ }
2860
+ pane.el.body.appendChild(batch);
2861
+
2862
+ while (pane.el.body.childNodes.length > TERM_SCROLLBACK) {
2863
+ pane.el.body.removeChild(pane.el.body.firstChild);
2864
+ }
2865
+ pane.el.stop.hidden = !pane.running;
2866
+ if (wasAtTail) pane.el.scroll.scrollTop = pane.el.scroll.scrollHeight;
2785
2867
  }
2786
2868
 
2787
2869
  async function paneKey(ev, index) {
@@ -2912,7 +2994,24 @@ function watchTerminal() {
2912
2994
  source.onerror = () => { /* the browser reconnects on its own */ };
2913
2995
  }
2914
2996
 
2915
- /** Font size and backdrop, applied to every pane at once. */
2997
+ /*
2998
+ * Font size and backdrop, applied to every pane at once.
2999
+ *
3000
+ * The picture is either the one KONECK ships with or one of yours, and yours is kept in this
3001
+ * browser's own storage rather than on the machine: it is a preference about how your terminal
3002
+ * looks, not something the server needs to know, and it should not travel anywhere or appear in
3003
+ * anybody else's session.
3004
+ */
3005
+ const OWN_BACKDROP_KEY = 'koneck.terminal.backdrop';
3006
+
3007
+ function backdropUrl() {
3008
+ let own = null;
3009
+ try { own = localStorage.getItem(OWN_BACKDROP_KEY); } catch (e) { own = null; }
3010
+ if (own) return own;
3011
+ return '/api/terminal/background'
3012
+ + (state.token ? '?token=' + encodeURIComponent(state.token) : '');
3013
+ }
3014
+
2916
3015
  function applyTerminalLook() {
2917
3016
  const host = $('termpanes');
2918
3017
  host.style.setProperty('--term-font', term.fontPx + 'px');
@@ -2920,11 +3019,66 @@ function applyTerminalLook() {
2920
3019
  const strength = Number($('tbgop').value) / 100;
2921
3020
  host.classList.toggle('backdrop', on);
2922
3021
  host.style.setProperty('--term-bg-strength', on ? String(strength) : '0');
2923
- if (on && !host.style.getPropertyValue('--term-bg-image')) {
2924
- const url = '/api/terminal/background'
2925
- + (state.token ? '?token=' + encodeURIComponent(state.token) : '');
2926
- host.style.setProperty('--term-bg-image', 'url("' + url + '")');
3022
+ host.style.setProperty('--term-bg-image', 'url("' + backdropUrl() + '")');
3023
+ let own = null;
3024
+ try { own = localStorage.getItem(OWN_BACKDROP_KEY); } catch (e) { own = null; }
3025
+ // The way back only exists when there is something to go back from.
3026
+ $('tbgreset').hidden = !own;
3027
+ }
3028
+
3029
+ $('tbgpick').onclick = () => { $('tbgfile').click(); };
3030
+
3031
+ $('tbgreset').onclick = () => {
3032
+ try { localStorage.removeItem(OWN_BACKDROP_KEY); } catch (e) { /* nothing stored */ }
3033
+ applyTerminalLook();
3034
+ };
3035
+
3036
+ $('tbgfile').onchange = async () => {
3037
+ const file = $('tbgfile').files && $('tbgfile').files[0];
3038
+ $('tbgfile').value = '';
3039
+ if (!file) return;
3040
+ let stored;
3041
+ try { stored = await shrinkForBackdrop(file); }
3042
+ catch (e) { $('tbgimg').title = 'That image could not be read.'; return; }
3043
+ try { localStorage.setItem(OWN_BACKDROP_KEY, stored); }
3044
+ catch (e) {
3045
+ // Storage is small and a photograph is not. Said rather than failed silently.
3046
+ $('tbgimg').title = 'That image is too large to keep in this browser.';
3047
+ return;
2927
3048
  }
3049
+ $('tbgimg').checked = true;
3050
+ applyTerminalLook();
3051
+ };
3052
+
3053
+ /*
3054
+ * A picture cut down to something a browser will keep.
3055
+ *
3056
+ * A phone photograph is several megabytes and local storage is a few in total, so storing one
3057
+ * whole would fail — and the panes are at most a screen wide, so the pixels beyond that were never
3058
+ * going to be seen. Drawn once at a sane width and re-encoded as a photograph, which is what it is.
3059
+ */
3060
+ function shrinkForBackdrop(file) {
3061
+ return new Promise((resolve, reject) => {
3062
+ const reader = new FileReader();
3063
+ reader.onerror = () => reject(new Error('unreadable'));
3064
+ reader.onload = () => {
3065
+ const img = new Image();
3066
+ img.onerror = () => reject(new Error('not an image'));
3067
+ img.onload = () => {
3068
+ const maxWide = 1920;
3069
+ const scale = Math.min(1, maxWide / (img.naturalWidth || maxWide));
3070
+ const canvas = document.createElement('canvas');
3071
+ canvas.width = Math.max(1, Math.round(img.naturalWidth * scale));
3072
+ canvas.height = Math.max(1, Math.round(img.naturalHeight * scale));
3073
+ const ctx = canvas.getContext('2d');
3074
+ if (!ctx) { reject(new Error('no canvas')); return; }
3075
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
3076
+ resolve(canvas.toDataURL('image/jpeg', 0.82));
3077
+ };
3078
+ img.src = String(reader.result);
3079
+ };
3080
+ reader.readAsDataURL(file);
3081
+ });
2928
3082
  }
2929
3083
 
2930
3084
  function startPaneDrag(ev, dividerIndex) {
@@ -3002,6 +3156,11 @@ const preview = { shot: null, width: 0 };
3002
3156
  */
3003
3157
  const typing = { pending: '', timer: null };
3004
3158
 
3159
+ /** Wheel movement waiting to be sent, so a gesture is one request rather than fifty. */
3160
+ const scrolling = { by: 0, timer: null };
3161
+ /** Long enough to gather a flick of the wheel, short enough that the page keeps up with it. */
3162
+ const SCROLL_BATCH_MS = 70;
3163
+
3005
3164
  /** Keys the page must be told about individually, with what they are called on the wire. */
3006
3165
  const SPECIAL_KEYS = {
3007
3166
  Enter: 'Enter', Tab: 'Tab', Backspace: 'Backspace', Escape: 'Escape',
@@ -3099,6 +3258,25 @@ function drawPreview(data) {
3099
3258
  img.tabIndex = 0;
3100
3259
  img.onkeydown = (ev) => { void pageKey(ev); };
3101
3260
  img.onblur = () => { void flushTyping(); };
3261
+ /*
3262
+ * The wheel scrolls the page, not the panel around it.
3263
+ *
3264
+ * There was no wheel handler at all: turning the wheel over a page scrolled the panel it sat in,
3265
+ * or nothing, and the only way down a page was the scroll buttons. Accumulated and sent as one
3266
+ * movement per burst, because a scroll gesture is fifty wheel events and fifty round trips is a
3267
+ * page that lurches instead of scrolling.
3268
+ */
3269
+ img.onwheel = (ev) => {
3270
+ ev.preventDefault();
3271
+ scrolling.by += ev.deltaY;
3272
+ if (scrolling.timer) return;
3273
+ scrolling.timer = setTimeout(() => {
3274
+ const by = Math.round(scrolling.by);
3275
+ scrolling.by = 0;
3276
+ scrolling.timer = null;
3277
+ if (by !== 0) void browserDo({ action: 'scroll', by: by });
3278
+ }, SCROLL_BATCH_MS);
3279
+ };
3102
3280
 
3103
3281
  // The picture is 1280 wide whatever it is displayed at, so a click has to be scaled back into
3104
3282
  // page coordinates or it lands somewhere else entirely.
@@ -1 +1 @@
1
- {"version":3,"file":"ui-client.js","sourceRoot":"","sources":["../../src/web/ui-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6nIlB,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"ui-client.js","sourceRoot":"","sources":["../../src/web/ui-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+yIlB,CAAC;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ui-css.d.ts","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AA8CA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAm9B3C"}
1
+ {"version":3,"file":"ui-css.d.ts","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AA8CA,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAq9B3C"}
@@ -837,6 +837,8 @@ body[data-tint="soft"]{filter:contrast(.92) brightness(1.04)}
837
837
  .termscroll{position:relative;flex:1;min-height:0;overflow:auto;padding:12px 14px 4px}
838
838
  .termbody{margin:0;font-family:var(--mono);font-size:var(--term-font);line-height:1.55;
839
839
  white-space:pre-wrap;word-break:break-word;color:var(--ink)}
840
+ /* A line is its own element so a new one can be added without rebuilding the rest. */
841
+ .termbody .tl{display:block}
840
842
  .termrow{position:relative;display:flex;gap:8px;align-items:center;padding:2px 14px 12px}
841
843
  .termps{font-family:var(--mono);font-size:var(--term-font);color:var(--cyan);flex:0 0 auto}
842
844
  /*
@@ -1 +1 @@
1
- {"version":3,"file":"ui-css.js","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;;;GAYG;AACH,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;CAkBZ,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO;;;;;;;;;;;;;;;;;gBAiBO,OAAO;;;oCAGa,IAAI;;2BAEb,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA27B9B,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"ui-css.js","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;;;GAYG;AACH,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;;CAkBZ,CAAC;AAEF,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO;;;;;;;;;;;;;;;;;gBAiBO,OAAO;;;oCAGa,IAAI;;2BAEb,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA67B9B,CAAC;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,wBAAgB,IAAI,IAAI,MAAM,CAiX7B"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,wBAAgB,IAAI,IAAI,MAAM,CA2X7B"}
package/dist/web/ui.js CHANGED
@@ -150,6 +150,16 @@ export function page() {
150
150
  </label>
151
151
  <input type="range" id="tbgop" min="4" max="40" value="14" title="How strongly it shows"
152
152
  aria-label="Backdrop strength">
153
+ <!--
154
+ Your own picture, or the one KONECK ships with. Kept in this browser rather than on the
155
+ server: it is a preference about how your terminal looks, not something the machine needs
156
+ to know, and nothing about it should travel anywhere.
157
+ -->
158
+ <button type="button" class="termbtn" id="tbgpick"
159
+ title="Use a picture of your own">choose&hellip;</button>
160
+ <button type="button" class="termbtn" id="tbgreset" hidden
161
+ title="Back to the picture KONECK ships with">default</button>
162
+ <input type="file" id="tbgfile" accept="image/*" hidden>
153
163
  <span class="termgap"></span>
154
164
  <button type="button" class="termbtn" id="tfontdown" title="Smaller text">A&minus;</button>
155
165
  <button type="button" class="termbtn" id="tfontup" title="Larger text">A+</button>
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,UAAU,IAAI;IAClB,OAAO;;;;;;;SAOA,GAAG,CAAC,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAqWF,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;EAC7C,YAAY,EAAE;;eAED,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,MAAM,UAAU,IAAI;IAClB,OAAO;;;;;;;SAOA,GAAG,CAAC,SAAS,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA+WF,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;EAC7C,YAAY,EAAE;;eAED,CAAC;AAChB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koneck",
3
- "version": "2.59.0",
3
+ "version": "2.60.0",
4
4
  "description": "Kinetically Orchestrated Neural Execution Engine for Code",
5
5
  "type": "module",
6
6
  "bin": {