Hauteur : bulles techniques en rangée, sections groupées, accès distant retiré

Trois gains de place, mesurés au navigateur en 1500×900.

- Raisonnement, outils et mémoire se posent CÔTE À CÔTE dans une rangée qui
  déborde à la ligne : un tour d'agent en enchaîne parfois dix, et empilées
  elles repoussaient la réponse hors de l'écran alors qu'elles ne portent
  qu'une étiquette tant qu'elles sont repliées. Mesuré : 8 bulles occupent
  2 lignes au lieu de 8. Dépliée, une bulle reprend toute la largeur — son
  contenu ne doit pas être comprimé dans une colonne étroite.

- Les sections de la barre latérale sont réunies en DEUX cartes (réglages
  d'IA / réglages d'application) au lieu d'une carte chacune : onze arrondis
  et autant de gouttières faisaient déborder la colonne. Mesuré : 876 px de
  contenu pour 876 px visibles — plus d'ascenseur.

- Section « Accès distant » supprimée, ainsi que son module JS (13-remote.js)
  et son chargement : elle pilotait le tunnel ajean.link, sans objet ici.
  Le code serveur du relais reste en place mais inerte (aucun jeton) : le
  retirer créerait des conflits à chaque reprise de l'amont.
This commit is contained in:
Loki committed 2026-08-15 22:20:46 +00:00
1 parent c90a2d86eb
commit 3740b881a8
6 files changed
+112 -254

No files matched your search

