Changelog
What changed, straight from the code
This isn't a marketing page: it's the actual CHANGELOG.md shipped inside the downloadable zip, read automatically on every visit — never retyped by hand, so it never drifts out of sync.
Current version : v1.4.0 Download this version
[1.0.8] - 2026-07-30
Ajouté (2026-07-30, liens hypertexte + commande /no_layout + flèches sur sélection multiple)
- Retour utilisateur — ajouter/modifier/retirer un lien hypertexte sur du texte : nouveau bouton dans la mini-barre de mise en forme (zone de texte, sélection requise) ouvrant un dialogue dédié (URL + « Retirer le lien » si un lien existe déjà). Le lien est réellement cliquable dans l'export PowerPoint (pas seulement un style visuel) ; à l'écran, souligné + couleur d'accent par défaut si aucune couleur n'a été choisie explicitement (jamais figé en dur dans le run tant que non retouché, même logique que police/taille/couleur).
- Retour utilisateur — commande
/no_layout: dans le chat, dire à l'IA de NE PAS utiliser les types de slides personnalisés de la charte pour cette demande (génération ou édition), tout en gardant couleurs/polices/icônes/images de la charte — pour laisser l'IA proposer une mise en forme nouvelle. Reconnue à l'autocomplétion "/" (comme/layout) et retirée du prompt avant envoi. - Retour utilisateur — flèches du clavier sur une sélection multiple : jusqu'ici sans aucun effet dès que plusieurs éléments étaient sélectionnés ensemble ; tous se déplacent désormais du même pas, en une seule entrée d'annulation pour le geste entier.
- +51 tests (
test_link_dialog.py,test_no_layout_command.py,test_no_layout_generation.py,test_no_layout_edit_service.py,test_no_layout_main_window.py— nouveaux fichiers ;test_richtext.py/test_rich_text_toolbar.py/test_canvas_rich_inline_edit.py/test_textfmt.py/test_roundtrip_pptx.py/test_schema.py/test_canvas_editing.pyétendus). - Exclusion des chartes d'exemple "société" (Socomec/ORCOM) rendue plus robuste : un nouveau fichier
Socomec - Charte Officielle.zipavait échappé à l'ancienne liste de noms exacts (packaging/build_release.py) — remplacée par une exclusion par PRÉFIXE de nom, qui couvre automatiquement tout futur fichier de la même marque sans avoir à s'en souvenir à chaque ajout.
Corrigé (2026-07-27, 2 plantages natifs en édition de texte + perte de données sur un glisser multi-éléments)
- Retour utilisateur — l'appli plantait en vidant tout le texte d'une zone, ou en collant un lien dans une zone de texte : même root cause pour les deux, trouvée en creusant :
QTextCharFormat.fontFamily()est une méthode dépréciée équivalant àfontFamilies()[0]— un ACCÈS MÉMOIRE INVALIDE (plantage natif, pas une exception Python interceptable) si le format ne porte AUCUNE propriété de police. Vider tout le texte (le curseur retombe sur un format sans aucune propriété) et coller du texte riche externe contenant un lien (le fragment importé ne porte pas de police explicite) produisent tous deux un tel format.ui/canvas_view.py::_safe_font_familylit désormaisfontFamilies()directement (jamais.fontFamily()), sans jamais planter. +6 tests (test_canvas_rich_inline_edit.py), dont 2 qui auraient fait planter tout le process de test sans le correctif — la vérification la plus directe possible pour un crash natif. - Retour utilisateur — glisser plusieurs éléments sélectionnés à la fois ne sauvegardait que la position de l'un d'eux : root cause — Qt déplace bien tous les éléments sélectionnés ensemble pendant le glisser (mécanisme intégré de
QGraphicsItem), mais seul l'élément cliqué pour démarrer le geste reçoit l'événement de relâchement de souris qui déclenche la sauvegarde ; les autres étaient déplacés à l'écran sans jamais être enregistrés, silencieusement rétablis à leur ancienne position au prochain changement de slide/annulation/réouverture.render/items.py::ElementItemsauvegarde désormais la position de TOUS les éléments sélectionnés au relâchement, avec une seule entrée d'annulation pour tout le geste (comme PowerPoint/Figma) — comportement inchangé pour un glisser d'un seul élément. +4 tests (test_canvas_editing.py,test_properties_panel_rect_sync.py). - 1228 tests passent en suite complète, aucune régression.
[1.0.7] - 2026-07-26
Ajouté (2026-07-26, icône sur le raccourci de lancement)
- Retour utilisateur : « identifier rapidement l'application à lancer depuis la racine du dossier » — un fichier
.batne peut PAS porter d'icône personnalisée (limitation Windows), contrairement à un raccourci.lnk.slydeforge.batcrée désormais automatiquement, à son premier lancement, un raccourciSlydeForge(icône de l'appli) à la racine du dossier, pointant vers le.bat(nouveaumake_shortcut.ps1, script dédié — aucune logique dupliquée). Ne se recrée pas si déjà présent (coût nul aux lancements suivants) ; supprimerSlydeForge.lnkpuis relancer le.batle régénère (utile si le dossier a été déplacé entretemps). - 2 bugs réels corrigés après premier retour utilisateur (icône absente dans l'Explorateur malgré des Propriétés correctes) : (1) le cache d'icônes de l'Explorateur n'est pas invalidé automatiquement par une création de raccourci via COM —
make_shortcut.ps1force désormais un rafraîchissement explicite (SHChangeNotify, API shell32). (2) piège Windows classique découvert et confirmé par un test isolé :%~dp0se termine par un\, et un chemin entre guillemets se terminant par\"juste avant le guillemet fermant est mal analysé par Windows (\"traité comme un guillemet littéral échappé, pas "backslash + fin de guillemet") — le script recevait le chemin avec un"littéral accroché à la fin, cassant silencieusement la création du raccourci. Fix :slydeforge.batpasse désormais"%~dp0."(le.neutralise le piège), etmake_shortcut.ps1normalise via[System.IO.Path]::GetFullPath(). - +1 test (
test_build_release.py).
Corrigé (2026-07-26, avertissement SmartScreen au 1er lancement de SlydeForge.exe)
- Retour utilisateur : « Windows a protégé votre ordinateur » (SmartScreen) au 1er double-clic sur
SlydeForge.exeaprès extraction d'un zip téléchargé au navigateur. Root cause : l'Explorateur Windows propage le « Mark of the Web » (marqueur de sécurité NTFSZone.Identifier) du zip téléchargé vers son contenu extrait, ce qui bloque tout .exe non signé tant qu'il est présent — vérifié empiriquement que ce n'est PAS un défaut depackaging/build_launcher_exe.py(un exe fraîchement construit localement n'a jamais ce marqueur).slydeforge.batretire désormais ce marqueur deSlydeForge.exedès son premier lancement (Unblock-File, jamais bloquant si PowerShell est absent) — évite l'avertissement à TOUS les lancements suivants.services/update_service.py::apply_update_from_zipfait de même par défense en profondeur pour tout.exeextrait via une mise à jour (vérifié que cette voie-là n'introduit de toute façon jamais le marqueur, contrairement à une extraction manuelle via l'Explorateur). - Limite honnête : rien ne peut supprimer l'avertissement au tout 1er double-clic d'un exe fraîchement téléchargé (avant que
slydeforge.batn'ait eu l'occasion de le débloquer) — seule une signature de code (certificat payant) élimine ce cas précis. Cliquer « Exécuter quand même » une fois est le comportement attendu et sûr pour un outil personnel non signé. - +3 tests (
test_update_from_zip.pyétendu).
Documentation (2026-07-26)
- Guide utilisateur mis à jour (
docs/guide-utilisateur.md) : fenêtre principale et menu Fichier recapturés (nouvelle barre d'outils Copier/Coller/Dupliquer/Pinceau, export/import de projet en .zip) ; nouvelle capture pour la gestion des projets (miniatures, tri, recherche — jusqu'ici jamais illustrée) ; texte à jour sur la saisie utilisable pendant un traitement, les interactions sur les fichiers joints (double-clic/clic droit), et le nouveau challenge conversationnel.
Ajouté (2026-07-26, challenge conversationnel post-génération + propriété intellectuelle)
- Nouveau : « challenger » le résultat en fin de 1re génération (
services/challenge_service.py, nouveau) : un bandeau propose « Voulez-vous que je challenge le résultat pour identifier des axes d'amélioration ? » directement dans le chat. En cas d'accord, l'IA analyse un lot de slides et propose, une à la fois, un axe d'amélioration DE FOND (clarté, pertinence, structure — distinct du contrôle de lisibilité déjà automatique) avec 1 à 3 solutions concrètes à choisir par bouton (ou juste une validation oui/non s'il n'y a qu'une solution). L'utilisateur peut appliquer une solution, passer, ou terminer l'échange à tout moment ; si d'autres axes restent possibles au-delà du lot analysé, l'appli propose de continuer. Toujours borné (au plus 3 suggestions par lot, au plus 3 relances) — jamais de boucle infinie pilotée par la seule réponse du modèle. - Propriété intellectuelle : nouveau
LICENSE.md— SlydeForge est un projet personnel d'Emilien MOREL, développé sur son temps personnel, n'appartenant à aucune entreprise ; les contributions sont bienvenues via LinkedIn. Mentionné dans le menu Aide > À propos,app.py,README.md, et inclus dans chaque release. - +58 tests (
test_challenge_service.py,test_chat_panel_challenge.py,test_challenge_flow_ui.py,test_about_dialog.py— nouveaux fichiers).
Corrigé (2026-07-26, retours après la release 1.0.6)
- Retour utilisateur — « Afficher dans l'explorateur » ne sélectionnait rien (clic droit sur un fichier joint) : root cause —
QFileDialogrend les chemins avec des « / » (convention interne de Qt), qu'explorer.exe /selectne résout pas de façon fiable (contrairement à la plupart des API Windows, qui normalisent silencieusement) ; seuls des « \ » natifs fonctionnent de façon fiable.ui/file_preview.py::reveal_in_file_managernormalise désormais le chemin avant de le passer à explorer. - Chartes trop orientées "société" retirées des releases : Socomec et ORCOM, initialement incluses avec les autres chartes d'exemple, sont désormais explicitement exclues de
packaging/build_release.py(retour utilisateur : initiative strictement personnelle, ne pas laisser penser que l'outil a été construit à partir d'exemples d'une société). SlydeForge.exe(lanceur, cf. version précédente) reconstruit et conservé à la racine du dépôt en plus d'être généré à chaque release — utile pour lancer l'appli directement depuis les sources sans repasser par le zip.
[1.0.6] - 2026-07-26
Ajouté (2026-07-26, fichiers joints : ouverture/gestion + prompt suivant préparable pendant un traitement + lanceur .exe)
- Retour utilisateur : « pouvoir double cliquer [sur un fichier joint à un prompt] pour l'ouvrir » + « pouvoir faire un clic droit sur les lignes pour gérer [...] supprimer/ouvrir ».
ui/file_preview.py: double-clic ouvre le fichier avec l'application par défaut (QDesktopServices) ; clic droit ouvre un menu Ouvrir / Afficher dans l'explorateur / Copier le chemin / Retirer (sélectionne d'abord seul l'item cliqué s'il n'est pas déjà dans la sélection, même convention queui/canvas_view.py). Câblé dansui/chat_panel.pyetui/generate_dialog.py. En chemin, root-cause d'un piège de test PySide6 découvert : monkeypatcherQMenu.execdirectement sur la CLASSE (monkeypatch.setattr(QMenu, "exec", ...)) ne suffit PAS avec shiboken — une instance déjà construite continue de résoudre la méthode C++ bloquante d'origine (confirmé par script isolé). Seule une VRAIE sous-classe Python interceptée via le nom du module (monkeypatch.setattr(ui.file_preview, "QMenu", MaSousClasse)) fonctionne de façon fiable. - Retour utilisateur : « pendant que l'assistant traite, je ne peux pas préparer mon prochain prompt ».
ChatPanel.set_busy()(ui/chat_panel.py) ne bloque plus que le bouton Envoyer — la zone de saisie, le bouton Joindre et la dictée restent utilisables pendant un traitement en cours. Root-cause :_submit()n'est déclenché QUE par le clic sur ce bouton (aucun raccourci Entrée ne l'appelle), donc le désactiver seul suffit à empêcher tout envoi prématuré. - Lanceur .exe Windows (
packaging/launcher_src.py+packaging/build_launcher_exe.py, compilé via PyInstaller) :SlydeForge.exe, icône applicative propre (Explorer/barre des tâches/menu Démarrer), pour un point d'entrée plus « pro » qu'un double-clic surslydeforge.bat. Volontairement minimal — son unique rôle est de retrouverslydeforge.batà côté de lui et de le lancer (fenêtre console conservée, dépendances vérifiées à chaque lancement exactement comme avant) : AUCUNE logique dupliquée,slydeforge.batreste la seule source de vérité pour la vérification/mise à jour des dépendances. Généré à chaque release (packaging/build_release.py), jamais commité en dur. - Audit du contenu de release (
packaging/build_release.py) — retour utilisateur : « vérifier qu'il ne manque pas de fichiers/documents nécessaires au bon usage ». Bug réel trouvé :docs/guide-utilisateur.md(lu parui/user_guide_dialog.py, menu Aide > Guide utilisateur) n'a JAMAIS été inclus dans un zip de release — ce menu était silencieusement inopérant (« Guide introuvable ») sur toute installation faite depuis une release, jamais depuis les sources.docs/ajouté àINCLUDE_DIRS.examples/(8 chartes prêtes à l'emploi, importables via Charte > Importer un .zip) également ajouté, sur décision explicite de l'utilisateur malgré son poids (~13 Mo) — sans elles, cette fonctionnalité n'avait rien à proposer par défaut à un nouvel utilisateur. - Base de données : confirmation —
init_db()(storage/db.py) tourne à CHAQUE démarrage (app.py::main()), pas seulement à la première installation. Son schéma est additif et idempotent (CREATE TABLE IF NOT EXISTS+_ensure_column/ALTER TABLE ADD COLUMNpar évolution, jamais de suppression/renommage) : toute mise à jour appliquée viaapply_update_from_zip(qui ne touche jamais%APPDATA%\SlydeForge, où vit la base) migre donc automatiquement le schéma au relancement suivant, sans étape manuelle. - +22 tests (
test_file_preview.pyétendu de 7 à 17,test_launcher_src.py/test_build_launcher_exe.pynouveaux,test_chat_panel_extra.py/test_build_release.pyétendus). - 1178 tests passent en suite complète, aucune régression.
Corrigé/Ajouté (2026-07-26, icônes de charte invisibles + aperçu des fichiers joints)
- Retour utilisateur (capture à l'appui) : « les icônes blanches avec fond transparent sont invisibles » dans la galerie/liste d'icônes de charte. Nouveau module
ui/asset_thumbnail.py: détecte les icônes dont le contenu OPAQUE est en moyenne trop clair (luminance) et compose un fond gris neutre contrastant derrière — jamais touché si l'icône est déjà visible (colorée/sombre). Remplace 3 copies auparavant dupliquées de chargement de miniature (ui/theme_editor.py,ui/image_insert_dialog.py,ui/theme_asset_gallery_dialog.py). Cette appli n'adapte pas son thème au mode sombre de Windows (QSS fixe) — le fond réel des listes est donc toujours clair aujourd'hui, d'où un seuil fixe plutôt qu'une lecture de palette dynamique. - Retour utilisateur : « je vois la liste des fichiers [joints à un prompt] mais pas de preview ». Nouveau module
ui/file_preview.py: vraie miniature pour les images et PDF (1re page, via PyMuPDF déjà utilisé pour l'extraction de texte), icône native du type de fichier pour le reste (xlsx/docx/pptx/csv/txt/md, viaQFileIconProvider) — jamais d'exception, quel que soit le fichier. Câblé dansui/chat_panel.py(fichiers joints au chat) etui/generate_dialog.py(fichiers d'analyse pour "Nouveau depuis un brief" — au passage, affichait jusqu'ici le CHEMIN COMPLET comme texte de l'item ; affiche désormais le nom seul, chemin conservé en infobulle +Qt.UserRolepour un retrait fiable). - +33 tests (
test_asset_thumbnail.py,test_file_preview.py,test_generate_dialog.pynouveaux,test_chat_panel_extra.pyétendu). - 1156 tests passent en suite complète, aucune régression.
[1.0.5] - 2026-07-26
Corrigé (2026-07-26, gestion des projets : dialogue enrichi + « data_uri vide » recensé une 2e fois)
- Retour utilisateur (gestion des projets) : « il faudrait une miniature et le nombre de slides afin de voir plus rapidement le contexte de la présentation. La miniature doit apparaître en premier. »
ui/project_manager_dialog.py: nouvelle colonne Miniature (1re colonne, rendu de la 1re slide) + colonne Slides, fenêtre élargie (720×440 → 1040×540).storage/projects.py::list_projects_with_previews()(nouvelle fonction, réservée à ce dialogue — reste sans dépendance Qt, contrairement àrender/capture.pyqui fait le rendu réel côté UI) fournit le nombre de slides + la 1re slide/charte/format à partir du deck RÉELLEMENT ouvert (autosave le plus récent si présent, sinon dernière version). - Retour utilisateur (tri + recherche) : « il faudrait pouvoir trier le tableau, et même pouvoir faire une recherche sur des mots clés. » Tri par clic sur l'en-tête (
setSortingEnabled), avec un item de tableau dédié (_SortableItem) pour que Slides/Versions trient par la vraie valeur NUMÉRIQUE (un tri texte trierait "10" avant "2"). Recherche par mot-clé (nom OU créé par), insensible à la casse, préservée après un renommage/une suppression. - Bug réel recensé une 2e fois — « data_uri vide » lors d'une génération depuis un brief (log utilisateur :
slides/0/elements/1/data_uri : '' does not match '^data:image/', sur un deck complexe de 12 slides avec fichier PPTX joint) : le 1er fix (31e vague) ne couvrait que le cas "asset_ref PRÉSENT mais inconnu, avec data_uri vide en couverture" — cette fois, l'élément n'avait AUCUN 'asset_ref' du tout (juste un data_uri vide posé directement), un cas jamais couvert par la condition"asset_ref" not in el: continuequi ignorait purement et simplement l'élément. Fix dansgenerate/slide_gen.py::_resolve_asset_refs(génération) ETcore/assets.py::resolve_asset_refs_in_elements(édition, MÊME logique dupliquée — désynchronisée une 1re fois avant ce fix, l'une des deux n'avait même pas encore le 1er correctif) : toute image sans data_uri exploitable (avec ou sans asset_ref) déclenche désormais la même relance informative auprès du LLM, plus jamais un échec de schéma cryptique. +14 tests (test_asset_ref.py, nouveautest_core_assets.py). - 145+ tests passent sur les fichiers touchés par cette vague, aucune régression.