Commit Graph
100 Commits
Author SHA1 Message Date
nathaninline 3dba323aab v0.7.8 : l'acces internet sans rien installer
Moteur web integre en pur Go (http + readability + html-to-markdown),
selectionnable par WEB_ENGINE. Crawl4AI reste disponible pour le rendu
JavaScript et reste le defaut des installations qui l'ont deja configure.

Le schema de web_open n'annonce plus actions/wait_for/dismiss_popups avec
le moteur integre, et une page riche en HTML mais sans texte est diagnostiquee
comme rendue en JavaScript, pour que le modele change de source au lieu de
rouvrir la meme URL en boucle.
2026-08-05 11:48:45 +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 aa92d2ab49 Notes de release 0.7.6 : recapituler toute la ligne 0.7
Les 0.7.0 a 0.7.5 etant retirees, la 0.7.6 devient la seule porte de
sortie depuis la 0.6.15. Ses notes doivent donc decrire le renommage
complet et pas seulement le dernier correctif : commande jean conservee,
migration automatique du dossier, redemarrage par le bouton, unites
systemd inchangees, disparition du dossier SKILLS.
2026-08-04 17:42:00 +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 75929e7b60 Migration automatique de l'agencement systeme (Unix)
Sans ca, le renommage n'atteignait pas les machines Linux installees. Le
dossier de donnees y est epingle par /etc/default/jean, que notre propre
installeur ecrit ; le code traitant un chemin explicite comme un ordre, il
ne migrait jamais. Constate en deployant 0.7.0 sur un vrai serveur : les
chemins sont restes en /etc/jean et il a fallu un script separe.

La regle qui debloque : distinguer NOTRE artefact du CHOIX de l'utilisateur.
Si le chemin epingle vaut exactement l'ancien emplacement par defaut, c'est
notre installeur qui l'a ecrit et on migre. Toute autre valeur est une
decision de l'utilisateur et reste intacte.

Le dossier, /etc/default et l'unite systemd bougent ENSEMBLE : les separer
donnerait le pire cas, des donnees deplacees et un service qui ne redemarre
plus. Les chemins sont reecrits par parcours du dossier plutot que d'apres
une liste devinee — l'experience montre qu'ils se cachent dans EXTRA_ARGS,
les copies .bak et jusque dans des notes de MEMORY. backends/ et les .gguf
sont sautes.

Deux moments de declenchement, tous deux root et deliberes : `install`, et
juste apres une mise a jour reussie. Jamais au demarrage ordinaire — un
service qui reecrit des unites systemd a chaque boot finirait par en casser
une, et sur un parc entier ca veut dire des machines qui ne redemarrent plus.

La variante post-mise-a-jour n'arrete AUCUN service : on s'execute dans
jean-link, l'arreter reviendrait a se tuer au milieu de la migration, dossier
deplace et chemins pas encore reecrits. Sans danger, un rename de dossier
sous Linux tolere les fichiers ouverts et un process garde son repertoire de
travail par son inode.

Sauvegarde prealable bloquante, et retour a l'etat initial si une etape
echoue apres le deplacement. Couvert par 6 tests sur un faux /etc, dont le
respect d'un chemin impose et la garantie qu'aucun service n'est touche par
la variante post-MAJ.
2026-08-04 16:23:20 +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 a58103ff7e Migration : reecrire aussi les chemins sous leur forme JSON echappee
Trouve en rejouant la migration dans un bac a sable isole. Les fichiers
JSON du dossier de donnees (model_dirs.json, mcp.json, webprefs.json) sont
ecrits par json.Marshal : sous Windows chaque antislash y est DOUBLE. La
reecriture ne cherchait que la forme native et la forme a slashs, elle
laissait donc ces fichiers pointer vers l'ancien dossier.

Pire, la fonction d'echappement etait ecrite avec des litteraux bruts et
remplacait en fait un antislash par lui-meme : elle ne doublait rien. Le
remplacement natif matchait alors la forme JSON et produisait un fichier
invalide (« invalid character 'U' in string escape code »), c'est-a-dire la
liste des dossiers de modeles perdue. Un bug pire que celui qu'on corrigeait.

jsonEscapePath utilise desormais des litteraux entre guillemets, avec un
commentaire explicite sur le piege ("\\" est UN antislash, "\\\\" en fait
deux). Test dedie qui verifie que le chemin est bien reecrit ET que le JSON
reste analysable apres coup.

Verifie en bac a sable sur les trois ecritures simultanement (native,
slashs, JSON echappe) : les trois sont reecrites, le JSON se reparse et
pointe sur le nouveau dossier.
2026-08-04 14:33:03 +02:00
nathaninline 8a2b5c6687 Migration : reecrire les chemins absolus pointant vers l'ancien dossier
Bug trouve en testant la migration sur une vraie machine (5,4 Go, 51 351
fichiers). Le rename du dossier reussissait, mais config.env contenait

  BIN=C:\ProgramData\jean\backends\llama.cpp\build\bin\Release\llama-server.exe

soit un chemin ABSOLU vers le dossier qu'on venait de renommer. Resultat :
le dossier migre intact, et llama-server ne demarre plus. Ca touche tous
ceux qui ont fait un `llamacpp install`, donc le cas nominal, pas un cas
limite. Les presets de configs/ portent le meme BIN et etaient touches
pareil (deux presets concernes sur la machine de test).

Apres un rename reussi, on reecrit donc les references a l'ancien chemin
dans les fichiers de config qu'on ecrit nous-memes : config.env,
model_dirs.json, mcp.json, webprefs.json et les presets de configs/. Les
deux ecritures de separateur sont couvertes, Windows acceptant \ et / dans
une meme valeur. Restreint a ces fichiers texte : on ne reecrit pas a
l'aveugle les 51 000 fichiers d'un dossier de donnees.

Les fichiers d'etat du service sont repris au passage (jean.pid/jean.log ->
ajean.pid/ajean.log), meme raison que pour le worker de lien : le PID dit
si le service tourne, l'ignorer ferait demarrer un second service.

Non traite volontairement : l'arborescence de build llama.cpp
(CMakeCache.txt et consorts) contient aussi des chemins absolus. Elle est
regenerable par `ajean llamacpp update` et la reecrire en masse serait plus
risque qu'utile.