+1 -1
View File
@@ -491,7 +491,7 @@ async function loadAll(){
// allSettled et pas all : un seul chargement en échec (accès distant coupé,
// clé API absente…) ne doit pas empêcher la suite — et surtout pas laisser les
// hauteurs réservées en place pour toujours.
await Promise.allSettled([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadConversations(),loadIdentity(),loadAgent(),loadInternet(),loadMCP(),loadNode(),loadApiKey(),loadNetwork(),loadPrefs(),loadLlamacpp(),loadRemote()]);
await Promise.allSettled([loadStatus(),loadVram(),loadRam(),loadCfg(),loadPresets(),loadConversations(),loadIdentity(),loadAgent(),loadInternet(),loadMCP(),loadNode(),loadApiKey(),loadNetwork(),loadPrefs(),loadLlamacpp()]);
releaseHeights(); // tout est en place : on rend la main et on mesure pour la prochaine fois
}
async function act(a){ toast(a+'…'); await jpost('/api/'+a); setTimeout(loadAll,1500); }
+16 -1
View File
@@ -56,7 +56,22 @@ function addMsg(role, text){
}
}
el.querySelector('.body').textContent=text;
chatEl().appendChild(el);
// Bulles techniques (raisonnement, outils, mémoire) : elles se posent CÔTE À
// CÔTE dans une rangée qui déborde à la ligne. Un tour d'agent en enchaîne
// parfois dix ; empilées, elles repoussaient la réponse hors de l'écran alors
// qu'elles ne portent qu'une étiquette tant qu'elles sont repliées. Dépliée,
// une bulle reprend toute la largeur de la rangée (CSS .toolrow).
if(collapsible){
let row = chatEl().lastElementChild;
if(!row || !row.classList.contains('toolrow')){
row = document.createElement('div');
row.className = 'toolrow';
chatEl().appendChild(row);
}
row.appendChild(el);
} else {
chatEl().appendChild(el);
}
scrollMaybe();
return el;
}
-96
View File
@@ -1,96 +0,0 @@
// Accès distant (ajean.link) — piloté depuis l'UI, sans terminal.
// « Connecter » ouvre une popup app.ajean.link/connect.html qui gère compte +
// abonnement, puis renvoie une clé de liaison par postMessage. On la POSTe à
// l'agent local (/api/link/connect) qui fait le `loki link` (token + service).
const LOKI_APP_ORIGIN = 'https://app.ajean.link';
function renderRemote(d){
const off = document.getElementById('remote-off'), on = document.getElementById('remote-on');
const badge = document.getElementById('remote-badge');
if(!d || !d.linked){
// Serveur jamais lié : on l'affiche explicitement plutôt que de laisser la
// pastille vide, qui se lisait comme « je ne sais pas ».
off.style.display=''; on.style.display='none';
setBadge(badge, false, 'non connecté');
return;
}
off.style.display='none'; on.style.display='';
document.getElementById('remote-url').value = d.machineURL || '';
const st = document.getElementById('remote-status');
if(d.active){ st.textContent='● en ligne — accessible à distance'; st.style.color='var(--accent)'; }
else { st.textContent='○ tunnel arrêté (l\'accès distant ne répondra pas)'; st.style.color='var(--warn)'; }
const sb = document.getElementById('remote-start');
if(sb){ sb.style.display = d.active ? 'none' : ''; }
setBadge(badge, d.active ? true : 'warn', d.active ? 'connecté' : 'arrêté');
}
async function loadRemote(){
// Le panneau ne vaut qu'en LOCAL : il pilote /api/link/* que le tunnel bloque
// (boîte noire). Sur le portail distant (app.ajean.link/server.html), on le cache.
const det = document.getElementById('remote-details');
if(location.hostname === 'app.ajean.link'){ if(det) det.style.display='none'; return; }
// Statut injoignable : on retombe sur « non connecté » plutôt que de garder
// l'affichage précédent, qui pourrait annoncer « connecté » à tort.
try{ renderRemote(await jget('/api/link/status')); }catch(e){ renderRemote(null); }
}
// Ouvre la popup de connexion et attend la clé renvoyée par postMessage.
function remoteConnect(){
const params = new URLSearchParams({ origin: window.location.origin, host: window.location.hostname || 'ce serveur' });
const url = LOKI_APP_ORIGIN + '/connect.html?' + params.toString();
const pop = window.open(url, 'loki-connect', 'width=440,height=640');
if(!pop){ toast('autorisez les popups pour connecter ajean.link'); return; }
async function onMsg(ev){
// Anti-usurpation : n'accepte QUE des messages du portail ajean.link.
if(ev.origin !== LOKI_APP_ORIGIN) return;
const d = ev.data || {};
if(d.type !== 'loki-link' || !d.token) return;
window.removeEventListener('message', onMsg);
try{
const r = await jpost('/api/link/connect', { token: d.token });
if(r && r.linked){
toast('✓ accès distant connecté');
if(r.serviceErr){ toast('token enregistré (service : '+r.serviceErr+')'); }
loadRemote();
} else {
toast((r && r.error) || 'échec de la connexion');
}
}catch(e){ toast('erreur : '+e); }
}
window.addEventListener('message', onMsg);
}
// Relance le tunnel avec la clé déjà enregistrée (sans repasser par la popup).
async function remoteStart(){
const b = document.getElementById('remote-start');
if(b){ b.disabled = true; b.textContent = 'démarrage…'; }
try{
const r = await jpost('/api/link/start', {});
if(r && r.active){ toast('✓ tunnel démarré'); }
else { toast((r && r.error) || 'le tunnel n\'a pas démarré'); }
}catch(e){ toast('erreur : '+e); }
if(b){ b.disabled = false; b.textContent = 'démarrer le tunnel'; }
loadRemote();
}
async function remoteDisconnect(){
const ok = await askConfirm('Couper l\'accès distant et oublier la clé de liaison de ce serveur ?', {title:'Accès distant', okLabel:'Déconnecter'});
if(!ok) return;
try{ await jpost('/api/link/disconnect', {}); toast('accès distant coupé'); loadRemote(); }
catch(e){ toast('erreur : '+e); }
}
async function remotePairCode(){
const box = document.getElementById('remote-pair');
box.style.display=''; box.textContent='génération du code…';
try{
const r = await jpost('/api/link/paircode', {});
if(r && r.code){
box.innerHTML = 'Empreinte : <b>'+(r.fingerprint||'—')+'</b><br>Code d\'appairage (valable 10 min, usage unique) : <b>'+r.code+'</b>';
} else {
box.textContent = (r && r.error) || 'code indisponible';
}
}catch(e){ box.textContent='erreur : '+e; }
}