Commit Graph
78 Commits
Author SHA1 Message Date
MichaelandClaude Opus 5.5 cf8d1cfaaa Version 0.14.0
Rattrapage d'AJEAN jusqu'à la 0.17.6 (contexte, reprise réseau, presets
externes, tâches ponctuelles, file d'attente) et reprises d'OpenFox pour le
mode Code (vérification quand le builder a fini, pré-vol des écritures,
relance des appels textuels, alias d'outils, consignes du dépôt, terminal).
Les 19 commits locaux de la synchro 0.13.6 → 0.16.3, restés hors de main,
y sont rejoués.

Bump des trois porteurs de version (constante Go, versioninfo.json, .syso
Windows régénérés), notes de release réécrites, NOTICE à jour des idées
reprises d'OpenFox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 23:41:37 +02:00
Claude 513aca1c7b Version 0.13.0
Le rattrapage de l'amont (navigateur piloté, chiffrement de la mémoire,
notifications, tâches script, sous-agents, anglais) était parti sur main
sous le numéro 0.12.3 : huit fonctionnalités sous un numéro de correctif.

Bump des trois porteurs de version — la constante Go, versioninfo.json et
les .syso Windows régénérés (go generate) — et notes de release réécrites
pour 0.13.0. Sans ça, `loki update` et le bandeau de mise à jour comparaient
une version qui ne bougeait pas.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6CAgoLJzufeA8rZTSpSpY
2026-09-23 07:52:59 +00:00
MichaelandClaude Fable 5 69bf8d985d Vérification du moteur de retour ; boutons MCP au gabarit ; « Paramètres »
- Le bouton « vérifier les mises à jour » revient dans la carte Moteur : il
  ne fait QUE regarder, là où « mettre à jour » télécharge et bascule après
  confirmation. Deux gestes qui n'engagent pas pareil, deux boutons.
- Les boutons « catalogue » / « + ajouter un serveur » (MCP) étaient des
  pilules arrondies au milieu de boutons rectangulaires : même gabarit que
  leurs voisins (4 px, 12 px, mêmes marges).
- « Réglages » devient « Paramètres » dans la barre latérale et en tête de
  la modale.

Version 0.12.3.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-21 08:13:21 +02:00
MichaelandClaude Fable 5 50fccdc9ad Captures d'écran : visibles en entier, jamais repliées d'office
La carte d'outil qui porte une capture (web_screenshot) échappe au plafond
de 280 px — l'image se montrait par le trou d'une serrure — et au repli
automatique : l'image EST le résultat, la replier la cachait sitôt prise.
Elle garde son max-height propre (420 px) et s'ouvre plein écran au clic.
Retirée de la liste de repli du tour pour survivre aussi au repli de fin de
tour. Au rejeu du journal, elle arrive repliée comme le reste de
l'historique. Version 0.12.2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 22:58:29 +02:00
MichaelandClaude Fable 5 66072e4047 Cartes de section : ouvertes tant qu'elles travaillent, repliées sitôt finies
Une carte (mémoire, raisonnement, outil…) reste ouverte pendant que SA
section travaille — bornée à 280 px, défilement qui suit l'écriture — et se
replie dès qu'elle est finie : l'outil au retour de son résultat, le
raisonnement quand le bloc suivant démarre, le reste en fin de tour. On
retrouve les fenêtres distinctes par section, sans qu'elles envahissent la
page. Version 0.12.1.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 22:47:45 +02:00
MichaelandClaude Fable 5 62573ff972 Version 0.12.0
Sélecteur de modèle fonctionnel, dictée vocale, cartes de raisonnement qui
suivent l'écriture, moyenne tok/s de la conversation, % de chargement réparé
à chaud, tri des discussions par création, bouton Réglages en pied de barre.
Notes de version à jour ; .syso régénérés.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 22:30:58 +02:00
MichaelandClaude Fable 5 43489769f4 Cartes raisonnement bornées et fluides ; version 0.11.0
Un long raisonnement (des milliers de tokens) faisait grandir la page de
plusieurs écrans et finissait par figer l'affichage : le bloc entier était
re-parsé en Markdown à chaque tick, en O(n²). Deux mesures :

- Les cartes raisonnement/outils ont une hauteur bornée (280 px) avec
  défilement interne, collé en bas pendant la génération (un défilement
  manuel vers le haut est respecté).
- En direct, un bloc de raisonnement géant n'est re-parsé que sur sa fin
  (REASON_TAIL) ; le texte complet est posé au rendu de fin de bloc. La
  finalité voyage avec le rendu en attente (renderPending.final) : le timer
  déjà armé passait final=false et consommait le rendu final en ne posant que
  la queue — le début du raisonnement n'était jamais rendu.

Version 0.11.0 (const, versioninfo, .syso régénérés) ; README et
RELEASE_NOTES à jour sur les nouveautés du fork.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-20 17:16:55 +02:00
Claude 276a8287cb Refonte : modèle chargé, attribution, ombres, flèche, favicon
Retours sur la refonte, cinq corrections.

Modèle affiché
  Le sélecteur de l'en-tête ne montrait que le PRESET actif — or un preset n'est
  « actif » que si son empreinte correspond exactement à la configuration. Une
  configuration écrite à la main, héritée de l'image ou modifiée d'un cran depuis
  le dernier preset n'en désigne aucun, et l'en-tête restait muet alors qu'un
  modèle tournait. Il retombe désormais sur le nom du fichier de la
  configuration active (loadCfg le lui donne), et l'infobulle porte le chemin
  complet.

Attribution
  « fork de AJEAN » revient sous le nom de l'app, dans l'en-tête de la barre
  latérale, au lieu du pied de la zone défilante.

Ombres
  Les bulles du fil et la carte de saisie portent une vraie ombre douce
  (--shadow-card), comme la maquette — le filet de 1 px ne les décollait pas du
  fond.

Bouton d'envoi
  Chevron sauge sur fond transparent, à la place de la pastille verte pleine :
  c'est le dessin de la maquette, et il suit alors la même charte que ses
  voisins (dépôt, fichiers).

Favicon
  Carré sauge (#5E7F5A) au lieu du carré noir, aux quatre endroits qui le
  dessinent : favicon SVG, icône d'accueil iOS, icône du .exe (icon.ico) et PNG
  macOS — tous rendus depuis sys_brand_icon.go, seule source du dessin. La
  variante « template » de macOS reste noire : le système ne lit que son alpha.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LPyFxVHNAN9u5pVzSYMwjd
2026-08-16 18:15:24 +00:00
Loki de6551a153 Rebaptise AJEAN en Loki (fork, lignée conservée)
- module github.com/R0m1k3/Loki, cmd/loki, internal/loki (package loki)
- LOKI_HOME, LOKI_MODEL_DIRS, LOKI_SERVICE, LOKI_DL_CONNS ; /etc/loki ;
  units loki-engine / loki-ui ; binaire et aide CLI
- updateRepo pointe sur R0m1k3/Loki (l'auto-update ne tirera plus les
  binaires AJEAN amont)

Conservé à l'identique : le domaine ajean.link (service de tunnel amont),
les littéraux de migration 0.7.x (migrate_07.go), RELEASE_NOTES.md et
LICENSE (historique et licence de l'amont).

go build/vet/test : verts.
2026-08-14 21:33:15 +00:00
nathaninline aeca75c547 v0.9.4 : la vision configurable par preset (projecteur mmproj) et les images envoyées au modele 2026-08-14 15:11:08 +02:00
nathaninline d4989f2991 v0.9.3 : statut moteur plus précis + réglages d'interface
- statut : la pastille ne dit plus toujours « modèle incompatible » (prêt /
  chargement… / erreur / arrêté) ; le détail n'accuse l'incompatibilité que
  quand le journal le montre (quant/architecture), sinon renvoie au journal
- panneau Actions : bouton « refresh » retiré ; mise à jour + exporter sur une
  ligne, bench + clear chat sur l'autre
- modale preset : titre sans le mot « Preset » redondant (juste le nom)
- mémoire : « auto (proactive) » → « auto »
2026-08-14 11:20:18 +02:00
nathaninline e3957fa749 v0.9.2 : postes distants dans le chat + envoi de fichiers via ajean.link reparé
- UI : bouton PC/wifi dans la barre de saisie → modale « Postes distants »
  (cible d'exécution, liste, appairage) ; bloc retiré des réglages
- envoi de fichiers derrière ajean.link : sendChunk passe par jfetch (E2E) au
  lieu d'un fetch brut qui n'atteignait pas le serveur derrière le relais
- ajean remote install ré-exécutable : --code force l'appairage, et nodeclient
  retire le service en cours + remplace le binaire verrouillé (Windows/Linux)
- MAJ depuis l'UI : restartAfterUpdate en sudo -n quand le service tourne en
  non-root ; références ajean-link → ajean-ui ; hint de restart corrigé
2026-08-14 10:31:46 +02:00
nathaninline 88d1e79e80 v0.9.1 : le poste distant est integre a ajean (fini le binaire ajean-remote separe)
- nouvelle sous-commande `ajean remote install|connect|run|status|uninstall|logout`
  (reutilise internal/nodeclient), remplace le binaire cmd/ajean-remote supprime
- le service (Windows/systemd/launchd) lance desormais `ajean remote run`
- UI Postes distants : commande affichee `ajean remote install ...`
- CI release : retrait du cross-build des 6 binaires ajean-remote
2026-08-14 09:24:40 +02:00
nathaninline 1454dff2a7 v0.9.0 : poste distant accessible via ajean.link, chiffré de bout en bout (relais aveugle) 2026-08-11 15:29:36 +02:00
nathaninline 7fa5461136 v0.8.9 : piloter un autre PC depuis l'IA (poste distant ajean-remote) 2026-08-11 14:58:15 +02:00
nathaninline e07051e1e3 v0.8.8 : envoi de fichiers jusqu'a 1 Go, en morceaux
La limite de 24 Mo n'etait pas arbitraire : le fichier partait dans un
seul corps JSON en base64, tenu entier en memoire par le navigateur puis
par le serveur. Relever la constante seule aurait demande ~1,4 Go de RAM
de chaque cote pour un fichier de 1 Go.

Le transfert est donc decoupe en tranches de 8 Mo. Le navigateur lit une
tranche a la fois (Blob.slice), le serveur la decode, l'ecrit dans un
.part et l'oublie ; seul le descripteur reste ouvert. Mesure sur 120 Mo :
la RAM du process n'a pas bouge (95 -> 96 Mo).

uploadMaxBytes (1 Go) borne desormais le DISQUE ; c'est uploadChunkMax
(8 Mo) qui borne la memoire, et lui seul.

Une session interrompue est balayee au bout de 10 min, et les .part
orphelins sont effaces au demarrage du service : les sessions vivent en
memoire, aucun n'est reprenable apres un arret. Un identifiant inconnu
est refuse en 409 plutot que de reprendre un fichier en son milieu.

La vignette affiche l'avancement en pourcentage au-dela d'une tranche.
2026-08-10 20:05:01 +02:00
nathaninline 6807bad48d v0.8.7 : envoyer et recevoir des fichiers dans le chat
Les fichiers circulent enfin dans les deux sens.

Envoi : trombone dans le composeur, glisser-deposer sur toute la fenetre,
ou Ctrl+V. Le fichier est depose dans uploads/ du dossier de travail de
l'agent et son chemin est annonce au modele, qui en fait ce qu'il veut
avec ses outils. Rien n'est interprete au passage, donc tout type de
fichier passe. Le depot n'a lieu qu'a l'ENVOI du message : retirer un
fichier de la liste ne laisse aucune trace sur le disque. Transport en
base64 dans du JSON et non en multipart, seule forme que le tunnel E2E
dispatche : l'acces distant marche sans code specifique.

Reception : le modele ecrit un lien Markdown ordinaire vers un fichier de
son dossier de travail, et le clic telecharge. Il repondait jusqu'ici par
un chemin serveur, inutilisable depuis un navigateur. Le clic passe par
fetch + blob (la cle de pilotage voyage dans un en-tete qu'une navigation
ne porterait pas, et le chemin de base change derriere le tunnel).
Markdown refusant les espaces non echappes dans une cible de lien, ils
sont encodes avant rendu : sans ca [x](mon rapport.pdf) ne produisait
rien du tout.

Perimetre du telechargement strictement limite au dossier de travail :
'..', chemins absolus et liens symboliques qui en sortent sont refuses,
et le fichier est toujours servi en piece jointe avec nosniff — un .html
produit par le modele ne doit pas s'executer dans l'origine de l'UI, ou
il lirait la cle de pilotage.

Preambule du mode agent : ~2350 -> ~1770 tokens, sans perdre une regle.
Le poids etait dans les schemas d'outils (le double du prompt), pas dans
le prompt. Celui-ci reenumerait des outils que les schemas decrivent
deja, et la regle « write, jamais echo » y figurait trois fois. Trois
tests gardent le budget : ce prompt a deja regrossi ligne par ligne deux
fois.

Aussi : l'export mentionne les pieces jointes (un message sans texte
donnait une section vide), et le decompte de contexte perd le mot
« contexte » au profit du nom du modele.
2026-08-10 17:11:56 +02:00
nathaninline 5a4c33661d v0.8.6 : changer la cle de pilotage ne coupe plus l'acces distant
Le tunnel lisait la cle une seule fois a son ouverture et injectait
l'ancienne apres tout changement : l'acces distant tombait en 401
jusqu'au redemarrage du service, avec pour seul symptome un
« chargement de la conversation » infini.
2026-08-08 21:32:52 +02:00
nathaninline 0ad961d75f v0.8.5 : le chat ne s'arrete plus en silence, et l'export se regle vraiment
Correction principale : un flux de reponse coupe en cours de route
etait indiscernable d'une fin normale (sc.Err() jamais consulte), donc
le tour se refermait sans un mot pendant que le moteur affichait un
« stop processing » normal. Issue #19. Un appel d'outil a moitie recu
pouvait meme etre execute avec des arguments tronques.

Fenetre d'export refaite : memes options de contenu quel que soit le
format, portee au curseur borne au nombre reel d'echanges, etat « rien
a exporter » sur un fil vide, style de l'editeur de preset. « clear
chat » passe en derniere position.

Aussi : la memoire n'est plus annoncee au modele sous MEMORY/ (issue
#20), et l'ecartement du binaire pendant une mise a jour ne peut plus
produire deux fois le meme nom.
2026-08-08 21:18:29 +02:00
nathaninline 52baab5786 v0.8.4 : l'historique s'exporte, le moteur se laisse joindre, les modeles en plusieurs fichiers marchent
Trois retours d'utilisateurs apres la 0.8.3.

Export de la conversation (regression de la 0.8 : conversation.json a
disparu dans ajean.db, verrouille et binaire). Bouton dans l'UI +
commande 'ajean export [--json] [fichier]', endpoint /api/chat/export.

Ecoute reseau du moteur : interrupteur 'joignable depuis le reseau local'
dans le panneau Acces OpenAI (HOST + regle de pare-feu Windows), commande
'ajean network [on|off|status]'. HOST devient un reglage de machine
preserve au changement de preset.

Modeles GGUF decoupes en tranches -00001-of-000NN : une famille = un
modele. Telechargement de toutes les tranches depuis n'importe quel lien,
sonde d'espace disque sur le total, liste et suppression regroupees,
demarrage refuse avec le nom du fichier manquant.
2026-08-08 20:01:54 +02:00
nathaninline acf11ff66a v0.8.3 : le stop arrete vraiment, le chat ne se bloque plus, raisonnement off = off
Bug 1 (chat bloque, remonte par Nathan) : trois causes cumulees.
- runShell naissait d'un contexte independant du tour : stop n'arretait rien.
  La commande herite desormais du contexte du tour, et la boucle d'outils
  s'interrompt des que l'arret est demande.
- cmd.WaitDelay : une commande laissant un process detache gardait les tubes
  ouverts, donc Wait ne revenait JAMAIS (ni delai, ni stop).
- Reset debloque toujours l'etat de generation : « nouvelle conversation » etait
  le geste tente quand le chat coince, il ne servait a rien. Un tour perime ne
  libere plus le tour courant.
Trouve en testant : le workspace disparu cassait TOUTES les commandes suivantes
(chdir: no such file or directory) jusqu'au redemarrage ; il est recree au besoin.

Bug 2 (raisonnement, remonte par Nathan) : l'UI ecrivait « off » en EFFACANT la
ligne REASONING, or sans drapeau le moteur suit le gabarit du modele, qui
raisonne. L'UI ecrit maintenant on|off et « off » part en --reasoning off, apres
avoir demande au binaire s'il connait le drapeau (ik_llama.cpp ne le connait pas
et refuserait de demarrer). Presets existants inchanges ; l'editeur dit desormais
« non precise : le modele decide » quand la cle est absente.
2026-08-08 11:20:22 +02:00
nathaninline e6a948c314 v0.8.2 : audit du coeur, correctifs de securite et de robustesse
- Le mode agent redevient une vraie fermeture : une surcharge de requete ne peut
  plus RALLUMER l'agent (donc bash/write/edit/MCP) quand la machine l'a coupe.
- Une lecture ratee de la cle de pilotage ne se confond plus avec « aucune cle » :
  requireWebAuth ferme (503) au lieu d'ouvrir l'API.
- healthCheck : timeout de 3 s. Sans lui, un moteur qui accepte la connexion sans
  repondre laissait /api/chat/send bloque indefiniment.
- Acces distant : la session de tunnel ecoute enfin un contexte. Un redemarrage ne
  fait plus cohabiter deux sessions ; le backoff se remet a zero apres une session
  qui a tenu.
- Flux SSE : selection des evenements neufs par dichotomie au lieu de relire tout
  le journal a chaque token et pour chaque appareil.
- Cache de lecture de la configuration, invalide par ecriture locale, par mtime et
  par age : fin des ~100 ouvertures de base par tour agentique.
- Erreurs moteur classees par type (errors.Is / net.Error) et non par sous-chaine
  anglaise ; les 3 compactions partagent un seul chemin ; champs morts de chatReq
  retires ; ReadHeaderTimeout sur les deux serveurs HTTP.
2026-08-08 10:56:41 +02:00
nathaninline db47c72240 v0.8.1 : le moteur dit enfin pourquoi il ne demarre pas, et les presets repartent propres
- start/restart : preflight (BIN, MODEL, .gguf) et fin du faux « [ok] activating »
  sur un service qui redemarre en boucle (SubState auto-restart).
- MODEL en chemin absolu accepte hors des dossiers declares (lecture seule) ;
  l'allowlist reste sur la suppression de fichiers.
- ajean edit : squelette commente des cles au lieu d'un fichier quasi vide.
- install : les prochaines etapes n'oublient plus « ajean llamacpp install ».
- Presets : un nouveau preset ne recopie plus la config active (issue #17),
  seulement BIN/HOST/PORT.
- Presets : plus de guillemet interne mange a la relecture (Go et interface),
  et EXTRA_ARGS decoupe en respectant les guillemets.
2026-08-08 09:16:16 +02:00
nathaninline 68d6d2032a Windows : version de fichier, fenetres de console et remplacement d'un meme build
Trois defauts signales a l'usage.

1. Le binaire 0.8.0 se DECLARAIT 0.7.13 a Windows : j'avais bump la constante Go
   sans toucher a cmd/ajean/versioninfo.json ni regenerer les .syso. D'ou le
   « version en cours 0.7.13 / ce fichier 0.8.0 » a chaque relance du fichier
   telecharge. Ressource remise a 0.8.0, .syso regeneres, et un test garde
   desormais les deux en phase.

2. Des fenetres de console apparaissaient : la relance apres installation et
   l'ouverture du navigateur creaient un enfant sans masquer sa fenetre, ce qui
   se voit maintenant que le binaire est en sous-systeme console. Les deux
   passent par hideCmd. Les raccourcis DEJA poses recoivent en plus le demarrage
   minimise, qui ne s'appliquait qu'aux nouveaux.

3. Deux builds de meme version n'etaient jamais remplaces : relancer un
   telechargement plus recent d'une preversion republiee demarrait simplement
   l'ancienne copie. On compare desormais les fichiers (taille puis SHA-256) et
   non les seuls numeros.

Au passage, l'icone est epinglee sur le raccourci : Windows garde parfois en
cache celle d'un binaire remplace et affiche un carre blanc.
2026-08-07 22:30:01 +02:00
nathaninline 081a88c846 v0.7.13 : selection de preset instantanee, envoi bloque tant que le modele charge
- Preset actif : liseré gauche droit, rogné par l'arrondi de la carte, un peu plus large
- Puce de l'actif dessinée en CSS (même taille et même assiette sur Windows et macOS)
- Survol et sélection moins appuyés dans la liste
- Bascule : retour visuel immédiat (barre qui glisse depuis la gauche, atténuée puis
  pleine) ; animations rejouées seulement quand la sélection change vraiment
- /api/switch répond sans attendre le redémarrage du service : bascule instantanée
- Bouton envoyer et touche Entrée désactivés tant que le modèle n'est pas chargé
2026-08-06 11:59:41 +02:00
nathaninline 742c14544a v0.7.12 : plus rien ne bouge apres le chargement 2026-08-05 21:59:30 +02:00
nathaninline f3769299b9 v0.7.11 : le menu parle enfin la meme langue partout 2026-08-05 21:21:16 +02:00
nathaninline fd758ce4f8 v0.7.10 : la mise a jour Windows arrete d'accuser les droits
- ecartement du binaire sous un nom unique : un reste verrouille par un ancien
  processus ne fait plus echouer le remplacement (message "droits insuffisants,
  relance en administrateur" qui etait faux, aucun privilege ne remplace une
  image en cours d'execution)
- section Cartes graphiques masquee pour de vrai avec une seule carte :
  l'attribut hidden etait sans effet, .pe-group{display:flex} l'emportait
2026-08-05 17:07:05 +02:00
nathaninline e57fc0966e v0.7.9 : les moteurs llama.cpp arretent de jouer a cache-cache
- moteur precompile : la version installee est celle qui tourne (on elisait le
  dossier le plus ancien), et les anciennes extractions sont purgees
- presets : le moteur precompile reste reconnu apres une mise a jour, et un BIN
  pointant une release disparue suit la version installee au lieu d'echouer
- build CUDA : le toolkit est cherche avant le nvcc du PATH, sa racine est
  passee a CMake (fin du "CUDA Toolkit not found" avec CUDA installe)
- job d'installation : etat persiste sur disque, une operation interrompue par
  un redemarrage du service est annoncee, pastille de rappel sur mobile
- editeur de modele : section Cartes graphiques (--device / --tensor-split), la
  liste vient du moteur du preset car les identifiants dependent du backend
- reglages : plus de menu replie, interrupteurs regroupes, decodage speculatif
- CUDA_VISIBLE_DEVICES et WEB_ENGINE survivent au changement de preset, sauf si
  le preset les definit lui-meme
2026-08-05 16:51:10 +02:00
nathaninline 9dedba0e47 v0.7.7 : la recherche internet ne tourne plus en rond
Le compactage du contexte detruisait ce dont l'IA avait besoin pour continuer
une recherche, ce qui la faisait boucler ou repartir de zero.

- Compactage : le resume est desormais fabrique a partir du torse ORIGINAL. On
  degraissait les resultats d'outils (page web -> marqueur) AVANT de resumer :
  le resumeur ne voyait plus aucune information trouvee, donc le resume n'en
  contenait aucune et l'IA relancait les memes recherches sans fin. Les
  resultats sont seulement raccourcis (1200 car.) pour le resumeur ; le torse
  degraisse ne sert plus que de repli si le resume echoue.
- Compactage : la demande EN COURS est preservee telle quelle. Pendant une
  boucle d'outils il n'y a aucun message user recent, elle tombait donc dans le
  torse et se dissolvait dans le resume, tandis que le TOUT PREMIER message de
  la conversation restait epingle en tete : l'IA repondait a la question du
  debut et abandonnait la recherche.
- Compactage : prompt du resumeur refait (findings, sources deja consultees,
  etat d'avancement) et plafond du resume porte de 1500 a 2200 caracteres.
- Appels repetes : l'avertissement passe EN TETE du resultat et, des la 2e
  redemande identique, le contenu n'est plus renvoye. Colle a la fin d'un
  resultat de plusieurs milliers de caracteres, il passait inapercu.
- Marqueur d'effacement du compactage : dit explicitement de ne PAS rappeler
  l'outil (l'ancien texte se lisait comme une invitation a re-telecharger).
- Outils web : sortie bornee a 8000 caracteres comme le shell. Un
  web_read(limit=500) pouvait injecter 25000 caracteres d'un coup et declencher
  les compactages en cascade.
- Bulles d'outils : la borne d'affichage passe de 4000 a 12000 caracteres, donc
  l'etiquette « ~N tok » cesse d'afficher toujours ~1004 (la valeur du plafond)
  et donne la vraie taille. Le chemin « appel identique non rejoue » envoyait
  lui le resultat brut sans troncature.
2026-08-04 22:28:19 +02:00
nathaninline e730c1ef49 v0.7.6 : ne plus creer le dossier SKILLS
Les skills ont ete fondus dans la memoire, mais les trois chemins
d'installation (Windows, Linux, macOS) creaient toujours un dossier SKILLS
vide.

On cesse de le CREER sans cesser de le LIRE : migrateSkillsToMemory reprend
encore une fois les anciens skills d'une installation existante, et il faut
donc que skillsDir() continue de pointer quelque part. La fonction ne fait
rien quand le dossier est absent.

Rien n'est supprime : un dossier SKILLS existant reste en place, son contenu
ayant deja ete repris dans la memoire.

Verifie sur une installation neuve en bac a sable : plus aucun SKILLS cree.
2026-08-04 17:38:08 +02:00
nathaninline d72578ea55 v0.7.5 : le bouton de mise a jour redemarre l'application (Windows)
Un process ne peut pas se relancer lui-meme : tant qu'il tourne, il occupe le
port et tient son propre dossier de donnees. On delegue donc a un
accompagnateur detache — une copie de nous lancee avec une sous-commande
interne — qui attend notre disparition, migre pendant cette fenetre, puis
relance l'application.

C'est cette fenetre qui manquait depuis le debut. Une mise a jour en place
laisse AJEAN tourner, donc le dossier tenu, donc le renommage echoue avec
« Acces refuse » — que Windows renvoie aussi bien pour un verrou que pour un
manque de droits. D'ou des postes bloques sur l'ancien nom malgre 0.7.1 a
0.7.4. Le retour terrain le confirme : la migration n'a abouti qu'en lancant
l'exe telecharge, seul chemin qui arretait les instances avant de migrer.

installedExePath() est relu APRES la migration avant de relancer : le binaire
installe vit dans le dossier de donnees, il change donc de place avec lui, et
relancer l'ancien chemin echouerait. Repli sur le binaire courant si la cible
a disparu — mieux vaut relancer quelque chose que laisser l'utilisateur sans
application.

L'attente est bornee a 30 s. Un depassement n'interrompt pas la suite : la
migration echouera peut-etre et sera retentee plus tard, alors que rester
coince laisserait l'utilisateur sans rien.

Verifie de bout en bout sur banc d'essai : l'accompagnateur attend la
fermeture du process cible, se termine proprement, et l'application est bien
relancee et ressert l'UI.
2026-08-04 17:31:06 +02:00
nathaninline 1f773151a6 v0.7.4 : migrer le dossier depuis le chemin de mise a jour (Windows)
L'elevation ajoutee en 0.7.3 n'etait jamais atteinte. Elle n'etait cablee que
dans `install` et dans l'installeur de mise a jour (double-clic sur l'exe
telecharge) ; or les utilisateurs font `ajean update` ou cliquent le bouton de
l'interface. restartAfterUpdate ne fait rien sous Windows, et au redemarrage
appFirstRun sort avant d'arriver la (l'application se reconnait comme etant
deja l'installee). Aucun poste ne migrait donc jamais.

postUpdateMigrate est appele apres une mise a jour reussie, cote CLI comme
cote UI web.

Une hypothese a ete invalidee au passage, et elle changeait tout : on croyait
qu'un binaire en cours d'execution empechait de renommer le dossier qui le
contient. C'est faux — Windows verrouille le fichier .exe, pas le nom de ses
dossiers parents. Verifie sur banc d'essai. La migration peut donc se faire
depuis l'application en marche, ce qui rend ce chemin possible.

Consequence non anticipee, traitee ici : le binaire installe vit DANS le
dossier de donnees. Le renommer deplace donc le programme, et laisse un
raccourci du menu Demarrer et une entree de PATH pointant dans le vide.
relinkAfterMigration repointe le raccourci, ajoute le nouveau dossier bin au
PATH et retire l'ancien.

Course de donnees corrigee : retryHomeMigration reinitialisait le cache du
dossier resolu sans verrou, alors qu'il est desormais appele depuis un handler
HTTP pendant que le serveur sert d'autres requetes. sync.Once est remplace par
un RWMutex, et les reinitialisations directes des installeurs Unix passent par
resetResolvedHome.
2026-08-04 17:16:17 +02:00
nathaninline 8365447de0 v0.7.3 : demander l'elevation Windows quand elle debloque la migration
Un compte non administrateur ne peut pas renommer C:\ProgramData\jean : le
droit manquant porte sur C:\ProgramData. Ces postes gardaient donc l'ancien
nom indefiniment. Les 0.7.1 et 0.7.2 avaient traite le bruit, pas le fond.

L'installation relance desormais AJEAN en administrateur le temps de la
SEULE migration (sous-commande interne, absente de l'aide), puis rend la
main. Un refus de la fenetre UAC est une reponse valable : on continue sur
l'ancien chemin, sans rien casser.

Deux tentatives de discrimination ont echoue avant celle-ci, et le detail
compte pour qui relira ce code :

- Le code d'erreur ne distingue rien. Windows renvoie ERROR_ACCESS_DENIED
  aussi bien pour un manque de droits que pour un dossier verrouille par un
  programme en cours. Un test le prouve, il avait ete ecrit en croyant
  l'inverse.
- Sonder l'ecriture dans le dossier parent ne distingue rien non plus :
  ProgramData autorise la creation de fichiers aux utilisateurs standards,
  c'est la suppression/renommage d'une entree existante qui est refusee.

C'est donc le LIEU D'APPEL qui selectionne, et lui est fiable : on n'eleve
que depuis `install` et depuis l'installeur de mise a jour, tous deux apres
l'arret des instances. Le cas « verrouille » y est deja ecarte.

Note pour les tests : ne JAMAIS appeler elevateForHomeMigration() sous
`go test`. os.Executable() y designe le binaire de test, que l'elevation
relance — donc toute la suite, en boucle. Constate.
2026-08-04 17:03:34 +02:00
nathaninline 7a141d19b5 v0.7.2 : l'alias jean.exe et les raccourcis restaient sur une version perimee
Regression introduite par l'alias de la 0.7.0, signalee en usage : « Une
version plus recente d'AJEAN est deja installee » a CHAQUE lancement, sans
moyen d'en sortir.

Deux defauts qui se renforcaient.

installLegacyAlias utilisait copyExe, qui echoue quand jean.exe est en cours
d'execution — Windows refuse d'ecraser un .exe actif. L'echec etait ignore
volontairement (« sans gravite, la copie repassera au prochain lancement »),
ce qui etait faux : l'alias restait fige indefiniment. replaceExe applique
desormais la technique deja utilisee pour le binaire principal — renommer
l'ancien, ecrire le nouveau, restaurer si la copie echoue. installSelf s'en
sert aussi, pour la meme raison.

ensureShortcuts ne touchait jamais un raccourci existant. Ceux crees avant la
0.7.0 visaient donc toujours jean.exe. Chaque lancement executait l'alias
perime, qui voyait ajean.exe plus recent et le signalait — la boucle. Un
raccourci existant est maintenant repointe s'il vise autre chose que le
binaire courant.

cleanupOldBinary balaie aussi le jean.exe.old que le nouveau remplacement
peut laisser.

Deux tests : remplacement d'un exe verrouille, et garantie que la cible ne
disparait jamais si la copie echoue apres le renommage.
2026-08-04 16:50:39 +02:00
nathaninline b4d2d5ed02 v0.7.1 : ne plus afficher l'echec de migration a chaque commande
Remonte par un utilisateur Windows non administrateur. Renommer
C:\ProgramData\jean exige d'ecrire dans C:\ProgramData, ce qu'un compte
standard ne peut pas faire : le rename echouait a chaque lancement et le
message technique s'affichait avant CHAQUE commande, y compris `ajean help`.

Rien n'etait casse — le repli sur l'ancien chemin fonctionne comme prevu et
aucune donnee n'est en jeu. Le defaut etait entierement dans l'affichage :
un detail interne presente comme une erreur, sur une situation permanente et
sans consequence.

La raison est desormais enregistree au lieu d'etre imprimee, et ressortie la
ou elle est actionnable : `ajean where`, qui parle justement d'emplacements,
avec la marche a suivre. `ajean install` en administrateur retente la
migration — c'est le seul moment ou les droits sont reunis — et le fait AVANT
de resoudre le dossier, sinon la variable resterait sur l'ancien chemin et on
installerait a cote.

La cause du rename est extraite du *os.LinkError : son texte repete les deux
chemins complets, ce qui donnait trois fois les memes chemins dans un message
qui les cite deja et noyait l'essentiel (« Acces refuse »).

Deux tests : l'echec reste silencieux mais enregistre, et aucun message
parasite quand la migration reussit. Verifie sur un cas reproduit — `help`
est propre, `where` affiche le conseil.
2026-08-04 16:40:22 +02:00
nathaninline 2b20158e7c CI : chemins cmd/jean -> cmd/ajean oublies dans les workflows
Le renommage des dossiers avait ete repercute dans release.yml mais pas
dans ci.yml, qui compilait encore ./cmd/jean : les deux jobs echouaient.
Une occurrence trainait aussi dans mac-build.yml (cmd/jean/icon.ico), que
le remplacement precedent n'avait attrapee que pour icon.png.

Un cas n'etait pas qu'un commentaire : tools/assemble-ui utilisait
"internal/jean/ui" comme chemin par defaut. La directive go:generate passe
le dossier en argument, donc la generation fonctionnait, mais l'invocation
directe documentee dans son propre en-tete (go run ./tools/assemble-ui)
aurait echoue.

Le reste etait des commentaires designant les anciens chemins, corriges
pour que le depot ne mente plus sur sa propre structure.

Job ci rejoue en entier en local : gofmt, vet, build, tests et les quatre
cross-compilations de release.
2026-08-04 16:31:43 +02:00
nathaninline aa452f9799 v0.7.0 : Jean devient AJEAN
Bump de version et notes de release. Le renommage complet jean -> AJEAN
est decrit dans RELEASE_NOTES.md ; les commits precedents en portent le
detail technique.
2026-08-04 15:59:41 +02:00
nathaninline 993be881d5 Renommage AJEAN (3/3) : textes, aide, README et variables d'environnement
Surface visible passee en AJEAN : aide de la CLI, messages, invite du chat
terminal, commentaires, README, metadonnees Windows du binaire
(InternalName / OriginalFilename).

Les reglages s'appellent desormais AJEAN_* (AJEAN_HOME, AJEAN_MODEL_DIRS,
AJEAN_DL_CONNS, AJEAN_LINK_URL, AJEAN_ACME_EMAIL, AJEAN_SERVICE), avec
l'ancien nom JEAN_* toujours lu en second via envAny(). Ces variables sont
posees a la main dans des shells, des units, des docker-compose et des
scripts de deploiement qu'on ne peut pas retrouver : cesser de les lire
ferait retomber silencieusement un reglage sur sa valeur par defaut.

Migration one-shot du dossier de donnees retentee dans la fenetre ou
l'installateur Windows a arrete toutes les instances, seule fenetre ou le
rename peut aboutir. Le chemin du binaire est recalcule juste apres, sinon
on reinstallerait dans le dossier qu'on vient de deplacer.

Deux choses volontairement NON renommees, parce que les renommer casserait
des utilisateurs sans rien apporter :

- "model": "jean", le nom expose sur l'endpoint compatible OpenAI. Des
  integrations externes le configurent en dur.
- les cles localStorage (jean-theme, jean.sys...). Les renommer
  reinitialiserait theme, preferences d'affichage et prompt systeme dans le
  navigateur de chaque utilisateur.

Le plist launchd recevait /usr/local/bin/jean en dur : le chemin est
desormais injecte, sinon le daemon macOS aurait refuse de demarrer apres le
renommage.

index.html regenere depuis ui/src via go generate.
2026-08-04 14:16:12 +02:00
nathaninline 110458c133 Renommage AJEAN (1/3) : module, chemins de donnees et auto-MAJ
Socle du renommage jean -> AJEAN, sans aucun impact visible pour le parc
installe. Trois briques :

- module github.com/nathaninline/ajean, cmd/ajean, internal/ajean,
  package ajean. Purement interne.

- AjeanHome() remplace JeanHome(). Les defauts deviennent
  %ProgramData%\ajean et /etc/ajean, avec migration du dossier existant
  au premier lancement. La migration est un os.Rename dans le dossier
  parent de l'ancien chemin : intra-volume, donc atomique et instantane
  meme avec des .gguf de plusieurs dizaines de Go. Si le rename echoue
  (handle ouvert sous Windows, droits, volume en lecture seule) on
  CONTINUE sur l'ancien chemin et on retentera : jamais de copie, jamais
  de suppression, le pire cas est "rien n'a bouge".
  $AJEAN_HOME et $JEAN_HOME restent tous deux honores, ainsi que
  /etc/default/ajean et /etc/default/jean : un chemin impose a la main
  est un ordre, on ne le migre pas.

- l'auto-MAJ accepte desormais ajean-<os>-<arch> ET jean-<os>-<arch>,
  dans cet ordre. Indispensable dans les deux sens : les binaires deja
  installes ne connaissent que jean-*, et ce binaire-ci doit pouvoir
  s'installer depuis une release anterieure au renommage.

Couvert par des tests, dont le repli quand un handle ouvert bloque le
rename sous Windows.
2026-08-04 13:59:25 +02:00
nathaninline c1d58b19f2 v0.6.15 : un refus d'installation n'est plus definitif
Le drapeau .install_declined (0.6.11) supprimait la question POUR TOUJOURS :
apres un Non, plus aucun moyen d'installer AJEAN, meme en relancant le fichier
telecharge. Un refus vaut « pas maintenant » : la question revient au prochain
lancement, et la fenetre l'annonce.

Verifie au banc d'essai : refus, relance, question reposee, acceptation,
installation + raccourcis + demarrage.
2026-08-04 13:34:28 +02:00
nathaninline 26ce8a9a14 v0.6.14 : creer le dossier bin a la premiere installation
Sur une machine vierge, le premier lancement du fichier telecharge echouait sur
« open C:\ProgramData\jean\bin\jean.exe: The system cannot find the path
specified » : appFirstRun creait le dossier de donnees mais pas son sous-dossier
bin, cree jusqu'ici par le seul `jean install`. AJEAN demarrait alors depuis le
fichier telecharge, sans installation ni raccourcis.

MkdirAll deplace dans installSelf, donc valable quel que soit l'appelant.
Reproduit puis verifie sur banc d'essai Windows (parcours complet depuis un
dossier de donnees inexistant), + test unitaire.
2026-08-04 13:24:42 +02:00
nathaninline 0e94f1e9e2 v0.6.13 : chemins Windows canonises avant comparaison
Correction du defaut trouve au banc d'essai Windows : voir 5728abf. Notes de
release + bump de version.
2026-08-04 12:50:00 +02:00
nathaninline 1d58a7b1b9 v0.6.12 : le .exe telecharge gere le cas « AJEAN deja lance » et les retours en arriere
- si AJEAN tourne, remplacer le binaire ne changeait RIEN a l'ecran (l'ancienne
  version restait en memoire) et rien ne le disait. On demande desormais s'il
  faut fermer et redemarrer pour appliquer la mise a jour, versions affichees.
- si la version installee est PLUS RECENTE que le fichier lance : avertissement,
  aucun remplacement, choix entre demarrer et fermer. Avant, une version plus
  ancienne prenait la place sans un mot.
- version installee illisible (binaire anterieur aux ressources de version) :
  traitee comme ancienne donc remplacable. La traiter comme egale condamnait ces
  installations a ne plus jamais se mettre a jour, en silence.
- raccourcis verifies a chaque demarrage et recrees s'ils manquent, et ranges
  dans le dossier « Programmes » du menu Demarrer (ils etaient a la racine, donc
  introuvables par la recherche). La desinstallation nettoie les deux endroits.
- les instances en cours sont reperees par CHEMIN complet, jamais par nom
  d'image : un taskkill /IM jean.exe emporterait le processus courant.
2026-08-04 12:01:13 +02:00
nathaninline 0d9284e95c v0.6.11 : le .exe telecharge met a jour et demarre, emplacements dans le journal
- Windows : quand AJEAN est deja installe, lancer le fichier telecharge remplace
  le binaire installe (s'il est plus recent) puis demarre l'application, sans
  message. La 0.6.10 annoncait « vous lancez une copie » puis demarrait quand
  meme : une information inactionnable suivie d'un comportement non annonce.
  Le refus d'installation est desormais memorise (.install_declined).
- la version du binaire installe est lue dans les ressources du fichier
  (VS_VERSIONINFO). L'implementation evidente (executer `jean version` et lire
  la sortie) renvoie du VIDE : le binaire est en sous-systeme GUI et n'ecrit pas
  dans un tuyau, donc la mise a jour ne se serait jamais faite, en silence.
  Piege documente dans le code + deux tests.
- UI : les emplacements passent sous le journal du moteur (clic sur la pastille
  d'etat) au lieu d'un bouton isole dans les actions.
2026-08-04 11:39:25 +02:00
nathaninline 1f3961eaa9 v0.6.10 : dossier de travail pour l'agent, lancement Windows explicite, mise à jour lisible, icône noire
- mode agent : les outils write/edit/bash résolvent les chemins relatifs dans
  JEAN_HOME/workspace et le shell y démarre, au lieu du répertoire courant du
  processus (Bureau, ProgramData\jean\bin). Les chemins absolus demandés
  explicitement restent honorés.
- Windows : le double-clic n'installe plus en silence. Boîte de dialogue unique,
  raccourcis menu Démarrer + Bureau, puis relance depuis la copie installée — un
  seul binaire fait foi. Désinstallation : retrait des raccourcis.
- update : contrôle des droits AVANT le téléchargement (l'échec tombait sur le
  fichier temporaire, avec un message brut), message donnant la commande exacte,
  timeout UI porté de 30 s à 10 min.
- jean where + bouton « Où sont mes fichiers ? » : emplacements, et alerte quand
  le binaire lancé n'est pas celui installé.
- icônes : source unique (sys_brand_icon.go) pour la zone de notification, la
  barre de menus macOS et l'icône du .exe, alignée sur le favicon noir. macOS en
  icône template (une icône noire figée disparaît sur une barre sombre).
- CI : le bundle macOS part de icon.png au lieu de convertir le .ico via sips,
  dont l'échec était masqué par « || true » ; notes de release versionnées.
2026-08-04 11:17:43 +02:00
nathaninline 7b0a5dbf75 v0.6.9 : l'IA écrit enfin les fichiers directement
Nouvel outil write : créer ou réécrire un fichier passe par le disque, plus
par le shell. Sous Windows le shell est cmd.exe et son quoting cassait tout
script contenant des guillemets imbriqués (echo, python -c, base64) ; l'IA
bouclait sans jamais y arriver. Signalé par Arnaud Hocquelet.

L'outil bash annonce désormais le vrai shell de la plateforme (cmd.exe sous
Windows) au lieu de dire bash partout, pour que le modèle arrête de générer
la syntaxe d'un autre shell.

Interface : le contenu d'une écriture se remplit ligne à ligne en direct dans
la bulle (diffusé à la ligne et pas au token, pour ne pas saturer le rendu
mobile), et les compteurs +N -N passent sur l'étiquette pour rester visibles
une fois la bulle repliée.
2026-08-03 15:12:18 +02:00
nathaninline 73a772520c v0.6.8 : les modeles peuvent vivre ailleurs que dans le dossier jean
Un .gguf pose sur un disque externe etait invisible dans l'UI : la liste
des modeles ne scannait que JEAN_HOME et un preset pointant ailleurs
affichait « introuvable ». On peut desormais declarer des dossiers de
modeles supplementaires (replies derriere une ligne dans l'editeur de
preset, persistes dans model_dirs.json, ou via JEAN_MODEL_DIRS).

Acces distant : la pastille affiche « non connecte » au lieu de rester
vide quand le serveur n'est lie a aucun compte.
2026-08-03 11:58:00 +02:00
nathaninline acf094f961 v0.6.7 : plus de toast fantome « rien a compacter » a chaque rafraichissement
Au chargement, l'UI rejoue tout le journal de la conversation pour reconstruire
le fil. L'evenement `compact_noop` y est persiste : il etait donc rejoue comme
n'importe quel message et redeclenchait son toast a CHAQUE ouverture de page,
avec une info qui datait parfois de plusieurs heures.

Confusion entre deux natures d'evenements : une notification ponctuelle, qui n'a
de sens qu'en direct, et une trace du fil, qui doit etre rejouee. Le toast est
desormais tu pendant le replay. La marque « contexte compacte », elle, continue
d'etre rejouee — c'est tout son interet.
2026-07-31 01:05:28 +02:00
nathaninline a727394115 v0.6.6 : le compactage automatique du contexte marche vraiment
Le compactage ne se declenchait qu'au DEBUT d'un tour, avec le contexte du
tour precedent. Le tour qui faisait franchir le seuil se terminait donc a
81% sans rien declencher : la jauge restait haute, seul le bouton manuel
apparaissait, et le compactage automatique semblait mort.

- seuil reteste a trois moments au lieu d'un : debut de tour (inchange),
  PENDANT la boucle d'outils, et EN FIN de tour des que le seuil est franchi
- une compaction faite en cours de tour etait perdue : l'appelant
  reconstruisait l'historique en ajoutant les messages du tour a sa copie
  d'AVANT compaction. Le fil complet revenait, la jauge retombait a 43% puis
  explosait a 92% au message suivant. Elle publie desormais sa nouvelle vue
  (StreamEvent.NewHistory), qui REMPLACE l'historique. Meme correction pour
  le filet de secours sur erreur 500 et pour le client terminal.
- la queue protegee reculait jusqu'au message `user` precedent. Pendant une
  longue recherche il n'y en a aucun : la queue avalait toute la sequence
  d'outils, torse vide, compaction sans effet — les pages web qui remplissent
  la fenetre etaient justement celles qui etaient protegees. Elle peut
  maintenant demarrer sur un `assistant`, frontiere tout aussi sure (il part
  avec ses resultats d'outils). Test de regression ajoute.
- une compaction sans effet ne disait plus rien : toast explicite + une ligne
  [compact] par decision dans le journal (ctx, seuil, avant/apres, changé)

UI : la mini-banniere au-dessus de la saisie doublonnait les trois points
animes de l'IA. L'indicateur existant est desormais etiquete « compactage du
contexte… » en accent, et une marque discrete reste DANS le fil a l'endroit
de la coupure — elle survit au rafraichissement, contrairement au toast.
2026-07-30 22:17:40 +02:00