koneck 2.53.0 → 2.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/chat.d.ts.map +1 -1
  2. package/dist/chat.js +21 -2
  3. package/dist/chat.js.map +1 -1
  4. package/dist/config-store.d.ts +6 -0
  5. package/dist/config-store.d.ts.map +1 -1
  6. package/dist/config-store.js +2 -1
  7. package/dist/config-store.js.map +1 -1
  8. package/dist/engine.d.ts.map +1 -1
  9. package/dist/engine.js +105 -2
  10. package/dist/engine.js.map +1 -1
  11. package/dist/failover.d.ts +95 -0
  12. package/dist/failover.d.ts.map +1 -0
  13. package/dist/failover.js +191 -0
  14. package/dist/failover.js.map +1 -0
  15. package/dist/ink-chat.d.ts.map +1 -1
  16. package/dist/ink-chat.js +37 -2
  17. package/dist/ink-chat.js.map +1 -1
  18. package/dist/tui.d.ts +8 -0
  19. package/dist/tui.d.ts.map +1 -1
  20. package/dist/tui.js +12 -0
  21. package/dist/tui.js.map +1 -1
  22. package/dist/types.d.ts +19 -0
  23. package/dist/types.d.ts.map +1 -1
  24. package/dist/web/api.d.ts +1 -1
  25. package/dist/web/api.d.ts.map +1 -1
  26. package/dist/web/api.js +45 -1
  27. package/dist/web/api.js.map +1 -1
  28. package/dist/web/changes.d.ts.map +1 -1
  29. package/dist/web/changes.js +21 -2
  30. package/dist/web/changes.js.map +1 -1
  31. package/dist/web/sessions.d.ts +8 -0
  32. package/dist/web/sessions.d.ts.map +1 -1
  33. package/dist/web/sessions.js +36 -0
  34. package/dist/web/sessions.js.map +1 -1
  35. package/dist/web/ui-client.d.ts.map +1 -1
  36. package/dist/web/ui-client.js +117 -6
  37. package/dist/web/ui-client.js.map +1 -1
  38. package/dist/web/ui-css.d.ts.map +1 -1
  39. package/dist/web/ui-css.js +29 -0
  40. package/dist/web/ui-css.js.map +1 -1
  41. package/dist/web/ui.d.ts.map +1 -1
  42. package/dist/web/ui.js +42 -0
  43. package/dist/web/ui.js.map +1 -1
  44. package/package.json +1 -1
@@ -543,16 +543,70 @@ function setPills(provider, model) {
543
543
  }
544
544
 
545
545
  /* ── changes ───────────────────────────────────────────────── */
