shadok-ai 0.2.8 → 0.2.10

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 (2) hide show
  1. package/package.json +1 -1
  2. package/public/index.html +26 -22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shadok-ai",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "main": "dist/session.js",
5
5
  "scripts": {
6
6
  "test": "node --import tsx --test test/*.ts .claude/skills/shadok-ai-agents/test/*.test.mjs",
package/public/index.html CHANGED
@@ -258,10 +258,8 @@
258
258
  .tab {
259
259
  position: relative;
260
260
  display: flex;
261
- /* Aligné en haut : led + icônes se posent sur la ligne du NOM (ligne 1),
262
- pas au centre des deux lignes. */
263
- align-items: flex-start;
264
- gap: 8px;
261
+ flex-direction: column; /* ligne 1 (led+nom+icônes) puis ligne 2 (infos) */
262
+ gap: 1px;
265
263
  font-family: var(--mono);
266
264
  font-size: 12px;
267
265
  color: var(--text-dim);
@@ -271,8 +269,7 @@
271
269
  cursor: pointer;
272
270
  user-select: none;
273
271
  }
274
- /* Recentre le point d'état sur la ligne du nom (sinon collé tout en haut). */
275
- .tab .led { margin-top: 4px; }
272
+ .tab-row1 { display: flex; align-items: center; gap: 8px; }
276
273
  /* Context-window usage: tiny number + thin bar at the bottom of the tab. */
277
274
  .tab .ctxnum { font-size: 9px; color: var(--text-dim); flex: none; }
278
275
  /* Heure du dernier message, discrète (le nom en flex:1 la pousse à droite). */
@@ -310,14 +307,12 @@
310
307
  border-radius: 0 4px 4px 0;
311
308
  box-shadow: inset 3px 0 0 var(--phosphor);
312
309
  }
313
- /* Nom + heure empilés : le titre sur sa ligne (jamais tronqué par l'heure),
314
- l'heure en dessous en tout petit. */
315
- .tab-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
316
- /* Ligne 2 : « xxx ago » + % de contexte, ensemble sous le nom. */
317
- .tab-info { display: flex; align-items: baseline; gap: 6px; }
318
- /* Le % de contexte poussé à droite de la ligne (« xxx ago » reste à gauche). */
319
- .tab-info .ctxnum { margin-left: auto; }
310
+ /* Ligne 2 pleine largeur : « xxx ago » à gauche, % de contexte tout à droite. */
311
+ .tab-row2 { display: flex; align-items: baseline; gap: 6px; }
312
+ .tab-row2 .ctxnum { margin-left: auto; }
320
313
  .tab .name {
314
+ flex: 1;
315
+ min-width: 0;
321
316
  overflow: hidden;
322
317
  text-overflow: ellipsis;
323
318
  white-space: nowrap;
@@ -1533,14 +1528,15 @@
1533
1528
  tg.innerHTML = '<svg viewBox="0 0 24 24" width="12" height="12" style="vertical-align:-1px" aria-hidden="true"><path fill="#26A5E4" d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 12 12 12 12 0 0 0 12-12A12 12 0 0 0 12 0a12 12 0 0 0-.056 0zm4.962 7.224c.1-.002.321.023.465.14a.506.506 0 0 1 .171.325c.016.093.036.306.02.472-.18 1.898-.962 6.502-1.36 8.627-.168.9-.499 1.201-.82 1.23-.696.065-1.225-.46-1.9-.902-1.056-.693-1.653-1.124-2.678-1.8-1.185-.78-.417-1.21.258-1.91.177-.184 3.247-2.977 3.307-3.23.007-.032.014-.15-.056-.212s-.174-.041-.249-.024c-.106.024-1.793 1.14-5.061 3.345-.48.33-.913.49-1.302.48-.428-.008-1.252-.241-1.865-.44-.752-.245-1.349-.374-1.297-.789.027-.216.325-.437.893-.663 3.498-1.524 5.83-2.529 6.998-3.014 3.332-1.386 4.025-1.627 4.476-1.635z"/></svg>';
1534
1529
  tg.title = "Mirrored to Telegram";
1535
1530
  // Nom + heure empilés (l'heure SOUS le titre, pour ne pas le tronquer).
1536
- const mainCol = document.createElement("div");
1537
- mainCol.className = "tab-main";
1538
- // Ligne 2 sous le nom : heure relative « xxx ago » + % de contexte, ensemble.
1539
- const infoRow = document.createElement("div");
1540
- infoRow.className = "tab-info";
1541
- infoRow.append(lastAt, ctxNum);
1542
- mainCol.append(name, infoRow);
1543
- btn.append(led, mainCol, timer, mute, cron, tg, close);
1531
+ // Deux lignes : ligne 1 = led + nom + icônes ; ligne 2 PLEINE LARGEUR =
1532
+ // « xxx ago » à gauche, % de contexte tout à droite (plus caché par les icônes).
1533
+ const row1 = document.createElement("div");
1534
+ row1.className = "tab-row1";
1535
+ row1.append(led, name, timer, mute, cron, tg, close);
1536
+ const row2 = document.createElement("div");
1537
+ row2.className = "tab-row2";
1538
+ row2.append(lastAt, ctxNum);
1539
+ btn.append(row1, row2);
1544
1540
  // Context-window usage: a thin progress bar at the bottom of the tab.
1545
1541
  const ctxBar = document.createElement("div");
1546
1542
  ctxBar.className = "ctxbar";
@@ -3644,6 +3640,14 @@
3644
3640
  for (let i = 0; i < bin.length; i++) a[i] = bin.charCodeAt(i);
3645
3641
  return a;
3646
3642
  }
3643
+ // Keystroke → base64, UTF-8 first. btoa() alone treats the string as Latin1,
3644
+ // so "é" (U+00E9) went out as the single byte 0xE9 instead of its UTF-8 pair
3645
+ // 0xC3 0xA9 → mojibake in the pane; anything above U+00FF (emoji…) threw.
3646
+ function strToB64Utf8(s) {
3647
+ let bin = "";
3648
+ for (const b of new TextEncoder().encode(s)) bin += String.fromCharCode(b);
3649
+ return btoa(bin);
3650
+ }
3647
3651
  function updateTermBtn() {
3648
3652
  const on = !!(active && active.termOn);
3649
3653
  const b = $("chanTerm");
@@ -3669,7 +3673,7 @@
3669
3673
  term.open($("xtermHost"));
3670
3674
  term.onData((d) => {
3671
3675
  if (term && termSession && termSession.ws)
3672
- termSession.ws.send(JSON.stringify({ type: "term-input", data: btoa(d) }));
3676
+ termSession.ws.send(JSON.stringify({ type: "term-input", data: strToB64Utf8(d) }));
3673
3677
  });
3674
3678
  }
3675
3679
  if (termSession !== active) {