mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-23 15:08:16 +02:00
v0.5.10 : le produit s'appelle AJEAN + diff des ecritures dans le chat + variante AJEAN sombre
- renommage : « Jean » devient « AJEAN » dans tous les textes visibles (titre de l'UI, proprietes du binaire Windows, barre de menus macOS / zone de notification, messages du terminal, README). La commande, les services, les chemins et le depot ne changent pas. - nouveau thème « AJEAN sombre » (même habillage pixel, palette nuit) ; les regles de mise en page sont partagees via [data-theme^="ajean"]. - l'IA montre ce qu'elle ecrit : les outils edit / mem_add / mem_edit renvoient un diff ligne a ligne, affiche en vert (+) et rouge (-) dans la bulle d'outil et persiste avec la conversation (chat_diff.go). - ecritures idempotentes : si la modification est deja en place, edit et mem_edit repondent « deja a jour » au lieu d'une erreur trompeuse ; un appel d'outil rigoureusement identique n'est plus rejoue dans le meme tour. - saisie du chat auto-agrandissante (une ligne au repos en thème ChatGPT, deux ailleurs), bouton d'envoi enfin aligne, astuce clavier detachee de la carte. - editeur de preset relu pour le thème AJEAN (plus de double encadrement), champ + bouton de telechargement recolles dans tous les thèmes, interrupteurs carres. - emojis retires de l'interface (les glyphes monochromes restent).
This commit is contained in:
1 parent
6195d77759
commit
e2475c6688
30 files changed
+641
-209
No files matched your search
@@ -97,26 +97,26 @@ function renderBody(el, text){ const b=bodyOf(el); b.innerHTML = md(text); addCo
|
||||
// Render a tool call as its own conversation message: the command the model
|
||||
// wrote, then the response it got back. textContent keeps it injection-safe.
|
||||
function renderToolMsg(el, tu){
|
||||
// Métadonnées d'affichage par outil : nom court + en-tête avec icône. Les outils
|
||||
// web (web_search/open/read/grep) doivent afficher 🌐, pas le fallback mémoire.
|
||||
// Métadonnées d'affichage par outil : nom court + en-tête. Les outils web
|
||||
// (web_search/open/read/grep) ont leur propre libellé, pas le fallback mémoire.
|
||||
const META = {
|
||||
bash: {lbl:'terminal', head:'⚙️ commande'},
|
||||
edit: {lbl:'édition', head:'✏️ édition'},
|
||||
web_search: {lbl:'recherche', head:'🌐 recherche web'},
|
||||
web_open: {lbl:'page web', head:'🌐 ouverture'},
|
||||
web_read: {lbl:'page web', head:'🌐 lecture'},
|
||||
web_grep: {lbl:'page web', head:'🌐 recherche'},
|
||||
bash: {lbl:'terminal', head:'commande'},
|
||||
edit: {lbl:'édition', head:'édition'},
|
||||
web_search: {lbl:'recherche', head:'recherche web'},
|
||||
web_open: {lbl:'page web', head:'ouverture'},
|
||||
web_read: {lbl:'page web', head:'lecture'},
|
||||
web_grep: {lbl:'page web', head:'recherche'},
|
||||
};
|
||||
// Outils MCP (nom mcp__<serveur>__<outil>) : icône dédiée + libellé lisible,
|
||||
// Outils MCP (nom mcp__<serveur>__<outil>) : en-tête = nom du serveur, libellé lisible,
|
||||
// pas le fallback mémoire. On extrait serveur et outil du nom namespacé.
|
||||
let meta = META[tu.name];
|
||||
if(!meta && tu.name && tu.name.indexOf('mcp__')===0){
|
||||
const parts = tu.name.slice(5).split('__');
|
||||
const server = parts.shift() || 'mcp';
|
||||
const tool = parts.join('__') || tu.name;
|
||||
meta = {lbl: tool, head: '🔌 '+server};
|
||||
meta = {lbl: tool, head: server};
|
||||
}
|
||||
meta = meta || {lbl:'mémoire', head:'🧠 mémoire'};
|
||||
meta = meta || {lbl:'mémoire', head:'mémoire'};
|
||||
let lbl = meta.lbl;
|
||||
// Indication du volume de la réponse de l'outil (~tokens, estimation 1 tok ≈ 4 car).
|
||||
if(tu.result){ lbl += ' · ~' + Math.max(1, Math.round(tu.result.length/4)) + ' tok'; }
|
||||
@@ -131,6 +131,26 @@ function renderToolMsg(el, tu){
|
||||
if(tu.typing){ const car=document.createElement('span'); car.className='tool-caret'; car.textContent='▋'; code.appendChild(car); }
|
||||
pre.appendChild(code); body.appendChild(pre);
|
||||
}
|
||||
// Diff d'une écriture (fichier ou page de mémoire) : lignes ajoutées en vert,
|
||||
// retirées en rouge, contexte en gris — comme un diff de terminal.
|
||||
if(tu.diff && tu.diff.length){
|
||||
const sub=document.createElement('div'); sub.className='tool-sub';
|
||||
let add=0, del=0;
|
||||
tu.diff.forEach(l=>{ if(l.op==='+') add++; else if(l.op==='-') del++; });
|
||||
sub.textContent='modifications';
|
||||
const cnt=document.createElement('span'); cnt.className='diff-count';
|
||||
cnt.innerHTML='<span class="a">+'+add+'</span> <span class="d">-'+del+'</span>';
|
||||
sub.appendChild(cnt);
|
||||
body.appendChild(sub);
|
||||
const pre=document.createElement('pre'); pre.className='diff';
|
||||
tu.diff.forEach(l=>{
|
||||
const ln=document.createElement('span');
|
||||
ln.className='dl'+(l.op==='+'?' add':l.op==='-'?' del':'');
|
||||
ln.textContent=(l.op==='+'?'+':l.op==='-'?'-':' ')+' '+l.text;
|
||||
pre.appendChild(ln);
|
||||
});
|
||||
body.appendChild(pre);
|
||||
}
|
||||
const hasResult = tu.result!==undefined && tu.result!=='';
|
||||
if(hasResult){
|
||||
const sub=document.createElement('div'); sub.className='tool-sub'; sub.textContent='réponse';
|
||||
@@ -148,6 +168,8 @@ function renderToolMsg(el, tu){
|
||||
function addCopyButtons(root){
|
||||
root.querySelectorAll('pre').forEach(pre=>{
|
||||
if(pre.querySelector('.copybtn')) return;
|
||||
// Pas de bouton copier sur un diff : on copierait les préfixes + / - .
|
||||
if(pre.classList.contains('diff')) return;
|
||||
const btn=document.createElement('button');
|
||||
btn.className='copybtn'; btn.type='button'; btn.textContent='copier';
|
||||
btn.onclick=async(e)=>{
|
||||
@@ -204,3 +226,14 @@ function restoreChat(){
|
||||
connectStream();
|
||||
}
|
||||
function onKey(e){ if(e.key==='Enter' && !e.shiftKey){ e.preventDefault(); send(); } }
|
||||
// La zone de saisie s'ajuste à son contenu : une ligne au repos, puis elle
|
||||
// grandit jusqu'à sa max-height (au-delà, elle défile). Appelée à la frappe, à
|
||||
// l'envoi et au chargement.
|
||||
function autoGrow(ta){
|
||||
ta = ta || document.getElementById('input');
|
||||
if(!ta) return;
|
||||
ta.style.height='auto';
|
||||
const max=parseInt(getComputedStyle(ta).maxHeight,10)||200;
|
||||
ta.style.height=Math.min(ta.scrollHeight, max)+'px';
|
||||
ta.style.overflowY = ta.scrollHeight>max ? 'auto' : 'hidden';
|
||||
}
|
||||
Reference in new issue
Block a user