546
- function renderDiff(text) {
546
+ /*
547
+ * A diff a reader can act on: the marker, the line number, and the code coloured as code.
548
+ *
549
+ * It used to strip the marker with a slice — and show no numbers — so a change was a coloured
550
+ * band with no way to say which line it was or, on a monochrome screen, which direction it went.
551
+ * Every other tool shows the + and the -; they are how you read a diff aloud.
552
+ */
553
+ function renderDiff(text, path) {
547
554
  const box = el('div', 'diff');
555
+ let oldNo = 1;
556
+ let newNo = 1;
557
+ const codeLines = [];
558
+ const codeRows = [];
559
+
548
560
  for (const line of text.split('\n')) {
549
- if (line === '@@') { box.appendChild(el('div', 'h', '⋯')); continue; }
550
- const cls = line[0] === '+' ? 'a' : line[0] === '-' ? 'd' : 'c';
551
- box.appendChild(el('div', cls, line.slice(1) || ' '));
561
+ // A hunk header says where the next hunk starts, so numbering survives a gap.
562
+ const hunk = /^@@ -(\d+) \+(\d+) @@/.exec(line);
563
+ if (hunk || line === '@@') {
564
+ if (hunk) { oldNo = Number(hunk[1]); newNo = Number(hunk[2]); }
565
+ box.appendChild(el('div', 'h', '\u22ef'));
566
+ continue;
567
+ }
568
+ const mark = line[0];
569
+ const body = line.slice(1);
570
+ const cls = mark === '+' ? 'a' : mark === '-' ? 'd' : 'c';
571
+
572
+ const row = el('div', 'dl ' + cls);
573
+ // The removed side keeps its old number, the added side its new one: that is what makes a
574
+ // number in a diff mean anything.
575
+ row.appendChild(el('span', 'dn', mark === '+' ? String(newNo) : String(oldNo)));
576
+ row.appendChild(el('span', 'dm', mark === '+' ? '+' : mark === '-' ? '\u2212' : ' '));
577
+ const code = el('span', 'dc');
578
+ code.textContent = body === '' ? '\u200b' : body;
579
+ row.appendChild(code);
580
+ box.appendChild(row);
581
+
582
+ codeLines.push(body);
583
+ codeRows.push(code);
584
+ if (mark !== '+') oldNo++;
585
+ if (mark !== '-') newNo++;
552
586
  }
587
+
588
+ // Coloured afterwards, so the diff is on screen immediately and the colour arrives when it does.
589
+ if (path && codeLines.length) void colourDiff(path, codeLines, codeRows);
553
590
  return box;
554
591
  }
555
592
 
593
+ /** Asks for the same colours the file view uses, and repaints the diff's code in place. */
594
+ async function colourDiff(path, lines, rows) {
595
+ let tokens = null;
596
+ try {
597
+ const out = await api('/api/highlight', { method: 'POST',
598
+ body: JSON.stringify({ path: path, text: lines.join('\n') }) });
599
+ tokens = out.tokens;
600
+ } catch (e) { return; }
601
+ if (!tokens) return;
602
+ for (let i = 0; i < rows.length; i++) {
603
+ const forLine = tokens[i];
604
+ if (!forLine || !forLine.length) continue;
605
+ rows[i].textContent = '';
606
+ if (!paintTokens(rows[i], forLine, null)) rows[i].textContent = lines[i] || '\u200b';
607
+ }
608
+ }
609
+
556
610
  function fileCard(c, openByDefault) {
557
611
  const box = el('div', 'file');
558
612
  const fh = el('button', 'fh');
@@ -563,7 +617,7 @@ function fileCard(c, openByDefault) {
563
617
  box.appendChild(fh);
564
618
  const body = c.diff === null
565
619
  ? (() => { const d = el('div', 'diff'); d.appendChild(el('div', 'c', ' binary or too large to diff')); return d; })()
566
- : renderDiff(c.diff);
620
+ : renderDiff(c.diff, c.path);
567
621
  body.hidden = !openByDefault;
568
622
  fh.onclick = () => { body.hidden = !body.hidden; };
569
623
  box.appendChild(body);
@@ -3329,7 +3383,15 @@ async function showWatched(path, asDiff) {
3329
3383
  head.style.padding = '8px 13px';
3330
3384
  head.textContent = '+' + ch.added + ' \u2212' + ch.removed + ' ' + ch.kind;
3331
3385
  host.appendChild(head);
3332
- host.appendChild(renderDiff(ch.diff));
3386
+ host.appendChild(renderDiff(ch.diff, path));
3387
+ /*
3388
+ * Put the change on screen, not the top of the file.
3389
+ *
3390
+ * A diff opened at line one for a change three hundred lines down is a panel that has to
3391
+ * be searched. The first added or removed row is what the reader came for.
3392
+ */
3393
+ const firstChange = host.querySelector('.diff .a, .diff .d');
3394
+ if (firstChange) firstChange.scrollIntoView({ block: 'center' });
3333
3395
  return;
3334
3396
  }
3335
3397
  }
@@ -3443,6 +3505,55 @@ function showKeyRow(name) {
3443
3505
  $('keyin').value = '';
3444
3506
  }
3445
3507
 
3508
+ /*
3509
+ * The failover policy: read when the dialog opens, written when Save is pressed.
3510
+ *
3511
+ * Saved to the config file rather than held in the page, because a policy that has to be set again
3512
+ * every session is one that never gets used. Live sessions take it immediately.
3513
+ */
3514
+ async function loadFailover() {
3515
+ let out;
3516
+ try { out = await api('/api/failover'); } catch (e) { return; }
3517
+ const p = out.policy || {};
3518
+ $('foon').checked = !!p.enabled;
3519
+ $('fobody').hidden = !p.enabled;
3520
+ $('fodecide').value = p.decide || 'ask';
3521
+ $('foscope').value = p.scope || 'model';
3522
+ $('foorder').value = p.order || 'sequence';
3523
+ $('folist').value = (p.models || [])
3524
+ .map((c) => (c.provider ? c.provider + '/' : '') + c.model).join(', ');
3525
+ for (const name of ['exhausted', 'failing', 'limited', 'too-long']) {
3526
+ $('fo-' + name).checked = (p.on || []).indexOf(name) !== -1;
3527
+ }
3528
+ }
3529
+
3530
+ $('foon').onchange = () => { $('fobody').hidden = !$('foon').checked; };
3531
+
3532
+ $('fosave').onclick = async () => {
3533
+ const on = ['exhausted', 'failing', 'limited', 'too-long'].filter((n) => $('fo-' + n).checked);
3534
+ const models = $('folist').value.split(',').map((s) => s.trim()).filter(Boolean);
3535
+ let out;
3536
+ try {
3537
+ out = await api('/api/failover', { method: 'POST', body: JSON.stringify({
3538
+ enabled: $('foon').checked,
3539
+ decide: $('fodecide').value,
3540
+ scope: $('foscope').value,
3541
+ order: $('foorder').value,
3542
+ on: on,
3543
+ models: models,
3544
+ discover: models.length === 0,
3545
+ }) });
3546
+ } catch (e) {
3547
+ $('fosaid').style.color = 'var(--red)';
3548
+ $('fosaid').textContent = e.message;
3549
+ return;
3550
+ }
3551
+ $('fosaid').style.color = 'var(--green)';
3552
+ $('fosaid').textContent = out.policy.enabled
3553
+ ? 'Saved. ' + (out.policy.decide === 'auto' ? 'It will move on and say so.' : 'It will ask first.')
3554
+ : 'Saved — off. A failing model ends the turn.';
3555
+ };
3556
+
3446
3557
  $('keydrop').onclick = async () => {
3447
3558
  const name = $('mprov').value;
3448
3559
  try { await api('/api/key?provider=' + encodeURIComponent(name), { method: 'DELETE' }); }
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmqHlB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkxHlB,CAAC;AACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ui-css.d.ts","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA45B3C"}
1
+ {"version":3,"file":"ui-css.d.ts","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAy7B3C"}
@@ -257,9 +257,25 @@ header{height:47px;flex:0 0 47px;border-bottom:1px solid var(--line);display:fle
257
257
  .diff{border-top:1px solid var(--line);font-family:var(--mono);font-size:11.5px;line-height:1.45;
258
258
  overflow-x:auto;max-height:520px;overflow-y:auto}
259
259
  .diff div{padding:0 12px;white-space:pre}
260
+ /*
261
+ * A row is number, marker, code — three columns that cannot drift apart.
262
+ *
263
+ * The marker used to be stripped and there were no numbers, so a change was a coloured band with
264
+ * no way to say which line it was, and on a monochrome screen no way to tell which direction it
265
+ * went. Grid rather than inline, so a long line wraps under the code and never under the number.
266
+ */
267
+ .diff .dl{display:grid;grid-template-columns:3.6em 1.1em 1fr;gap:0;padding:0 12px 0 0;
268
+ white-space:pre-wrap;word-break:break-word}
269
+ .diff .dn{text-align:right;padding-right:10px;color:var(--dim);user-select:none;opacity:.75}
270
+ .diff .dm{text-align:center;user-select:none;font-weight:600}
271
+ .diff .dc{min-width:0}
260
272
  .diff .a{background:var(--add-bg);color:var(--add-ink)}
261
273
  .diff .d{background:var(--del-bg);color:var(--del-ink)}
274
+ .diff .a .dm{color:var(--add-ink)}
275
+ .diff .d .dm{color:var(--del-ink)}
262
276
  .diff .c{color:var(--muted)}
277
+ /* Inside a changed row the syntax colours would fight the red or green, so they defer to it. */
278
+ .diff .a .dc span,.diff .d .dc span{color:inherit!important}
263
279
  .diff .h{color:var(--dim);background:var(--panel-2);padding:2px 12px}
264
280
 
265
281
  /* ── timing ──────────────────────────────────────────────── */
@@ -648,6 +664,19 @@ dialog:has(.dlg.wide){max-width:560px}
648
664
  .rows .gut > div,.rows .src > div{white-space:pre;height:1.5em}
649
665
  .rows .gut > div.on{color:var(--cyan);background:var(--attn-bg)}
650
666
 
667
+ .fo{margin:2px 0 14px;padding:11px 0 0;border-top:1px solid var(--line-2)}
668
+ .folabel{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--fg);cursor:pointer}
669
+ .folabel input,.fochk input{accent-color:var(--cyan);cursor:pointer}
670
+ .forow{display:flex;align-items:center;flex-wrap:wrap;gap:7px;margin:9px 0;font-size:11.5px;
671
+ color:var(--muted)}
672
+ .forow select{background:var(--panel-2);color:var(--fg);border:1px solid var(--line-2);
673
+ border-radius:6px;padding:3px 6px;font-size:11.5px}
674
+ .fochk{display:flex;align-items:center;gap:5px;cursor:pointer}
675
+ #folist{width:100%;box-sizing:border-box;background:var(--panel-2);color:var(--fg);
676
+ border:1px solid var(--line-2);border-radius:7px;padding:6px 9px;font-family:var(--mono);
677
+ font-size:11.5px;margin:2px 0 4px}
678
+ #fosaid{color:var(--green)}
679
+
651
680
  /* A tool call with nothing to open — what was asked, and how it went. */
652
681
  .callhead{display:flex;align-items:center;gap:8px;padding:9px 13px;border-bottom:1px solid var(--line-2)}
653
682
  .callverb{color:var(--cyan);font-size:12px;text-transform:lowercase}
@@ -1 +1 @@
1
- {"version":3,"file":"ui-css.js","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO;;;;;;;;;;;;;;;;;gBAiBO,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAy4BtB,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"ui-css.js","sourceRoot":"","sources":["../../src/web/ui-css.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO;;;;;;;;;;;;;;;;;gBAiBO,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAs6BtB,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,CAyT7B"}
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/web/ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,wBAAgB,IAAI,IAAI,MAAM,CAmW7B"}
package/dist/web/ui.js CHANGED
@@ -281,6 +281,48 @@ export function page() {
281
281
  so a confirmation living inside it would be removed by the very refresh that proves it worked.
282
282
  -->
283
283
  <div id="keysaid" class="mnote"></div>
284
+ <!--
285
+ What to do when a model runs out or starts failing. Off unless it is turned on: a tool that
286
+ silently moves your work to a different model is not one that respects the user.
287
+ -->
288
+ <div class="fo">
289
+ <label class="folabel"><input type="checkbox" id="foon">
290
+ When this model runs out or starts failing, continue elsewhere</label>
291
+ <div id="fobody" hidden>
292
+ <div class="forow">
293
+ <span>Decide</span>
294
+ <select id="fodecide">
295
+ <option value="ask">ask me first</option>
296
+ <option value="auto">move on and tell me</option>
297
+ </select>
298
+ <span>Try</span>
299
+ <select id="foscope">
300
+ <option value="model">another model, same provider</option>
301
+ <option value="provider">another provider</option>
302
+ <option value="both">either</option>
303
+ </select>
304
+ <span>Order</span>
305
+ <select id="foorder">
306
+ <option value="sequence">the order I set</option>
307
+ <option value="random">pick at random</option>
308
+ </select>
309
+ </div>
310
+ <input id="folist" placeholder="models to try, in order — leave empty to use whatever the provider serves"
311
+ autocomplete="off" spellcheck="false">
312
+ <div class="mnote">One per comma. Prefix with a provider to move provider too, for example
313
+ <code>openrouter/minimax/minimax-m3:free</code>. Empty means ask the provider what it
314
+ serves and try those.</div>
315
+ <div class="forow">
316
+ <span>Because of</span>
317
+ <label class="fochk"><input type="checkbox" id="fo-exhausted" checked> out of credit</label>
318
+ <label class="fochk"><input type="checkbox" id="fo-failing" checked> failing upstream</label>
319
+ <label class="fochk"><input type="checkbox" id="fo-limited"> rate limited</label>
320
+ <label class="fochk"><input type="checkbox" id="fo-too-long"> conversation too long</label>
321
+ </div>
322
+ <button type="button" class="keygo" id="fosave">Save this policy</button>
323
+ <span id="fosaid" class="mnote"></span>
324
+ </div>
325
+ </div>
284
326
  <div id="keywhich" class="mnote" hidden></div>
285
327
  <div id="keyhas" class="mnote" hidden>
286
328
  A key for <b id="keyhaswho"></b> is remembered on this machine.
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6SF,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAuVF,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.53.0",
3
+ "version": "2.54.0",
4
4
  "description": "Kinetically Orchestrated Neural Execution Engine for Code",
5
5
  "type": "module",
6
6
  "bin": {