v2.2 - Small improvement Interface change

This commit is contained in:
pporcheret
2026-10-29 11:13:02 +01:00
parent a17c3cb614
commit 7f26f9b015
271 changed files with 6207 additions and 16044 deletions
@@ -0,0 +1,111 @@
/* ALFRED_HERMES_NEW_SESSION_V1 — reset sûr de la seule session conversationnelle Hermes. */
(() => {
'use strict';
function setup() {
const grid = document.querySelector('#avMoreDialog .av-more-grid');
if (!grid || document.getElementById('avHermesNewSession')) return false;
const button = document.createElement('button');
button.type = 'button';
button.id = 'avHermesNewSession';
button.className = 'av-hermes-new-session';
button.innerHTML = '<svg viewBox="0 0 24 24" class="a-icon" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7"/><path d="M3 3v6h6"/><path d="M12 7v5l4 2"/></svg><span>Nouvelle session Hermes</span>';
grid.appendChild(button);
const dialog = document.createElement('dialog');
dialog.id = 'avHermesSessionDialog';
dialog.className = 'av-hermes-session-dialog';
dialog.setAttribute('aria-labelledby', 'avHermesSessionTitle');
dialog.innerHTML = `
<form method="dialog" class="av-hermes-session-content">
<h2 id="avHermesSessionTitle">Nouvelle session Hermes</h2>
<p>Repartir sans le contexte de l’ancienne conversation. La prochaine demande utilisera une nouvelle session avec les outils Hermes disponibles. La session actuelle sera sauvegardée.</p>
<p class="av-hermes-session-note">Les outils, les Skills et les réglages de Dona restent inchangés. Aucune tâche Hermes n'est annulée.</p>
<p id="avHermesSessionMessage" class="av-hermes-session-message" role="status" aria-live="polite"></p>
<div class="av-hermes-session-actions">
<button type="button" id="avHermesSessionCancel" class="av-hermes-session-secondary">Annuler</button>
<button type="button" id="avHermesSessionConfirm" class="av-hermes-session-primary">Créer une nouvelle session</button>
</div>
</form>`;
document.body.appendChild(dialog);
const msg = dialog.querySelector('#avHermesSessionMessage');
const confirm = dialog.querySelector('#avHermesSessionConfirm');
const cancel = dialog.querySelector('#avHermesSessionCancel');
let csrf = '';
let busy = false;
function setMessage(text, error = false) {
msg.textContent = text;
msg.classList.toggle('is-error', error);
}
button.addEventListener('click', async () => {
document.getElementById('avMoreDialog')?.close();
setMessage('');
confirm.hidden = false;
cancel.textContent = 'Annuler';
dialog.showModal();
confirm.disabled = true;
try {
const response = await fetch('/api/control/auth', {credentials:'same-origin',cache:'no-store'});
if (!response.ok) throw new Error('Vérification administrateur impossible.');
const auth = await response.json();
if (!auth.authenticated || !auth.csrf) {
setMessage('Connecte-toi d’abord en administrateur dans Configuration (/config), puis reviens ici.', true);
confirm.hidden = true;
cancel.textContent = 'Fermer';
const link = document.createElement('a');
link.href = '/config';
link.textContent = 'Ouvrir Configuration';
link.className = 'av-hermes-session-login';
const old = dialog.querySelector('.av-hermes-session-login');
old?.remove();
msg.after(link);
} else {
dialog.querySelector('.av-hermes-session-login')?.remove();
csrf = auth.csrf;
confirm.disabled = false;
}
} catch (e) {
setMessage(e.message, true);
}
});
cancel.addEventListener('click', () => { if (!busy) dialog.close(); });
confirm.addEventListener('click', async () => {
if (busy || !csrf) return;
busy = true;
confirm.disabled = true;
cancel.disabled = true;
setMessage('Création de la nouvelle session…');
try {
const response = await fetch('/api/control/hermes/new-session', {
method:'POST', credentials:'same-origin', cache:'no-store',
headers: {'X-Alfred-CSRF':csrf,'Content-Type':'application/json'},
body:'{}'
});
const data = await response.json();
if (!response.ok || !data.ok) throw new Error(data.error || 'Erreur HTTP '+response.status);
setMessage(data.message || 'Nouvelle session prête.');
confirm.hidden = true;
cancel.textContent = 'Fermer';
} catch (e) {
setMessage(e.message, true);
} finally {
busy = false;
cancel.disabled = false;
confirm.disabled = false;
}
});
return true;
}
function init() {
if (setup()) return;
const observer = new MutationObserver(() => { if (setup()) observer.disconnect(); });
observer.observe(document.body,{childList:true,subtree:true});
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init, {once:true});
else init();
})();