Verifie de bout en bout sur la machine de test : service demarre,
llama-server chargé depuis le nouveau chemin, /health ok, completion reelle
ok. Deux tests ajoutes reproduisant le cas.
2026-08-04 14:24:53 +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 3720b90173 Renommage AJEAN (2/3) : services, binaire et releases
Suite du renommage. Principe directeur : le code s'adapte a ce qui est
DEJA installe sur la machine, plutot que d'exiger une migration
privilegiee qui pourrait echouer et laisser un serveur sans service.

Services (sys_unitname.go). Une mise a jour remplace le binaire, pas les
unites systemd : un serveur deja installe tourne encore sous jean.service
et jean-link.service. serviceName() et linkServiceName() resolvent donc
le nom a l'usage — l'unite qui existe reellement — au lieu de supposer
"ajean*". Sans ca, le premier systemctl restart apres MAJ echouerait, et
sur un serveur distant ca veut dire l'acces coupe sans terminal pour
reparer. Meme logique pour le label launchd, ou le prefixe com.jean. est
conserve tant que c'est lui qui est charge.

Le fichier PID du worker de lien est repris au passage (jean-link.pid ->
ajean-link.pid) : c'est lui qui dit si un worker tourne, et sans reprise
la premiere version renommee en aurait demarre un second, donnant deux
tunnels concurrents vers le relais.

Binaire. installedExePath vise desormais ajean(.exe), et l'installation
pose un alias "jean" a cote — lien symbolique sous Unix, copie sous
Windows ou les liens demandent des droits qu'on n'a pas toujours. La
commande d'hier reste tapable : on ne controle ni les alias shell, ni les
cron, ni les scripts de deploiement, ni les tutos deja ecrits.

/etc/default/ajean est ecrit avec AJEAN_HOME ET JEAN_HOME, et l'ancien
/etc/default/jean est laisse en place plutot que supprime : des scripts
d'utilisateurs le sourcent.

Releases. Les workflows produisent ajean-<os>-<arch> puis en copient un
jeu jean-<os>-<arch> identique, une fois les binaires macOS recuperes.
Les deux jeux sont dans SHA256SUMS. Ces copies sont indispensables : le
parc installe ne sait chercher que jean-*, il ne pourrait donc meme pas
atteindre la version qui apprend a lire ajean-*. A retirer quand le parc
aura bascule. Le bundle devient AJEAN.app, avec le zip publie sous les
deux noms pour ne pas casser les liens de telechargement deja diffuses.
La detection du mode application se basant sur /Contents/MacOS et non sur
le nom du bundle, elle n'est pas affectee.
2026-08-04 14:07:44 +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 5728abf93e Windows : comparer les chemins canonises, pas les chaines brutes
Windows expose le meme fichier sous plusieurs ecritures (forme courte 8.3
« ADMINI~1 » contre « Administrateur », casse, liens). Les deux comparaisons de
chemins du premier lancement le supposaient identique des deux cotes :

- runningPIDs ratait l'instance en cours -> on remplacait le binaire en croyant
  l'application arretee, elle continuait de tourner en ancienne version sans que
  rien ne l'indique. C'est le bug corrige en 0.6.12, revenu par une autre porte.
- appFirstRun : l'application installee se serait prise pour une copie
  telechargee et se serait relancee, en BOUCLE INFINIE.

Constate sur banc d'essai Windows (JEAN_HOME sous un chemin en forme courte).
2026-08-04 12:37:59 +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 f541d997d2 Notes de release : suppression des tirets cadratins 2026-08-04 11:27:30 +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 6e7fe7d4a6 README : nouvelle accroche 2026-08-03 17:48:10 +02:00
nathaninline d50a01b404 README : formulations de l'introduction 2026-08-03 17:35:06 +02:00
nathaninline e0297ddea6 README : suppression des tirets cadratins dans le texte et de la phrase de trop sur llama.cpp 2026-08-03 17:32:37 +02:00
nathaninline 658de68d78 README : vouvoiement et repositionnement — AJEAN est une application d'IA locale complete, llama.cpp n'est que le moteur 2026-08-03 17:30:06 +02:00
nathaninline 0e6763920b README : remise à jour et simplification, nouvelle capture d'écran
Le README avait pris du retard sur les versions 0.5 et 0.6. Ajouts : serveurs
MCP (format mcp.json compatible Claude Desktop, transports stdio et HTTP),
compactage automatique du contexte, commandes app et oai, téléchargement de
modèles depuis l'UI.

Corrections : le mode agent donne désormais terminal, écriture/édition de
fichiers, mémoire, web et MCP — pas seulement « shell + mémoire ». La section
Windows ne parle plus de « jean tools ». Tableaux de config et de variables
d'environnement complétés (COMPACT, CRAWL4AI_KEY, JEAN_MODEL_DIRS, HF_TOKEN,
JEAN_DL_CONNS).

Structure resserrée : commandes regroupées par usage plutôt que par ordre
historique, sections longues raccourcies sans perte d'information.
2026-08-03 17:26:49 +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 3fd04a8304 web : le toast 'rien a compacter' ne se rejoue plus a chaque rafraichissement 2026-07-31 00:41:17 +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
nathaninline ecb05fcb86 gofmt : alignement des champs du client HTTP de telechargement 2026-07-30 15:16:55 +02:00
nathaninline 065264a055 v0.6.5 : telechargement de modeles bien plus rapide, barre de progression et annulation
- Telechargement d'un .gguf en 8 connexions paralleles (requetes Range,
  ecriture en place avec WriteAt) au lieu d'un seul flux TCP : sur le CDN
  Hugging Face le gain est typiquement de 3 a 6x. Repli automatique sur le
  flux unique si la source ne gere pas les ranges.
- Client HTTP dedie (pool de connexions reutilisees, HTTP/2 desactive) et
  reprise par tranche en cas de coupure. Reglable via JEAN_DL_CONNS.
- Barre de progression integree dans la modale de preset, avec vitesse et
  temps restant.
- Bouton d'annulation : coupe vraiment le telechargement et supprime le
  fichier partiel. Fermer la modale ne l'interrompt plus, l'UI se rebranche
  dessus a la reouverture.
- Les .gguf.part orphelins (crash, restart du service) sont nettoyes au
  demarrage.
- La liste de selection du modele s'ouvre alignee a gauche et sur toute la
  largeur de la ligne.
2026-07-30 15:06:01 +02:00
nathaninline 1360eb1943 v0.6.4 : serveurs MCP connectes en parallele et prechauffes, vitesse de generation de retour, retouches du menu
MCP : les serveurs actifs se connectent en parallele au lieu de la file
indienne (quatre serveurs npx n'additionnent plus leurs demarrages) et sont
prechauffes au lancement du service, donc le premier message ne paie plus le
handshake. Une session est publiee dans le pool avant d'aboutir : deux
appelants simultanes partagent la meme tentative au lieu de lancer deux
process.

Interface : la vitesse de generation (prefill/decode) reapparait sous chaque
reponse, en fondu, avec un interrupteur pour la masquer ; infobulles " ? "
qui n'etaient plus rognees ; espace superflu en haut des cartes du mode
agent ; pastilles d'etat redessinees et plaquees a droite ; moteurs renommes
en llama.cpp precompile / compile / personnalise ; badge conseille lisible en
sombre ; section Service fondue dans Moteur ; plus qu'un enregistrement
automatique pour l'acces internet.

Documentation : le README dit desormais que Crawl4AI est un serveur a
heberger soi-meme, avec la commande Docker.
2026-07-30 10:21:09 +02:00
nathaninline 92c350bdb8 v0.6.3 : texte non coupe autour des outils, garde-fous d'outils retires, retours UI
- Flux : le reliquat retenu par la garde « </think> » est vidé dès qu'un appel
  d'outil arrive, au lieu de la fin du flux. Sans ça il partait APRÈS
  l'événement d'outil et la fin de phrase — souvent coupée en plein mot —
  atterrissait dans une bulle séparée sous l'outil.
- Le plafond d'appels d'outils par tour (TOOL_LIMIT) et l'anti-boucle « appel
  identique répété » sont SUPPRIMÉS : ils coupaient des tours légitimes (une
  recherche enchaîne facilement des dizaines d'appels). Le bouton stop reste
  le seul frein. Endpoint /api/agent/tool-limit et son interrupteur retirés.
- Prompt système : « You are Jean » (majuscule) — le modèle recopiait la casse
  et se présentait en minuscule.
- UI : titres du menu tous en monospace capitales via une seule règle (la casse
  vient du CSS, plus du HTML).
- UI : le message envoyé s'affiche tout de suite en gris (« envoi… ») et
  s'éclaircit quand le serveur le confirme ; il ne disparaît plus pendant
  l'aller-retour, et il est retiré si l'envoi échoue.
- UI : voile de chargement du fil (« chargement de la conversation… » /
  « connexion au serveur… ») — un chat vide ne se confond plus avec une
  connexion lente.
- UI mobile : hauteur de coque 100dvh hors PWA (100vh en PWA), et plus aucun
  défilement du document. Le mode PWA est détecté par navigator.standalone :
  le média display-mode ne matche pas, faute de manifeste.
2026-07-29 18:49:53 +02:00
nathaninline a3a9c36367 v0.6.2 : carte de saisie correctement posee en bas sur iPhone (PWA) + listes deroulantes lisibles en sombre
Coque en 100vh au lieu de 100dvh : mesure faite sur iPhone en PWA, la vue web
couvre 956 pt mais la fenetre de mise en page n'en fait que 894, calee en haut.
100dvh (comme height:100%) vaut 894 -> il restait une bande morte de 62 pt sous
la carte de saisie, qui se recalait au premier defilement. 100vh se refere au
grand viewport et vaut bien 956.

La marge de zone sure passe du <body> a la carte elle-meme : geometrie
identique, mais l'arrondi bas reste detache du fond.

Listes deroulantes : la liste ouverte d'un <select> n'herite pas du fond de son
select ; nos selects transparents a texte clair donnaient du texte clair sur
fond blanc en theme sombre (signale sur Cache KV, en fait toutes les listes).
Les <option>/<optgroup> portent desormais les couleurs du theme.
2026-07-29 00:04:31 +02:00
nathaninline a7e3f0782c v0.6.1 : notifications de nouveau visibles + colonne de lecture alignee sur la saisie
- Les notifications du bas d'ecran (#toast) n'avaient pas de z-index. Depuis
  que la mise en page en colonne rend le composer absolu (z-index 4), elles
  etaient peintes DESSOUS et n'apparaissaient plus. Elles passent au-dessus du
  composer, sous les modales.
- La zone de chat reserve une gouttiere de barre de defilement de chaque cote
  (scrollbar-gutter: stable both-edges) ; le composer, lui, n'est pas defilant.
  Les messages etaient donc en retrait d'une gouttiere (~15 px) par rapport a
  la zone de saisie, ecart bien visible quand la barre laterale est escamotee.
  La gouttiere reelle est mesuree en JS et reportee sur le composer.
2026-07-28 15:48:48 +02:00
nathaninline 8fd71d6013 v0.6.0 : refonte de l'interface web (theme unique noir et blanc, menu lateral repense)
Interface
- Un seul theme, en deux variantes claire et sombre. Les themes Classique,
  Doux, ChatGPT et AJEAN sont retires, ainsi que le reglage de police et ses
  quatre variantes (plus aucun telechargement Google Fonts).
- La disposition en colonne centree devient celle de l'application : reponses
  sans bulle, question en pastille a droite, composer en pilule.
- Menu lateral refondu sur un gabarit unique repris des listes de la modale de
  preset : cartes, lignes de 34 px, intitule a gauche et controle a droite.
  Menu replie = 462 px, plus de defilement au chargement.
- GPU et RAM fusionnes en une section Machine, avec un vrai bloc de
  statistique (nom, valeur alignee, jauge, detail).
- Palette sombre plus contrastee : gris de texte a 7,6:1 (contre 5,6),
  bordures et surfaces enfin distinctes du fond.
- Le logo affiche toujours AJEAN (le A n'apparaissait qu'en mode agent) et
  passe en couleur d'accent quand l'agent est actif.
- Les garde-fous du serveur ([stop: ...]) s'affichent en encart discret.

Corrections
- Fond d'accent + texte blanc en dur : illisible en mode sombre (bouton
  enregistrer de l'editeur de preset, boutons accoles, bulle utilisateur).
- Pave des interrupteurs invisible sur piste claire, piste trop proche du fond.
- Valeurs cle/valeur inversees (« Go 24 / 18,2 ») : direction:rtl sans
  unicode-bidi:plaintext.
- Jauge de VRAM invisible (fond de la jauge = couleur de sa carte).
- Badges d'etat flottants dans les en-tetes (deux margin-left:auto).
- Ombres et voiles calibres pour un fond sombre, trop lourds sur du blanc.

Preferences
- /api/prefs n'accepte plus que theme=light|dark et les quatre drapeaux
  d'affichage ; les cles obsoletes (police, anciens themes) sont purgees a la
  premiere ecriture, et le client normalise un theme herite.
2026-07-28 15:31:11 +02:00
nathaninline 15bb9358bc v0.5.12 : la cle Crawl4AI quitte config.env pour un fichier dedie (0600)
Une cle en clair dans config.env finit dans les copier-coller de depannage.
Elle vit desormais dans $JEAN_HOME/.crawl4ai_key en 0600, comme la cle de
completion (.api_key) ; les installations qui l'avaient dans config.env sont
migrees a la premiere lecture, et l'ecriture efface toute trace residuelle.

Approche proposee par @feanor91 dans la PR #15 — merci a lui.
2026-07-28 11:43:40 +02:00
nathaninline 8956b1ed76 ci : gofmt sur web_prefs.go (alignement de la liste blanche des preferences) 2026-07-28 11:24:33 +02:00
nathaninline dbd4a6a570 v0.5.11 : themes clair/sombre par famille + police reglable + affichage a la carte + cle API Crawl4AI
- Apparence repensee : la liste ne montre plus que les FAMILLES de theme
  (Classique, AJEAN, Doux, ChatGPT) avec un interrupteur clair/sombre, au lieu
  d'une entree par variante. Nouveau theme « ChatGPT sombre » (fond quasi noir).
- Le theme par defaut redevient « clair ».
- Nouveau reglage « police », independant du theme : du theme / Mono / Systeme /
  Lexend / Serif (Lexend n'est telechargee que si elle est choisie).
- Le mode « complet / simple » laisse place a quatre interrupteurs : masquer le
  raisonnement, masquer les appels d'outils, garder les bulles repliees, barre
  laterale escamotable (tiroir meme sur ordinateur). L'ancien reglage est repris.
- Cle API du serveur Crawl4AI reglable depuis l'UI (et `jean internet key`) :
  envoyee en Authorization: Bearer sur toutes les requetes, jamais relue par
  l'API (indice sur 4 caracteres), preservee au changement de preset.
- Mise en page : colonne de lecture bornee a 900 px en mode escamotable, marges
  d'origine sinon ; tiroir de meme largeur que la barre fixe ; bouton ☰ qui ne
  recouvre plus le fil ; logo et numero de version recales.
2026-07-28 11:21:44 +02:00
nathaninline e2475c6688 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).
2026-07-28 10:20:19 +02:00
nathaninline 6195d77759 v0.5.9 : nouveau theme AJEAN (bleu pixel, clair) par defaut + logo AJEAN dessine en pixels
- theme "AJEAN" : fond clair quadrille, bleu #1f6feb, aucun arrondi, bordures de
  2 px, ombres en blocs decales, boutons en capitales qui s'enfoncent au survol.
  Meme charte que la landing ajean.app.
- il devient le theme par defaut (registre, initTheme, script anti-flash du head).
- correctif : "ajean" manquait dans la liste blanche serveur (web_prefs.go), donc
  le choix etait rejete et le thème "sautait" a chaque rafraichissement.
- logo : le mot AJEAN est dessine en pixels (SVG, grille 4x5 par lettre, trait
  d'un module, j repris de la tuile du favicon) au lieu d'etre ecrit en texte ;
  le "a" du mode agent garde son animation d'apparition.
2026-07-28 07:58:06 +02:00
nathaninline 1b07054943 v0.5.8 : correctif reponse affichee en double (compaction de fin de tour) 2026-07-27 13:01:55 +02:00
nathaninline 36070387d0 correctif : reponse affichee en double quand la compaction de fin de tour fusionne un bloc que le client suivait en direct 2026-07-27 12:47:15 +02:00
nathaninline d22e8c8622 v0.5.7 : nouveau theme ChatGPT (noir et blanc, mise en page epuree) + composer en carte avec jauge de contexte integree 2026-07-27 12:22:56 +02:00
nathaninline cdcf89b068 ci : gofmt sur web_server.go (alignement des routes /api) 2026-07-27 10:44:35 +02:00
nathaninline 83a3a79abe v0.5.6 : backends custom depuis un depot Git + editeur de preset repense (champs facon Reglages iOS) + incompatibilite modele/moteur signalee 2026-07-27 10:35:04 +02:00
nathaninline 1af9262e97 v0.5.5 : conversation unique sur Mac/Windows (tunnel dans le process de l'app) 2026-07-25 14:00:19 +02:00
nathaninline 1118a15273 app de bureau : UN SEUL process proprietaire de la conversation
La conversation est un objet en memoire persiste dans conversation.json :
deux process qui la servent = deux fils divergents qui s'ecrasent. Sous
Linux le service jean-link sert deja les DEUX surfaces (UI locale :8090 +
tunnel) pour cette raison ; le worker detache ajoute en v0.5.4 rompait ce
principe sur Mac/Windows -> conversations differentes entre le local et
app.ajean.link.

L'app fait desormais tourner le tunnel dans son propre process, avec le
MEME mux que l'UI locale, et supprime au demarrage tout worker detache
rescape. Corollaire assume : l'acces distant vit tant que l'app est ouverte
(sur un portable qui s'endort, c'etait deja le cas en pratique).
2026-07-25 13:48:33 +02:00
nathaninline f8e856ed7c acces distant : remplacer un worker de tunnel issu d'une autre copie de l'app
Le worker est detache expres pour survivre a la fermeture de Jean.app : un
worker lance par une ancienne copie (translocatee ou version precedente)
continue donc de servir l'UI distante avec du code perime — l'alerte App
Translocation s'affichait sur app.ajean.link alors que l'app locale tournait
bien depuis /Applications.

Le fichier PID porte desormais le binaire d'origine en 2e ligne ; au
demarrage, un worker dont le binaire differe du notre est redemarre.
2026-07-25 13:29:33 +02:00
nathaninline 43ea4ad6c7 UI : plus de requetes suspendues indefiniment (saturation de connexions)
Chaque onglet Jean ouvert monopolise une connexion SSE permanente ; au-dela
du plafond navigateur (~6 par domaine) toute nouvelle requete part en file
d'attente sans jamais aboutir NI echouer : UI figee sur << chargement... >>
alors que le serveur repond en quelques ms (verifie en curl).

- un onglet cache relache son flux SSE et le reprend au retour (le replay
  depuis lastSeq rattrape ce qui a ete manque)
- timeout de 30 s sur les appels /api/* ordinaires, avec un message explicite
  au lieu d'une attente infinie
2026-07-25 12:53:29 +02:00
nathaninline e7d837d17e macOS : modele resolu depuis JEAN_HOME + alerte App Translocation
- config.env stocke MODEL sous forme de nom de fichier : sous systemd/launchd
  le WorkingDirectory vaut JEAN_HOME, mais une app de bureau demarre avec
  cwd=/ et llama-server ne trouvait pas le .gguf. cmdServe resout desormais
  MODEL et BIN relatifs contre JEAN_HOME, et le service en mode utilisateur
  fixe cmd.Dir (macOS + Windows).
- erreur explicite << modele introuvable : <chemin> >> au lieu d'un echec muet
- bandeau d'alerte quand l'app tourne depuis une copie AppTranslocation
  (app non signee ouverte depuis Telechargements) : chemin different a chaque
  lancement, instances concurrentes, maj du moteur impossible
2026-07-25 12:39:04 +02:00
nathaninline 9fe955d5ae backends precompiles : extraire les liens symboliques des archives
Les archives llama.cpp macOS/Linux livrent les bibliotheques sous leur nom
versionne (libllama-common.0.0.10107.dylib) PLUS un lien portant le nom
recherche par l'editeur de liens (libllama-common.0.dylib). L'extracteur
tar ignorait les entrees de type lien : backend installe mais llama-server
mort-ne sur << dyld: Library not loaded >>.

- extractArchive cree les liens (copie de repli quand os.Symlink echoue)
- marqueur de format dans VERSION : une install faite par l'ancien
  extracteur est refaite au lieu d'etre declaree << deja a jour >>
- test de non-regression + go test ajoute au job macOS de la CI
2026-07-25 12:29:47 +02:00
nathaninline 43da4b9197 macOS : DYLD_LIBRARY_PATH pour llama-server + journal du moteur dans l'UI
- dyld IGNORE LD_LIBRARY_PATH : sur macOS les .dylib livrees a cote de
  llama-server n'etaient pas trouvees, le moteur mourait sans un mot
- nouvelle route GET /api/service/log (journalctl sous Linux, fichier de
  log ailleurs) + panneau repliable ouvert en cliquant la pastille d'etat :
  on voit enfin POURQUOI un modele ne charge pas
2026-07-25 12:21:02 +02:00
nathaninline 075a05ebaa acces distant : le tunnel jean-link tourne aussi hors systemd (macOS/Windows)
linkServiceCtl/linkServiceActive etaient Linux-only : sur un Mac le token
etait bien enregistre mais rien ne composait jamais le tunnel, d'ou le
message << service arrete >> permanent. Hors Linux on lance desormais
'jean link serve' en processus detache suivi par un fichier PID
(spawnDetached/pidAlive/killTree, nouvelles primitives par plateforme).

- le mode app relance le tunnel au demarrage si une cle est enregistree
- nouvelle route POST /api/link/start + bouton << demarrer le tunnel >>
  dans le panneau, visible quand le lien est configure mais arrete
2026-07-25 12:02:31 +02:00
nathaninline 9787923879 macOS : service en mode utilisateur quand aucun LaunchDaemon n'est installe
Jean.app tourne sans root : launchctl load echouait sur un plist absent et
l'UI restait bloquee sur << service arrete >>. On bascule alors sur le meme
mecanisme que Windows (jean serve detache + fichier PID), avec setsid pour
survivre a la fermeture de l'app et un kill par groupe pour emporter
llama-server. Ajoute aussi l'action 'status', qui manquait cote darwin.
2026-07-25 11:37:42 +02:00
nathaninline a1b0cc0c58 macOS : JEAN_HOME utilisateur, RAM detectee, PATH Homebrew depuis le Finder
- /etc/jean n'est pas ecrivable par une app lancee depuis le Finder ->
  repli sur ~/Library/Application Support/jean (sauf sudo jean install)
- /api/ram lisait /proc/meminfo uniquement : ajout sysctl+vm_stat (macOS)
  et GlobalMemoryStatusEx (Windows, qui ne remontait rien non plus)
- PATH herite du Finder complete avec Homebrew/MacPorts : sans ca cmake,
  git et brew sont invisibles pour la compilation du backend
2026-07-25 11:30:02 +02:00
nathaninline 89cbb50fcf ci : workflow mac-build a la demande (Jean.app en artifact, sans release) 2026-07-25 11:22:31 +02:00
nathaninline 236bf4e978 ci : cibles macOS sur un runner Apple (CGO) au lieu du cross-compile 2026-07-25 10:27:18 +02:00
nathaninline ac171e5461 v0.5.4 : app macOS Jean.app (clic = UI web + icone barre de menus)
- Jean.app publie par la CI (zip par archi) : ouverture depuis le Finder ->
  mode application, comme le double-clic sur jean.exe sous Windows
- icone dans la barre de menus macOS (systray/Cocoa) avec Ouvrir/Quitter,
  bundle marque LSUIElement (pas d'icone Dock)
- builds darwin deplacees sur un runner macOS (CGO requis pour Cocoa)
- signature ad-hoc du bundle + icone .icns
2026-07-25 10:23:33 +02:00
nathaninline 2f1f40c604 v0.5.3 : détection du preset actif robuste + retouches UI
- Presets : la détection du preset actif compare désormais l'ENSEMBLE des
  KEY=VALUE effectifs (ordre, commentaires, lignes vides et clés appareil
  ignorés) au lieu d'un hash ligne à ligne. Fini le preset qui n'apparaît plus
  en surbrillance après un reformatage de config.env (toggle mémoire/internet…).
  Couvert par un test unitaire.
- UI : toggles « Paramètres » du mode agent dans des cartes bordées ; champs de
  la modale MCP correctement espacés ; section MOTEUR sans contours colorés ;
  liens « mettre à jour » / « vérifier la version » sans soulignement.
2026-07-24 17:29:50 +02:00
nathaninline 142dd87299 v0.5.2 : robustesse appels d'outils + nettoyage UI
- Chat : valide le JSON des arguments d'outil avant de les stocker dans
  l'historique. Un modèle très quantifié pouvait émettre des arguments
  tronqués/non-JSON (non vides) qui, persistés, faisaient échouer le template
  de chat de llama.cpp à chaque requête → 500 en boucle jusqu'au reset.
  json.Valid remplace le simple test != "" (llm_client.go).
- UI : section « Accès OpenAI » remise au propre (adresses locale/publique
  groupées, clé API), sans émojis ; « Accès distant » sans émojis. Classes
  .io-input/.io-cap partagées.
2026-07-24 17:06:13 +02:00
nathaninline d8b08dbb89 v0.5.1 : accès distant ajean.link depuis l'UI + app Windows sans console
- Panneau « Accès distant » dans l'UI web : abonnement + liaison ajean.link
  en un clic (popup connect.html → clé remise à l'agent local), sans terminal.
  Endpoints locaux /api/link/status|connect|disconnect|paircode (web_link_api.go).
- Accès OpenAI public : refuse d'être activé sans accès distant, avec message.
- Windows : binaire compilé en sous-système GUI (-H=windowsgui) → plus aucune
  fenêtre de console au double-clic ; rattachement à la console parente en CLI
  (sys_console_windows.go). Suppression du hack relaunchDetachedApp.
- Windows : masquage (CREATE_NO_WINDOW) de TOUS les sous-process — git/vswhere
  du panneau MOTEUR (flash à chaque refresh), llama-server, MCP stdio, winget…
- Vouvoiement du nouveau parcours.
2026-07-24 16:39:09 +02:00
nathaninline 8e57685b19 v0.5.0 : intégration MCP (Model Context Protocol)
Jean peut désormais se connecter à des serveurs MCP tiers pour enrichir la
palette d'outils de l'IA (accès fichiers, bases de données, APIs métier…).

- Transports stdio (process local npx/uvx/binaire) et http (Streamable HTTP
  distant, en-têtes d'auth possibles), via le SDK officiel go-sdk.
- Outils namespacés mcp__<serveur>__<outil>, exposés seulement en mode agent
  (même niveau de confiance que le shell : exécution de code sur l'hôte).
- Sessions persistantes (connexion paresseuse + cachée, reconnexion auto).
- Gestion complète dans l'UI web : ajout/édition de serveurs, activation par
  serveur ET par outil (pour maîtriser le contexte), état de connexion en direct.
- Config dans mcp.json (format Claude Desktop mcpServers, copiable).
2026-07-24 12:49:56 +02:00
nathaninline e8f566ebc0 v0.4.16 : historique de chat - fini la perte du debut
Le journal d'affichage stockait un evenement par token (plafond 5000) -> il se
remplissait en quelques reponses et on ne pouvait plus remonter jusqu'au debut.
Desormais il est coalesce en fin de tour (un tour = une poignee d'evenements au
lieu d'un par token), plafond monte a 20000. Des centaines de tours tiennent
maintenant dans l'historique.
2026-07-23 20:03:46 +02:00
nathaninline 7cfc548474 Historique chat : coalescer le journal en fin de tour (fini la perte du debut)
Le journal d'affichage stockait un evenement par TOKEN et etait plafonne a 5000
-> il se remplissait en quelques reponses et perdait le debut de la conversation
a l'ecran (impossible de remonter jusqu'au deput). Fix : compactLogLocked()
coalesce les suites content/reasoning en un seul evenement chacun a la fin de
chaque tour (le replay le faisait deja, pas le stockage), en preservant toks/ts0
pour le compteur tok/s. Plafond monte a 20000 pour absorber un gros tour en cours
avant sa coalescence. Un tour terminé pese desormais une poignee d'evenements au
lieu d'un par token -> des centaines de tours tiennent dans le journal.
2026-07-23 20:01:54 +02:00
nathaninline ac8095024f v0.4.15 : compaction du contexte revue de fond en comble
- Progression visible : banniere "compactage en cours" pendant le resume (au lieu
  d'une UI figee), jauge de contexte qui chute immediatement.
- Bouton "compacter" fonctionnel : declenche une vraie compaction manuelle
  (visible des 50%), au lieu d'un toast inutile.
- Compaction efficace : budget de queue base sur la conversation (pas la fenetre)
  -> corrige le "rien a compacter" ; resume borne et dense (max_tokens, thinking
  desactive, plafond dur) ; reduction garantie >= 20%.
- Prompt resumeur universel : en anglais, resume dans la LANGUE de la conversation,
  avec objectif explicite (continuer sans perdre d'info importante).
- Erreurs moteur claires : "connection refused"/timeout/EOF traduits en message
  comprehensible au lieu du brut "dial tcp ...".
2026-07-23 17:56:38 +02:00
nathaninline 4223606780 Compaction : prompt resumeur en anglais + resume dans la langue de la conversation
- Prompt resumeur, marqueur injecte, labels de transcription et marqueur de
  troncature passes du francais code en dur a l'anglais (coherent avec le system
  prompt principal, app universelle) ; le resume est produit dans la LANGUE de la
  conversation.
- Ajout de l'objectif explicite du resume : continuer la conversation sans perdre
  d'info utile/importante pour comprendre le contexte.
2026-07-23 17:46:55 +02:00
nathaninline 2c1c9bc3f0 CI: gofmt sur web_server.go (alignement des routes casse la CI) 2026-07-23 17:32:45 +02:00
nathaninline ea5d0eed4f Compaction : budget de queue base sur la conversation, pas la fenetre (fix "rien a compacter")
Bug : tailBudget = 0.25 x fenetre. Une conversation de 25k tokens dans une
fenetre de 64k gardait 16k en queue -> torse minuscule (~4k) -> reduction < 20%
-> refusee -> "rien a compacter" a 68%. Corrige : tailBudget = 0.25 x taille
estimee de la conversation -> on garde ~25% des tours recents et on compacte les
~75% du debut, quelle que soit la fenetre.

Aussi : la jauge post-compaction ajoute le surcout fixe non compactable (prompt
systeme injecte + schemas d'outils = contexte reel - estimation messages), pour
afficher une valeur realiste au lieu de chuter trop bas puis resauter.
2026-07-23 17:28:12 +02:00
nathaninline dcbfcb36f9 Compaction plus efficace : resume borne, reduction garantie, jauge immediate
- Resume borne et dense : max_tokens 700, consigne 250 mots max, plafond dur a
  1500 caracteres, et surtout thinking DESACTIVE pour l'appel de resume
  (chat_template_kwargs enable_thinking:false) -> plus rapide, plus dense, plus
  de budget gaspille en <think> par un modele hybride.
- Garantie de reduction : la compaction n'est acceptee que si elle enleve >=20%
  du contexte estime, sinon refusee -> fini le "compactage a chaque message sans
  reduire". Queue plus agressive (tailFrac 0.35 -> 0.25) : le contexte retombe
  plus bas et met plus longtemps a re-declencher.
- Jauge de contexte : chute immediatement apres compaction (delta ctx_used emis
  aussitot) au lieu d'attendre la fin du tour.
2026-07-23 17:07:55 +02:00
nathaninline 7720877533 Compaction : progression visible, bouton fonctionnel, erreurs moteur claires
- Banniere "Compactage du contexte en cours" pendant le resume (emis avant/apres
  via deltas compacting), au lieu d'une UI figee sans info.
- Le bouton "compacter" declenche desormais une VRAIE compaction manuelle
  (/api/chat/compact -> CompactNow, detache) ; visible des 50% de contexte. Fini
  le toast "c'est automatique" qui ne faisait rien.
- Erreurs de transport llama-server (connection refused / timeout / EOF)
  traduites en message clair ("le moteur demarre/charge, reessaie") au lieu du
  brut "dial tcp 127.0.0.1:8080: connect: connection refused".
2026-07-23 16:51:00 +02:00
nathaninline 0a81d8e4f4 v0.4.14 : refonte du modale editeur de preset
- Modale d'edition de preset refait au propre : classes CSS reutilisables,
  bloc "Modele & moteur" regroupe en carte, selecteur de moteur en 3 segments.
- Section telechargement : "Telecharger un modele" (pas forcement Hugging Face)
  + bouton reduit a une icone compacte collee au champ.
2026-07-23 15:48:52 +02:00
nathaninline ec4de88951 UI editeur preset : "Telecharger un modele" + bouton telechargement compact
- Libelle "Telecharger depuis Hugging Face" -> "Telecharger un modele"
  (pas forcement HF, juste un lien direct .gguf).
- Le bouton devient une icone compacte (⬇) collee au champ (input-btn) au lieu
  d'un gros bouton "telecharger" qui prenait toute la largeur.
2026-07-23 15:41:56 +02:00
nathaninline 37c4b4ca52 UI: refonte propre du modale editeur de preset
Styles inline -> classes CSS reutilisables (.modal-*, .fld, .ctl, .card, .seg).
Bloc modele/moteur regroupe dans une carte "Modele & moteur", selecteur de
moteur en 3 segments (rapide/optimise/perso), hierarchie et espacements clairs.
Verifie desktop + mobile. IDs et handlers inchanges.
2026-07-23 15:35:14 +02:00
nathaninline 3f03808e2c v0.4.13 : RAM dans la sidebar, config active clarifiee, verification de moteur
- Sidebar : nouvel affichage de la RAM systeme (used/total, /proc/meminfo).
- Config active : BIN devient MOTEUR (rapide/optimise/custom+chemin), ajout de
  N-CPU-MOE si present dans EXTRA_ARGS, retrait de PORT (deja affiche en haut).
- Section moteurs : renommee MOTEUR, passage au vouvoiement, et lien
  "verifier la version" (interroge la derniere version sans installer).
2026-07-23 15:08:59 +02:00
nathaninline 2b5356acd8 UI config active : N-CPU-MOE en majuscule 2026-07-23 13:59:26 +02:00
nathaninline 3574039d56 UI config active : retire PORT (deja affiche en haut) 2026-07-23 13:57:35 +02:00
nathaninline 6d54c45afa UI moteur : section renommee MOTEUR, vouvoiement, verification de version
- Titre "Backend llama.cpp" -> "MOTEUR".
- Passage au vouvoiement dans tous les textes de la section.
- Nouveau lien "verifier la version" sur chaque moteur (rapide/optimise) :
  interroge la derniere version dispo (endpoints check existants) SANS installer,
  et affiche le resultat en toast avant tout lancement d'install.
2026-07-23 13:56:09 +02:00
nathaninline 996f918e72 UI: MOTEUR en majuscule dans la config active 2026-07-23 13:49:53 +02:00
nathaninline a04613a87d UI: 'BIN' renomme 'moteur' dans la config active 2026-07-23 13:47:39 +02:00
nathaninline 6bdf9e8ae4 UI config active : BIN affiche le moteur (rapide/optimise/custom+chemin) + n-cpu-moe
- BIN devient un libelle lisible : "rapide" (moteur precompile), "optimise"
  (compile), ou "custom : <chemin>" sinon (via in_use / prebuilt.in_use de
  /api/llamacpp). Le chemin complet reste en tooltip.
- Ajout d'une ligne "n-cpu-moe" quand --n-cpu-moe est present dans EXTRA_ARGS.
2026-07-23 13:45:20 +02:00
nathaninline dbb0ac40a4 UI: affichage de la RAM systeme dans la barre laterale
Nouvel endpoint /api/ram (lecture /proc/meminfo, used/total en Mo, 0 hors Linux)
et bloc RAM dans la sidebar a cote du GPU, rafraichi toutes les 3 s. Masque si
pas de /proc/meminfo (Windows/mac).
2026-07-23 13:40:53 +02:00
nathaninline ee76638f15 v0.4.12 : fix reasoning Laguna S 2.1 (reponse qui partait dans le thinking)
Les modeles hybrides (Laguna S 2.1) qui repondent SANS reflechir n envoyaient
que `content` (ni reasoning_content, ni </think>, retire par le backend a
--reasoning-format). jean, avec REASONING=on, supposait un bloc <think> ouvert
par le prompt et vidait toute la reponse dans la bulle thinking. On streame
desormais le contenu en direct par defaut et on ne bascule en reasoning qu au
vu d un </think> reel. La coupe de la queue anti-</think> est realignee sur une
frontiere de rune UTF-8 pour ne plus casser les accents (e -> mojibake).
2026-07-23 11:49:40 +02:00
nathaninline ef5b036d99 backend llama.cpp : choix du moteur PAR MODELE (3 options), la barre laterale n'installe plus que
Corrige la confusion : deux endroits ecrivaient la ligne BIN et se battaient
(la barre laterale changeait le BIN global + redemarrait, puis selectionner un
preset remettait le BIN du preset). Desormais :
- la section laterale 'Backend llama.cpp' sert UNIQUEMENT a installer / mettre
  a jour les moteurs (rapide / optimisee), elle ne change plus le BIN actif
- le choix du moteur se fait PAR MODELE, dans l'editeur de preset, avec 3
  options claires : Rapide (precompile) / Optimise (compile) / Personnalise
  (chemin libre ou backend depose dans le dossier backends de jean, detecte)
- detection auto de l'option a l'ouverture selon le BIN du preset ; l'astuce
  indique le dossier ou deposer un binaire custom
- /api/llamacpp expose backends_dir ; l'endpoint /use n'est plus utilise par l'UI

v0.4.11
2026-07-22 20:17:23 +02:00
nathaninline c5522a51a5 v0.4.10 : backend llama.cpp, interface simplifiee (2 modes rapide / optimisee) 2026-07-22 19:55:04 +02:00
nathaninline ff045ba21e UI backend llama.cpp : vue simplifiee (2 modes rapide/optimisee, plus de badge, sans jargon)
Refonte de la section pour la rendre utilisable sans connaissances techniques :
- suppression du badge a cote du titre et de tous les details (commit, retard
  git, arch CUDA, nombre de jobs, chemins) ; une seule ligne 'Moteur actif : …'
- deux cartes claires : Version rapide (precompile, conseillee) / Version
  optimisee (compilee) ; un clic installe, active ou bascule
- bascule instantanee entre deux versions deja installees (nouvel endpoint
  /api/llamacpp/use : repointe BIN + redemarre, sans recompiler)
- carte active : '✓ Actif' + 'mettre a jour' ; progression et logs replies sous 'details'
2026-07-22 19:54:48 +02:00
nathaninline b0c1503ed8 v0.4.9 : backend llama.cpp precompile (binaires officiels, plus besoin de recompiler) 2026-07-22 19:22:34 +02:00
nathaninline b1890ed6f7 backend llama.cpp : mode binaires precompiles officiels (aucune compilation)
Alternative rapide a la compilation locale : telechargement des binaires
officiels de ggml-org/llama.cpp publies a chaque release (~2 min au lieu de
~40 de build CUDA). Le variant est choisi selon la machine (CUDA Windows avec
selection de la version selon le pilote + cudart, Vulkan, Metal, ROCm, CPU),
extrait dans backends/llama.cpp-prebuilt et BIN repointe dessus.

- backend_prebuilt.go : detection release/variant, telechargement avec
  progression, extraction zip/tar.gz anti zip-slip, marqueur VERSION
- UI : bouton 'binaires precompiles' + 'compiler (sources)', le statut
  distingue le mode actif (precompile vs build local), 'verifier les maj'
  compare a la derniere release officielle en mode precompile
- CLI : 'jean llamacpp prebuilt'
- le build local reste sur le disque : bascule possible via l'editeur de preset

Limites : builds generiques (pas de tuning natif) ; pas de build CUDA officiel
Linux (variant Vulkan) ; la compilation locale reste requise pour les forks.
2026-07-22 19:22:08 +02:00
nathaninline 58b59da823 v0.4.8 : gestion du backend llama.cpp depuis l'interface web (statut, verification des maj, install / update / recompilation avec logs en direct) 2026-07-22 17:59:12 +02:00
nathaninline 7ac571974f gestion du backend llama.cpp depuis l'UI web : statut (commit, retard, binaire, accelerateur detecte), verification des maj (git fetch), install / update / recompilation en job asynchrone avec phases, compteur de fichiers compiles et logs de build streames (poll /api/llamacpp/job) ; le service est arrete pendant le build puis relance, BIN repointe automatiquement 2026-07-22 13:34:56 +02:00
nathaninline 29f249be09 release CI : generer SHA256SUMS dans le workflow (jean update le verifie depuis v0.4.6) - evite le desaccord binaires CI / sommes manuelles qui a casse jean update sur v0.4.7 2026-07-22 12:37:57 +02:00
nathaninline 6bfa554edf v0.4.7 : detection et reparation auto de l'integration Visual Studio de CUDA (fix 'No CUDA toolset found' au build llama.cpp Windows, issue #10) 2026-07-22 12:26:03 +02:00
nathaninline 4fea700edc build CUDA Windows : detection + reparation de l'integration Visual Studio de CUDA manquante (erreur cryptique 'No CUDA toolset found', issue #10) - verif avant cmake via vswhere, copie auto des MSBuildExtensions du toolkit si possible, sinon message clair avec les 2 solutions ; filet dans hintMissingBuildDep 2026-07-22 12:24:33 +02:00
nathaninline 48c3e807be v0.4.6 : correctifs de la revue de code (reset/epoch, persistance du message user, cle jamais en URL, SHA256SUMS verifie par jean update, permissions preservees par edit, port conflict Windows) 2026-07-22 11:59:54 +02:00