A6 : list_xlsx_sheets (noms + dimensions + truncated), xlsx_to_markdown (table bornee 100x20 pour le contexte LLM), update_xlsx_cells et append_xlsx_rows (WRITE + confirmation, via edit_xlsx_cells : verrou, ecriture atomique, neutralisation des formules, 409 lossy). Les lignes ajoutees sont coercees comme dans le viewer (A10). Labels de step ai.step.xlsx_* FR/EN ; update_xlsx_cells/append_xlsx_rows branches sur MUTATING_TOOLS et FILE_WRITE_TOOLS (refresh viewer via obsigate:file-written). Tests : test_spreadsheet_tools.py 17 (risque, confirmation, persistance, garde formule heritee, coercion) + contre-preuve (cells vide -> 2 echecs). ruff 0, mypy 0, i18n parity, validate-imports. đ€ Generated with Codebuff Co-Authored-By: Codebuff <[email protected]>
168 KiB
Changelog â ObsiGate
Toutes les modifications notables d'ObsiGate sont documentées dans ce fichier.
Format basé sur Keep a Changelog, et Semantic Versioning.
En cours de développement : les changements à venir sont listés dans la section Unreleased. La derniÚre version livrée est 2.33.0.
[Unreleased]
[2.33.0] â 2026-09-28
[2.32.0] â 2026-09-28
[2.31.0] â 2026-09-28
Correction
- BUG-090 â troncature silencieuse d'une feuille
.xlsxau-delĂ de 500 lignes Ă 40 colonnes.render_sheets()renvoie les dimensions dĂ©clarĂ©es par la feuille (total_rows/total_cols), les plafonds du moteur (max_rows/max_cols) et un flagtruncated: la visionneuse affiche un bandeau « Feuille tronquĂ©e â 500 lignes affichĂ©es sur 520 » (i18n FR/EN) au lieu de prĂ©senter une table courte comme complĂšte. La ligne d'en-tĂȘtes est dĂ©sormais figĂ©e au dĂ©filement vertical (theadsticky,top: autosur les numĂ©ros de ligne pour Ă©viter leur empilement en haut Ă gauche). #153 A8/R5.
Ajouté
- #153 A9 â chargement paresseux d'une feuille par fenĂȘtres.
GET /api/file/{vault}/xlsx/sheet?sheet=&offset=&limit=renvoie un bloc de lignes (XlsxSheetWindowResponse, plafond 1 000 lignes par requĂȘte,has_morede pagination) avec les vraies coordonnĂ©es A1 et numĂ©ros de ligne de la feuille â une fenĂȘtre se comporte exactement comme le rendu complet. Erreurs typĂ©es : 404 feuille inconnue, 415 fichier non-.xlsx. La lecture des valeurs calculĂ©es en cache (#153 A12) s'applique aussi aux fenĂȘtres. - #153 A9bis â « Charger la suite » sous une feuille tronquĂ©e. Un pied de page annonce la progression et fetch la fenĂȘtre suivante au clic ou Ă l'approche du bas du tableau (sentinelle de dĂ©filement). Les lignes ajoutĂ©es passent par le mĂȘme pipeline d'Ă©dition que le rendu initial : Ă©ditables et sauvegardables immĂ©diatement. Un fetch Ă©chouĂ© restore le bouton (retry possible) ; feuille complĂšte â pied de page masquĂ©.
[2.30.0] â 2026-09-27
Correction
- BUG-089 â un reindex manuel ne reconstruisait pas l'index inversĂ©.
reload_index()/reload_single_vault()remplacent l'entrĂ©e de vault en bloc, ce qui n'Ă©met pas les notifications incrĂ©mentales : la recherche TF-IDF continuait de servir un index pĂ©rimĂ© aprĂšs un reindex. Les deux fonctions appellent dĂ©sormaisinit_inverted_index(). Au passage,backend/search.pylisait l'index viafrom backend.indexer import indexâ une liaison par valeur du dict : un rechargement du modulebackend.indexerrecrĂ©ait le dict cĂŽtĂ© indexer alors que la recherche Ă©crivait dans l'ancien, et l'index inversĂ© n'indexait plus rien. Tous les accĂšs passent par_indexer.index. TrouvĂ© en Ă©crivant le test de recherche d'A5 : il passait isolĂ©ment et Ă©chouait en suite complĂšte selon l'ordre.
Ajouté
- #153 A5 â les tableurs sont indexĂ©s par leur contenu.
extract_indexable_text()extrait les noms de feuilles et les 20 premiĂšres lignes (plafond 5 000 caractĂšres, 20 feuilles) pour le TF-IDF et la recherche sĂ©mantique. Un mot tapĂ© dans une cellule rend dĂ©sormais le classeur trouvable ; la lecture binaire pour l'affichage est inchangĂ©e et un classeur chiffrĂ©/corrompu s'indexe par son seul nom. - #153 A10 â la saisie est typĂ©e comme dans Excel. Une valeur
TRUE/FAUX/OUI/NONdevient un boolĂ©en, une dateJJ/MM/AAAA(avecHH:MMoptionnel) devient une vraie date â et dans l'ordre français :01/02/2026est le 1á”Êł fĂ©vrier. Une saisie ressemblant Ă une formule n'est jamais convertie. - #153 A12 â la valeur calculĂ©e s'affiche sous la formule. Quand une
cellule porte encore le résultat de son dernier calcul Excel, celui-ci
s'affiche dans une ligne discrĂšte sous la formule. La seconde lecture
data_only=Truen'a lieu que si l'archive contient réellement une valeur en cache, et toute erreur retombe sur l'affichage formules seul. Info-bulle traduite FR/EN (xlsx.cached_value_title).
[2.29.0] â 2026-09-27
Correction
- BUG-084 â l'index inversĂ© conservait des documents fantĂŽmes aprĂšs la
suppression d'une vault.
remove_vault_from_index()(backend/indexer.py) ne notifiait pas le hook incrĂ©mental : aprĂšs suppression d'une vault, ses documents restaient dans l'index inversĂ© (postings,doc_info,doc_vault,vault_docs) et continuaient de correspondre aux recherches pour une vault inexistante â seul un reindex manuel les effaçait. Le correctif dĂ©clenche_on_index_change('remove', âŠ)pour chaque fichier de la vault, et_remove_doc_internals()supprime dĂ©sormais la clĂ©vault_docsdont le set devient vide (c'est undefaultdict: une lecture la recrĂ©ait). Test :TestVaultRemovalPurgesInvertedIndex(contre-preuve : Ă©choue sans le correctif).
Maintenance
-
Index inversĂ© â
is_stale()renommĂ©is_ready(). La relecture deplan.mda Ă©tabli que les Ă©tapes 6 et 7 (suppression du cooldown et du hack de coalescence) Ă©taient dĂ©jĂ livrĂ©es : ni_last_rebuild, ni_rebuild_cooldown, ni_source_generation, ni_on_vault_changene subsistent.is_stale()ne mesurait donc plus aucune staleness â il indiquait seulement si l'index initial Ă©tait construit, sous un nom trompeur. RenommĂ©is_ready(), cohĂ©rent avec leis_ready()deSemanticIndex; l'aliasis_stale()deSemanticIndex, sans appelant, est supprimĂ©./api/diagnosticsexpose dĂ©sormaisis_ready(libellĂ© « Index prĂȘt » cĂŽtĂ©frontend/js/config.js). Tests :test_is_ready_tracks_initial_build,test_is_ready_survives_incremental_updates. -
plan.mdrecalibrĂ©. Le fichier est dĂ©sormais marquĂ© « livrĂ© » et suivi d'une section « Ătat rĂ©el » : le code a divergĂ© du plan sur quatre points (pas de repli_needs_rebuild,_readyau lieu dedoc_count == 0,rebuild()conservĂ© au dĂ©marrage,is_stale()repurposĂ©). Les extraits de code du plan sont explicitement signalĂ©s comme ne dĂ©crivant pas le code actuel. -
Fixtures de test locales exclues du suivi Git.
test_dir/music/,test_dir/video/,test_vault/images/,test_vault/markdown/ettest_vault/budget.xlsx(~200 Mo) sont ajoutĂ©s au.gitignore: aucun test ni job CI ne les rĂ©fĂ©rence â les tests unitaires gĂ©nĂšrent leurs fixtures danstmp_pathet l'E2E n'utilise que les fixtures committĂ©es (test_vault/sample-*.{mp3,png,svg,webm,pdf},test_dir/*.md). Ils restaient non suivis et polluaientgit status.
Sécurité
- BUG-088 â plus d'injection de formule via la visionneuse Excel. Une
saisie
=cmd|'/c calc'!A1(ou@âŠ) Ă©tait stockĂ©e comme formule par openpyxl, donc exĂ©cutĂ©e par Excel Ă la rĂ©ouverture du fichier (DDE).edit_xlsx_cellsforce maintenant le type texte (cell.data_type = "s") pour toute valeur commençant par=ou@; l'API accepteallow_formula: trueet la visionneuse expose un boutonf(x)(opt-in, Ă©tat de session, jamais persistĂ©).+/-restent des nombres. - BUG-087 â Ă©criture concurrente d'un classeur.
load_workbook()âsave()n'Ă©tait pas sĂ©rialisĂ© : deux sauvegardes simultanĂ©es (deux onglets, l'agent IA et la visionneuse) faisaient gagner la derniĂšre, en silence. Verrou par chemin (backend/services/mutations.py::_xlsx_write_lock, timeout 15 s) autour du cycle lecture â Ă©dition â remplacement ; attente dĂ©passĂ©e â 409conflict. L'endpointPUT âŠ/xlsx/saveest devenu synchrone pour que l'attente s'exĂ©cute dans le threadpool.
Corrigé
- BUG-085 â la perte de donnĂ©es Ă l'enregistrement d'un
.xlsxest annoncĂ©e, plus silencieuse.GET /api/file/{vault}renvoiexlsx_lossy_features(Ă©lĂ©ments qu'un round-trip openpyxl perd) ; la visionneuse affiche un bandeau listant ces Ă©lĂ©ments et la premiĂšre sauvegarde demande confirmation avant de renvoyerforce: true. Sansforce, l'API rĂ©pond 409xlsx_lossy_contentavecdetails.features. PĂ©rimĂštre remesurĂ© sur openpyxl 3.1.5 : graphiques, images, dessins et tableaux croisĂ©s sont bien prĂ©servĂ©s ; sont perdus les valeurs calculĂ©es en cache, slicers/chronologies, contrĂŽles de formulaire, connexions/requĂȘtes, custom XML, signature numĂ©rique, commentaires enrichis et macros. - BUG-086 â Ă©criture atomique des classeurs.
wb.save()écrivait en place sur le fichier du vault : un plantage laissait un.xlsxtronqué. L'écriture passe désormais par un.tmppuisos.replace()(le backup.bakest inchangé, le.tmpest ignoré par le watcher). - Le handler global
ServiceErrorexpose maintenantcodeetdetailsdans la rĂ©ponse JSON, etapi()(frontend) les propage sur l'Error â nĂ©cessaire pour que le client distingue un 409 de confirmation d'une autre erreur.
Ajouté
- #153 (P0) â tests de la visionneuse Excel.
tests/frontend/xlsx-viewer.test.mjs(10 tests JSDOM : banniÚre, confirmation + repriseforce, refus, togglef(x), payload de sauvegarde) ettests/e2e/xlsx-viewer.spec.js(3 tests Playwright sur la fixturetest_vault/sample-xlsx-lossy.xlsx) ; la suite JSDOM est branchée dans le CI.
Documentation
- #153 â Visionneuse & Ă©dition XLSX : audit complet et backlog de
complétude. La visionneuse
.xlsxlivrĂ©e par #152 a Ă©tĂ© auditĂ©e couche par couche (lecturebackend/xlsx_reader.py, Ă©criturebackend/services.mutations.edit_xlsx_cells, UIrenderXlsxViewer, indexation, outils IA, tests). Bilan : la grille de valeurs est Ă©ditĂ©e correctement (sĂ©curitĂ©, backup, audit, Ă©chappement HTML), mais l'ensemble supportĂ© est Ă©troit, une partie du classeur est perdue Ă l'enregistrement, les tableurs sont invisibles pour la recherche et l'IA ne sait que les crĂ©er. Ouverture de l'item #153 dansdocs/ROADMAP.md(17 sous-tĂąches suivies A1 â A17 ; P0 livrĂ©, reste P1 recherche/IA/UX puis P2 Ă©tendu) et crĂ©ation de la fiche docs/features/xlsx-viewer.md : cartographie du code, limites par couche, tableau des risques R1-R5 et critĂšres d'acceptation par sous-tĂąche.
[2.28.16] â 2026-09-27
[2.28.15] â 2026-09-27
Sécurité
-
#87 T6 â dĂ©pendances qualifiĂ©es,
pip-auditbloquant (0 vulnĂ©rabilitĂ©). mistune 3.0.2 â 3.3.3 (XSS/ReDoS/DoS dans le moteur de rendu), python-multipart 0.0.9 â 0.0.31, weasyprint 69 â 70, mcp 1.9.4 â 1.28.1, fastapi 0.110.3 â 0.141.1 + starlette 0.37.2 â 1.7.0, setuptools 84 ;cast(str, âŠ)aux 3 sites d'appel mistune (typage 3.3 resserrĂ©). Suite complĂšte 1359 passed, ruff/mypy 0. Seule exception : PYSEC-2026-1325 (ecdsa, Minerva) â aucun correctif upstream ET JWT exclusivement HS256 (backend/auth/jwt_handler.py), les chemins ECDSA P-256 ne s'exĂ©cutent jamais â--ignore-vulndocumentĂ©. -
#87 T7 â semgrep SAST local bloquant (8 rĂšgles, 0 finding). Ruleset
semgrep-rules/(eval/exec, shell=True, os.system, pickle, yaml.load sans Loader, verify=False, Markup, mktemp) â 100 % local, aucun registre rĂ©seau (runner au rĂ©seau fragile). Trivy Ă©cartĂ© : binaire + base de vulnĂ©rabilitĂ©s Ă tĂ©lĂ©charger Ă chaque run, couche Python dĂ©jĂ couverte parpip-auditbloquant (image = slim + 4 libs). -
#87 T8 â fin BUG-034 : cookies Secure auto, CORS same-origin explicite.
OBSIGATE_SECURE_COOKIES=true|false|auto(dĂ©faut auto : Secure en https, sinon rien â logins http locaux prĂ©servĂ©s ;X-Forwarded-ProtohonorĂ© sousTRUST_PROXY, avertissement dĂ©marrage affinĂ©,TRUST_PROXY=truedans le compose prod) ;CORSMiddlewaresame-origin explicite (sĂ»r : web et desktop Tauri same-origin, API directe hors navigateur) ;style-src 'unsafe-inline'conservĂ© et assumĂ© (189 attributsstyle=+ 343el.styleâ suppression = réécriture complĂšte, risque nul cĂŽtĂ© exĂ©cution une foisscript-srcverrouillĂ© en T5c).
[2.28.14] â 2026-09-27
[2.28.13] â 2026-09-27
Modifié
- #87 (T5c) â
script-srcsans'unsafe-inline'. Seuls les scripts avec nonce frais (backend/csp.py, T5b) ou servis par'self'/CDN listés s'exécutent ;style-srcgarde'unsafe-inline'(chantier séparé). Vérifié :test_csp_nonce.py5/5, 0 handler inline restant dans les pages HTML (propriétésonXxx = fnen JS non concernées par la CSP).
[2.28.12] â 2026-09-27
Corrigé
- BUG-081 â
GET /api/auth/mfa/statusâ 500 quand l'auth est dĂ©sactivĂ©e. Le pseudo-useranonymous(auth dĂ©sactivĂ©e, mode E2E/CI) n'a aucune entrĂ©e en store :get_user(...)âNonepuisAttributeErrorsuruser.get. GardeNoneâ payload « MFA dĂ©sactivĂ© » (mfa_enabled: false,totp_enabled: false,webauthn_credentials: 0). Test :tests/test_mfa.py(TestMfaStatusAuthDisabled, Ă©choue en 500 sans le correctif).
[2.28.11] â 2026-09-27
[2.28.10] â 2026-09-27
Corrigé
- BUG-083 â job CI
securityrouge : le runner tronquait le#durun:pip-audit. Le runner Gitea Act coupe naĂŻvement au premier#(mĂȘme entre guillemets) :echo "... see #87)"devenait une citation non fermĂ©e (unexpected EOF while looking for matching '"'"). Seulrun:du workflow avec un#; l'echo n'a plus de#(rĂ©f#87en commentaire YAML, jamais vu par le shell). Garde-fou :tests/test_ci_workflow.py(aucun#dans le code desrun:,upload.test.mjsverrouillĂ© dans l'Ă©tape JSDOM â BUG-082).
[2.28.9] â 2026-09-27
Corrigé
- BUG-082 â CI
lintrouge : suites frontend exigeantjsdom.tests/frontend/upload.test.mjspuisconfig-ai-keys.test.mjs(imports statiquesjsdom, introduits par#89) Ă©taient exĂ©cutĂ©s dans l'Ă©tape frontend racine oĂčjsdomn'est jamais installĂ© (ERR_MODULE_NOT_FOUND, rouge depuis7bee4a2). DĂ©placĂ©s dans l'Ă©tape JSDOM (les deux branches, aprĂšs install si besoin) ; garde-foutests/test_ci_workflow.py: aucun fichier de l'Ă©tape racine ne doit importerjsdomstatiquement.
[2.28.8] â 2026-09-27
Corrigé
- BUG-080 â harnais E2E local anti-blocage (plus de run pendu toute la nuit).
run-e2e-local.ps1: Playwright lancĂ© vianodedirect sur la CLI locale (jamais de prompt interactif,Start-Processne sachant pas exĂ©cuternpx; paramĂštre$Arguments,$ArgsĂ©tant une variable automatique qui l'Ă©craserait), installation Chromium sautĂ©e si dĂ©jĂ prĂ©sent (E2E_INSTALL_BROWSERS=1pour forcer), Ă©tapesinstall/testbornĂ©es (E2E_TIMEOUT_SEC, dĂ©faut 1800 s / 600 s, exit 124 au dĂ©passement â au-delĂ du globalTimeout pour un abandon propre avec rapport) ;run-e2e-local.sh:npx --yes+ mĂȘmes bornes ;playwright.config.ts:globalTimeout(25 min en local, 30 min en CI,E2E_GLOBAL_TIMEOUT_MSpour surcharger) ;e2e-server.ps1: pidfile resynchronisĂ© sur le vrai propriĂ©taire du port etstopqui tue l'arbre complet (fini les serveurs orphelins qui squattent le port 2029). Garde-fous :tests/test_e2e_harness.py(8 tests).
[2.28.7] â 2026-09-26
Ajouté
- #87 (T5b) â nonces CSP prĂȘts pour la bascule (sans changement).
Nonce frais par réponse dans
script-src(backend/csp.py), injectĂ© dans les 6 pages HTML servies (dont la nouvelle route/excalidraw-editor.html, utilisĂ©e par l'iframe du viewer au lieu de/static/) et la page de partage ;tests/test_csp_nonce.py(unicitĂ©, concordance en-tĂȘte/HTML).unsafe-inlineconservĂ© jusqu'en T5c.
[2.28.6] â 2026-09-26
Modifié
- #87 (T5a) â 16 handlers inline convertis en listeners (CSP inchangĂ©e).
onclick/onerrordeindex.htmlet des vues JS (config,plugins,sync,viewer,auth) remplacés paraddEventListener; suites frontend vertes (unit, ai, config-mobile, pdf-viewer, mfa-settings, sidebar-filters).
[2.28.5] â 2026-09-26
[2.28.4] â 2026-09-26
Ajouté
- #87 (T4) â E2E XSS et serveur E2E pilotĂ©.
tests/e2e/xss.spec.js: page publique/s/{token}(titre/frontmatter hostile Ă©chappĂ©, JSON neutralisĂ©, aucun JS exĂ©cutĂ©) et lecteur markdown (sanitizer, aucunon*/javascript:vivant) â 2/2 verts en local.scripts/e2e-server.ps1:start|stop|status|logsavec progression visible et fichier PID (fini les serveurs orphelins sur le port 2029).
[2.28.3] â 2026-09-26
Ajouté
- #87 (T3) â cookies
Secureet CORS explicites. Helperis_secure_cookies()centralisĂ© (dĂ©fautfalseconservĂ© pour ne pas casser les logins HTTP locaux) + avertissement au dĂ©marrage sur bind non-loopback sansSecure;tests/test_security_headers.pyatteste l'absence de CORS permissif (same-origin par dĂ©faut du navigateur) et les en-tĂȘtes de durcissement.
[2.28.2] â 2026-09-26
Ajouté
- #87 (T2) â tests de durcissement : concurrence et regex.
tests/test_hardening_concurrency.py: créations/mises à jour/login failuresconcurrents surusers.json(zéro mise à jour perdue, JSON toujours récupérable) et budget temps de la politique ReDoS (motifs catastrophiques rejetés en < 1 s, motifs acceptés < 5 s sur 200 Ko).
[2.28.1] â 2026-09-26
Modifié
- #87 (T1) â CI sĂ©curitĂ© durcie.
banditpasse en bloquant (# nosecjustifiés : SHA1 non-crypto, subprocess git à argv fixe,saxutils.escapesans parsing ; B105 exclu commepyproject.toml) ;npm audit --omit=devbloquant (0 faille) ; les 5 suites frontend hors CI (upload,pretty,media-viewer,mfa-settings,config-ai-keys, vertes en local) rejoignent le joblint.pip-auditreste consultatif (upgrades starlette/weasyprint à qualifier, chantier dédié).
[2.28.0] â 2026-09-26
Modifié
- #85 (T10) â persistance d'Ă©tat et clĂŽture de la refonte architecturale.
Verrous
RLocksur les stores JSON sans protection (revoked_tokens,shares,webhooks+ secrets, clĂ©s d'outils) avec tests de concurrence (tests/test_store_locks.pyâ pertes prouvĂ©es sans verrou) ; rate-limit auth persistĂ© en option (OBSIGATE_RATELIMIT_DB, SQLite WAL, sĂ©mantique identique, dĂ©faut mĂ©moire inchangĂ©,tests/test_ratelimit_store.py). Contrattools/registry.pyauditĂ© (permissions/quotas/redaction dĂ©jĂ cĂąblĂ©s, rien Ă coder). Index non persistĂ© : rebuild diffĂ©rentiel #86 suffisant (dĂ©cision documentĂ©e). Fichedocs/features/archi-refonte-85.md, #85 sorti du backlog (index roadmap).
[2.27.12] â 2026-09-26
Modifié
- #85 (T9) â extraction realtime + render hors du monolithe
backend/main.py. Le stream SSE/api/eventset le WebSocket/ws/collab/*sont servis parbackend/routers/realtime.py, le pipeline markdown (mistune, wikilinks, slugs, sanitizer) parbackend/render.py(imports directs, plus de couplage diffĂ©rĂ©).main.py(4 827 â ~760 lignes) ne contient plus que l'assemblage : lifespan, middlewares, montage des 16 routers, racine/api, statique/SPA et cales de compatibilitĂ© testĂ©es.
[2.27.11] â 2026-09-26
Modifié
- #85 (T8) â extraction vaults/history/conflicts hors du monolithe
backend/main.py. 13 routes servies parbackend/routers/vaults.py,history.pyetconflicts.py;VaultInfo/BookmarkToggleRequestdansschemas.py, handle watcher partagé dansbackend/watcher_state.py.tests/test_api_main.pyimportehumanize_mtimedepuis son module canonique (services.recent).
[2.27.10] â 2026-09-26
Modifié
- #85 (T7) â extraction du domaine
confighors du monolithebackend/main.py./api/config, ai-keys (get/post/delete/test), tool-keys (Ă3), ai-models, diagnostics et dashboard sont servis parbackend/routers/config.py(_FALLBACK_MODELS, store clĂ©s et config dĂ©placĂ©s ;mainrĂ©importe_load_configpour son lifespan, les fixtures de tests inchangĂ©es).tests/test_ai_models.pypatch dĂ©sormais la rĂ©fĂ©rence du router.
[2.27.9] â 2026-09-26
Modifié
- #85 (T6c) â extraction media/pdf/export/guide hors du monolithe
backend/main.py. file/pdf, exports (html/md-bundle/epub), guide/download, pdf/stream|info, image, media+thumb, attachments (rescan/stats), vault settings (get/post/all) et vault files sont servis parbackend/routers/files_media.py; le helper Range partagé vit dansbackend/routers/helpers.py(tags OpenAPI inchangés, tests statiques frontendmedia-viewer/image-viewerréalignés).
[2.27.8] â 2026-09-26
Modifié
- #85 (T6b) â extraction mutations fichiers/dossiers hors du monolithe
backend/main.py.PUT .../save|xlsx/save,DELETE/POST/PATCH /api/file,POST/PATCH/DELETE /api/directory,POST /api/move,POST .../batch-uploadsont servis par le nouveaubackend/routers/files_write.py(effets de bord inchangés : audit, index, SSE, webhooks, plugins, historique) ; 15 modÚles dansschemas.py.
[2.27.7] â 2026-09-26
Modifié
- #85 (T6a) â extraction lecture fichiers hors du monolithe
backend/main.py./api/browse/{vault},/api/file/{vault}/raw|download|backlinksetGET /api/file/{vault}(vue rendue tous formats) sont servis par le nouveaubackend/routers/files_read.py; modÚles dansschemas.py,_content_disposition/_media_max_inline_bytesdansbackend/routers/helpers.py(partagés avec les tranches suivantes). Correctif au passage : décorateur orphelin/s/{token}resté en T3 et double-enregistrement de/api/conflictssupprimés.
[2.27.6] â 2026-09-26
Modifié
- #85 (T5) â extraction du domaine
searchhors du monolithebackend/main.py. Les 11 routes (/api/search,/advanced,/replace,/tags,/tree-search,/vault/{vault}/paths,/suggest,/tags/suggest,/graph/{vault},/index/reload,/index/reload/{vault}) sont servies par le nouveaubackend/routers/search.py; les modĂšles search dansschemas.pyet le pool de threads dansbackend/search_executor.py(mĂȘme dimensionnement, mĂȘme cycle de vie) â comportement inchangĂ©.
[2.27.5] â 2026-09-26
Modifié
- #85 (T4) â extraction du domaine
backupshors du monolithebackend/main.py. Les 9 routes (/api/file/{vault}/backups|diff|restore,/api/backups,/delete,/purge,/content,/compress,/auto) sont servies par le nouveaubackend/routers/backups.py;Diff/Restore*dĂ©mĂ©nagent dansschemas.pyet le singleton SSE dansbackend/sse.py(partagĂ© avecmain) â comportement inchangĂ©, aucun impact utilisateur.
[2.27.4] â 2026-09-26
Modifié
- #85 (T3) â extraction du domaine
sharinghors du monolithebackend/main.py.POST /api/share/{vault},GET /api/shares,DELETE /api/share/{share_id}et les pages publiques/s/{token},/s/{token}/raw,/s/{token}/pdfsont servis par le nouveaubackend/routers/sharing.pyâ chemins, rĂ©ponses, tags OpenAPI et authentification inchangĂ©s (aucun impact utilisateur).
[2.27.3] â 2026-09-26
Modifié
- #85 (T2) â extraction du domaine
webhookshors du monolithebackend/main.py. Le CRUDGET/POST/PATCH/DELETE /api/webhooks(admin) est servi par le nouveaubackend/routers/webhooks.pyâ chemins, rĂ©ponses, tags OpenAPI et authentification inchangĂ©s (aucun impact utilisateur).
[2.27.2] â 2026-09-26
Modifié
- #85 (T1) â extraction du domaine
healthhors du monolithebackend/main.py.GET /api/healthetGET /api/health/detailed(admin) sont servis par le nouveaubackend/routers/health.py(montĂ© dansmain.py) et le modĂšleHealthResponsedĂ©mĂ©nage dansbackend/schemas.pyâ chemins, rĂ©ponses, tags OpenAPI et authentification inchangĂ©s (aucun impact utilisateur).
[2.27.1] â 2026-09-26
Modifié
- Roadmap â priorisation dette & sĂ©curitĂ© (dĂ©cisions 2026-09-26).
Items #85 (refonte architecturale) et #87 (CI/CD) détaillés et marqués
prioritaires :
backend/main.pymesuré à ~4 827 lignes,tools/registry.pyà créer, persistance SQLite/Redis, verrous asyncio, audit desexceptlarges, CI sécurité bloquante (bandit/semgrep/trivy, audits pip/npm), finition CSP nonce (BUG-034), cookiesSecurepar défaut, rotation clé DeepSeek à confirmer (BUG-006). #73 Sync reporté (P4, hors chemin critique) ; desktop #77 confirmé non signé + doc SmartScreen, reste les 6 tests E2E manuels. Corrections : sections livrées #83/#84 retirées du backlog (détail dans l'archive, index inchangé), total restant recalculé (~12-18 jours chemin critique : #77 fin + #85 + #87).
[2.27.0] â 2026-09-25
Ajouté
- #152 â Viewer XLSX : affichage des fichiers
.xlsxen tableaux multi-feuilles (onglets, en-tĂȘtes A1), Ă©dition inline des cellules avecPUT /api/file/{vault}/xlsx/save(backup avant Ă©criture, coercion numĂ©rique) et tĂ©lĂ©chargement du fichier d'origine.
[2.25.1] â 2026-09-24
Corrigé
/api/diagnosticsâ erreur 500 « dictionary changed size during iteration ». Le calcul des statistiques d'index itĂ©raitinv.word_indexetindexen direct, pendant que l'indexeur les modifiait depuis un autre thread (build au dĂ©marrage, hooks incrĂ©mentaux) : l'itĂ©rateur de dict levaitRuntimeErroret l'endpoint renvoyait 500. Les deux dicts sont dĂ©sormais copiĂ©s avant itĂ©ration (copie atomique sous le GIL), ce qui supprime la course.
[2.25.0] â 2026-09-24
Ajouté
- #115 â barre d'outils de lecture toujours visible. La barre d'actions d'un
document (pop-out, bookmark, Editer, Source, Copier, PartagerâŠ) est dĂ©sormais
épinglée en haut de la zone de lecture : elle reste accessible en permanence,
mĂȘme au bas d'un document long, au lieu de disparaĂźtre au dĂ©filement. Elle est
rendue comme un enfant direct du conteneur de défilement (
.file-toolbar), masquĂ©e en mode lecture, et alignĂ©e dans la fenĂȘtre pop-out. - #117 â avatars prĂ©dĂ©finis dans le profil. La section Profil propose une
galerie de 12 avatars fournis avec l'application (
frontend/icons/avatar/) : un clic charge l'image, la recadre au format carrĂ© 256 px (mĂȘme pipeline que l'import) et l'enregistre sur le compte. L'avatar actif est surlignĂ© ; l'import d'une photo personnalisĂ©e et la suppression restent disponibles.
Corrigé
- BUG-078 â coloration syntaxique des fichiers de code perdue. Les feuilles de
style highlight.js étaient basculées à partir de la clé de thÚme
(
defaut-obsigate, âŠ) au lieu du mode (dark/light) : les deux feuilles se retrouvaient dĂ©sactivĂ©es et les blocs de code (.py,.sh,.ps1,.yml, JSON, blocs MarkdownâŠ) s'affichaient en texte brut. Le basculement est dĂ©sormais pilotĂ© par le mode, de façon dĂ©terministe, dans le moteur de thĂšme (themes.js) comme au premier rendu (ui.js) ; sĂ©pia et contraste Ă©levĂ© rĂ©utilisent la palette claire.
[2.24.0] â 2026-09-24
Ajouté
- BUG-077 â assistant IA : bouton « Stop ». Pendant qu'une rĂ©ponse se diffuse, le bouton d'envoi du composeur devient un bouton Stop (icĂŽne carrĂ©e, couleur d'alerte) : un clic interrompt immĂ©diatement l'exĂ©cution de l'agent (abort de la requĂȘte SSE, annulation de la tĂąche cĂŽtĂ© serveur Ă la dĂ©connexion) et la rĂ©ponse partielle est conservĂ©e avec un marqueur « âč ExĂ©cution arrĂȘtĂ©e. ». Le bouton reste actif (il n'est plus dĂ©sactivĂ©) tant que l'agent travaille, y compris pendant la reprise d'une confirmation.
Modifié
- BUG-075 â assistant IA : approbation globale des actions. Une mĂȘme rĂ©ponse du
modÚle peut demander plusieurs mutations (créer un dossier et les fichiers
qu'il contientâŠ). Elles sont dĂ©sormais regroupĂ©es en une seule confirmation (au
lieu d'une action aprÚs l'autre) : la carte liste chaque action avec son libellé et
son aperçu de diff, et un unique bouton « Tout approuver (N) » envoie
confirm_allâ les actions en attente sont appliquĂ©es d'un bloc, puis la suite de l'exĂ©cution est autorisĂ©e sans nouvelle carte. Les appels en lecture du mĂȘme lot s'exĂ©cutent immĂ©diatement (conversation valide). CĂŽtĂ© backend,pending.actionsremplace le reportdeferreddes mutations d'un lot (backend/agent/loop.py) etconfirm_allarmeToolContext.confirmedpour le reste du run (backend/bookslm_routes.py).
Corrigé
- BUG-074 â assistant IA : bloc d'Ă©tapes sans titre et compteur figĂ© Ă 1. Le rĂ©sumĂ© repliĂ© affiche dĂ©sormais un titre (le libellĂ© de la premiĂšre action, « N Ă©tapes â Fichier créé : notes/a.md ⶠ»), le compteur ne compte plus les rĂ©flexions (seules les actions) et la reprise d'une confirmation continue de diffuser dans le mĂȘme message au lieu de crĂ©er un nouveau message « 1 Ă©tape » par approbation : le bloc d'Ă©tapes s'accumule sur tout l'Ă©change.
- BUG-076 â assistant IA : arborescence et document ouvert non rafraĂźchis. AprĂšs
une action mutatrice de l'agent (création/suppression/renommage de fichier ou
dossier, écriture), l'arborescence est rafraßchie immédiatement (rafraßchissement
débouncé sur les événements
toolmutateurs, sans attendre le watcher) et le document affiché est rechargé depuis le disque ; les outils de création de documents (xlsx/docx/csv/pdf) notifient désormais aussi la visionneuse.
[2.23.0] â 2026-09-24
Ajouté
- #114 â Configuration, refonte mobile-responsive. La page « Configurations »
est désormais pensée pour le tactile (†768 px) : modale plein écran
(
100dvh, safe-area), sommaire en drawer coulissant gauche (position: fixed, largeurmin(320px, 88vw)) avec fond assombri (#config-modal.config-toc-open::before) et bouton de fermeture#config-toc-close(tap sur le backdrop ou Ăchap ferme le drawer d'abord, puis la modale) ; formulaires sur une colonne ; tous les boutons (save/secondary/danger/add/sm/hamburger/fermer) et liens du sommaire en cibles â„ 44 px ; champs et selects en 16 px + min-height 44 px (anti-zoom iOS) ; rangĂ©e « Sauvegarder / RĂ©indexer / RĂ©initialiser » sticky en bas de sa section avec safe-area ; MFA (codes de secours en 1 colonne, champ de code full-width et wrap des rangĂ©es d'action) ; dĂ©bordements webhook/token/share corrigĂ©s. Dettes HTML/i18n de l'audit incluses :.config-actions-rowreplacĂ©e dans#cfg-backend-settings(+</section>orphelin supprimĂ©), id dupliquĂ©cfg-partages-publicsretirĂ© du<h2>, conteneur mort#plugins-settings-containersupprimĂ©, libellĂ©#mt-exploreri18n (settings.explorer), doublons.config-btn-addet rĂšgle morte.mfa-recovery-inputpurgĂ©s ; i18n : clĂ©s mortessettings.backend,settings.backend_hint,settings.restart_badge,settings.save,settings.pluginssupprimĂ©es,config.toc_closeajoutĂ©e,settings.tabsFR corrigĂ© (« Onglets »). Tests :config-mobile.test.mjsĂ©tendu (27, au CI) + E2Econfig-mobile.spec.js(5, projetchromium-mobile). Fiche : docs/features/settings-mobile-114.md.
[2.22.1] â 2026-09-23
Corrigé
- BUG-073 â mobile, fin de contenu masquĂ©e. La barre de navigation fixe du bas
(
#mobile-toolbar, 64 px + safe-area) recouvrait le bas de tous les documents et pages en vue mobile (†768 px) : les derniĂšres lignes restaient dĂ©finitivement sous la barre. Cause : la rĂšgle de clearance du bloc mobile ciblait.main-layout, classe absente deindex.html(le vrai conteneur est.main-body) â sĂ©lecteur mort, aucun dĂ©gagement rĂ©servĂ©. Correctif : cible.main-body(padding-bottom: calc(64px + env(safe-area-inset-bottom, 0))), suppression de la rĂšgle sĆur morte.editor-modal.active ~ .main-layout, reset du dĂ©gagement en mode lecture (barre masquĂ©e) etbody.np-active .content-arearamenĂ© Ă76 px(le dĂ©gagement dock, sans double comptage avec.main-body). Tests :tests/frontend/mobile-toolbar.test.mjs(7, au CI) et E2Etests/e2e/mobile-toolbar.spec.js(2, projetchromium-mobile).
[2.22.0] â 2026-09-23
Ajouté
- #113 â avatar utilisateur. La section « Profil » des Configurations permet de
choisir / importer une image (PNG, JPG, WEBP, 8 Mo max) : elle est recadrée en
carré 256 px cÎté client, validée cÎté serveur (data-URL + octets magiques, sans SVG)
et persistée sur le compte (
avatardansdata/users.json, exposĂ© parGET/PATCH /api/auth/meet la rĂ©ponse de login). L'image s'affiche dans le cercle du profil en bas de la sidebar (initiales en repli) et peut ĂȘtre supprimĂ©e. UI : aperçu circulaire avec overlay camĂ©ra au survol, boutons Choisir / Supprimer, erreurs en ligne. ClĂ©s i18n FR/EN.
Modifié
- #113 â ordre des sections Configurations. La TOC et la page sont rĂ©organisĂ©es
dans un ordre naturel et parfaitement synchronisées : Profil en premier,
puis Sécurité, ThÚmes, Recherche, Historique récent, Tags, Fichiers cachés,
Synchronisation, Backend, Diagnostics, IA, Sources connectées, Clés API & MCP,
Push, Webhooks, Partages publics, Plugins et Ă propos en dernier. Les ancres
cfg-tagsetcfg-partages-publicssont désormais portées par leur<section>(cible de défilement = haut de section). Garde-fous : test statiquetests/frontend/settings-order-avatar.test.mjs(ordre TOC = page, pas d'ancre morte).
[2.21.0] â 2026-09-23
Ajouté
- #112 â section compte en bas de la sidebar. L'identitĂ© (avatar avec initiales, nom, rĂŽle) et la dĂ©connexion sont regroupĂ©es dans un bloc Ă©pinglĂ© au bas de la barre latĂ©rale, comme sur les sites professionnels ; un clic sur l'identitĂ© ouvre le Profil. Nouvelle clef i18n FR/EN pour le rĂŽle.
- #112 â pellicule d'images dĂ©filable. La molette de la souris fait dĂ©filer horizontalement la bande de miniatures et deux flĂšches translucides sur les cĂŽtĂ©s (rĂ©vĂ©lĂ©es au survol) remplissent la mĂȘme fonction.
Modifié
- #112 â en-tĂȘte allĂ©gĂ©. La version quitte le header pour le menu Options (ligne « Version ») ; le bouton de dĂ©connexion et le nom de l'utilisateur sont retirĂ©s du header au profit de la section compte de la sidebar. Le header droit ne conserve que l'indicateur hors-ligne, le contexte vault et le bouton Options.
[2.20.0] â 2026-09-23
Ajouté
- #111 â visionneuse d'images : flĂšches latĂ©rales translucides. Deux boutons
superposés le long des bords du cadre passent à l'image précédente/suivante ;
quasi invisibles au repos, ils se révÚlent au survol (et restent visibles sur
les appareils tactiles). Un compteur
n / totalcomplĂšte la barre d'outils.
Modifié
- #111 â navigation d'images fluide. Changer d'image se fait dĂ©sormais en
place (
showSiblingremplace lesrcdu<img>) : plus de rechargement de la vue ni de nouvel appel/api/browseĂ chaque flĂšche, mĂȘme dans un dossier contenant beaucoup d'images. La liste du dossier est mise en cache (TTL court) et les images voisines sont prĂ©chargĂ©es ; la pellicule de miniatures reste visible et la vignette active est simplement re-marquĂ©e. - #111 â image toujours ajustĂ©e au cadre. La visionneuse occupe tout l'espace disponible (zone de contenu en flex, sans dĂ©filement de page) et l'image est systĂ©matiquement redimensionnĂ©e dans son cadre, y compris panneau « MĂ©tadonnĂ©es » ouvert.
[2.19.2] â 2026-09-23
Ajouté
- Lanceur E2E Windows/PowerShell :
scripts/run-e2e-local.ps1(+ script npmtest:e2e:ps) reproduit localement le job CIe2e(uvicorn natif, auth dĂ©sactivĂ©e, fixtures TestVault/TestDir, port 2029, projetchromium-desktop) sans dĂ©pendre debashâ indispensable sur les postes Windows oĂč WSL ne dĂ©marre pas et oĂč git-bash est bloquĂ© par une politique de contrĂŽle d'application. Le scriptbashreste la rĂ©fĂ©rence pour la CI/Linux.
Corrigé
- BUG-072 â visionneuse d'images : le plein Ă©cran (lightbox) et le panneau « MĂ©tadonnĂ©es » sont dĂ©sormais conservĂ©s lors de la navigation entre images (flĂšches â/â et clic sur la pellicule) ; auparavant chaque changement d'image recrĂ©ait la visionneuse et perdait ces Ă©tats. Le panneau de mĂ©tadonnĂ©es s'affiche maintenant en barre latĂ©rale Ă droite de l'image (au lieu d'une bande sous la pellicule) et reste visible en plein Ă©cran.
[2.19.1] â 2026-09-23
Corrigé
- #110 â lisibilitĂ© et positionnement du lecteur mĂ©dia : en mode mobile, la
barre audio passe en grille (barre de progression pleine largeur sur sa propre
ligne) et les actions secondaires (précédent/suivant/agrandir/volume) sont
masquées pour éviter tout chevauchement ; le volume est aussi masqué sur les
écrans intermédiaires en desktop, et
overflow: hiddenempĂȘche le dĂ©bordement hors de la pilule. La mini-fenĂȘtre vidĂ©o n'est plus rĂ©-aimantĂ©e sur les bords : elle se dĂ©place et se redimensionne librement (position absolue mĂ©morisĂ©e, centre autorisĂ©), le glisser fonctionnant dĂ©sormais depuis n'importe quel point de la fenĂȘtre (boutons/curseurs/poignĂ©e exclus, seuil de 4 px pour prĂ©server les contrĂŽles natifs de la vidĂ©o).
[2.19.0] â 2026-09-23
Ajouté
- #110 â Lecteur mĂ©dia persistant « Now Playing » : les fichiers audio et
vidéo continuent de jouer pendant la navigation grùce à un contrÎleur global
frontend/js/now-playing.jsqui possĂšde un seul Ă©lĂ©ment<audio>/<video>tĂ©lĂ©portĂ© entre la vue inline (onglet/panneau) et un dock flottant (<body>), sans interruption de lecture. Dock desktop : pilule verre dĂ©poli (artwork, titre, voĂ»te, play/pause, prĂ©cĂ©dent/suivant, barre de progression, volume, retour au mĂ©dia, agrandir, fermer). Mini-fenĂȘtre vidĂ©o flottante dĂ©plaçable/redimensionnable avec aimantation aux coins et bouton Picture-in-Picture natif. Mode mobile : mini-player fixĂ© au-dessus de la barre d'outils (safe-areaviewport-fit=cover). IntĂ©gration Media Session (Ă©cran verrouillĂ©, touches matĂ©rielles, Windows SMTC), panneau Ă©tendu façon « Now Playing », lecture auto du mĂ©dia suivant/prĂ©cĂ©dent du dossier, reprise aprĂšs rechargement, notification quand l'onglet est fermĂ© pendant la lecture. Fiche : docs/features/media-viewers-109.md (§ Now Playing, #110).
[2.18.0] â 2026-09-23
Ajouté
- #109 â Support audio & vidĂ©o (lecteurs HTML5 intĂ©grĂ©s) : les fichiers audio
(
.mp3 .m4a .aac .wav .ogg .oga .opus .flac) et vidĂ©o (.mp4 .webm .mov .m4v) apparaissent dĂ©sormais dans l'arborescence et l'index (nom/taille/date uniquement, contenu jamais lu, intĂ©grĂ©s ĂSUPPORTED_EXTENSIONSviamedia_types.py). Nouvel endpointGET /api/media/{vault}?path=âŠavec support HTTPRange/206 Partial Content(Content-Range,Accept-Ranges,416sur plage invalide,413au-delĂ deOBSIGATE_MEDIA_MAX_INLINE_MB, dĂ©faut 500 Mo) â le helper Range depdf/streama Ă©tĂ© extrait en_stream_file_with_range()et est partagĂ©.api_file_view()exposeis_audio/is_video/stream_url/media_mimeavant toute lecture texte. Frontend : lecteur audio dĂ©diĂ© (artwork, durĂ©e vialoadedmetadata) et lecteur vidĂ©o (playsinline, scĂšne noire letterboxĂ©e), icĂŽnes Lucideaudio-lines/video, pause Ă la rĂ©initialisation de la vue, repli tĂ©lĂ©chargement si le codec n'est pas lisible ou le fichier trop volumineux. Les mĂ©dias sont exclus du contexte textuel BooksLM et du cache hors-ligne du service worker. Fiche : docs/features/media-viewers-109.md.
[2.17.0] â 2026-09-23
Ajouté
- #108 â Support complet des images (arborescence, visionneuse, indexation) :
les images (
.png .jpg .jpeg .gif .svg .webp .bmp .ico) apparaissent dĂ©sormais dans l'arborescence et l'index comme les autres fichiers â nom/taille/date uniquement, jamais les octets (contenu indexĂ© vide, TF-IDF prĂ©servĂ©). Nouveau module partagĂ©backend/media_types.py(extensions + MIME, socle rĂ©utilisĂ© par #109). Visionneuse dĂ©diĂ©e : zoom molette 0,1Ăâ8Ă, pan au glisser, double-clic pour rĂ©initialiser, boutons +/â/reset et badge de zoom, navigation â/â entre les images du dossier avec pellicule de miniatures, panneau mĂ©tadonnĂ©es (dimensions, taille, type, chemin, date), lightbox plein Ă©cran, « Ouvrir l'original » et tĂ©lĂ©chargement. EndpointGET /api/media/{vault}/thumb(miniature WebP 256 px, cache disque invalidĂ© par mtime, repli sur l'original pour le SVG,pillow>=10.0). Filtreext:png/ext:jpgopĂ©rationnel ; compteurs d'images sĂ©parĂ©s dans/api/dashboard(image_count/total_images). Fiche : docs/features/image-support.md.
Corrigé
- #108-B1 â Affichage isolĂ© d'une image : le
<img>gĂ©nĂ©rĂ© parapi_file_view()pointait vers/api/file/{vault}/raw(qui renvoie du JSON) au lieu de/api/image/{vault}(octets + MIME correct). CorrigĂ© cĂŽtĂ© backend et dansviewer.js(bouton Plein Ă©cran), avec encodage d'URL des chemins. - #108-B3 â XSS via SVG :
/api/image(et le repli miniatures) poseContent-Security-Policy: sandboxsur les SVG ouverts directement, pour empĂȘcher l'exĂ©cution du JavaScript embarquĂ© ; le middleware n'Ă©crase plus une politique stricte posĂ©e par une route.
[2.16.6] â 2026-09-22
Ajouté
- Guides d'utilisation
docs/GUIDES/: nouvel index + 10 guides FR (prise en main, recherche/PDF/Excalidraw, assistant IA & Forge, collaboration temps réel, PWA & hors-ligne, API REST, serveur MCP, authentification & sécurité, déploiement Docker, desktop Tauri). Le guide MCP est déplacé dansdocs/GUIDES/MCP.md;docs/MCP_GUIDE.mddevient une page de redirection.
Modifié
- README.md / README.fr.md : capture d'Ă©cran rĂ©elle de l'application en tĂȘte
(remplace l'illustration ASCII) ; un emoji sur chaque entrée de la table des
matiÚres ; nouvelle section « Guides » avec liens vers
docs/GUIDES/; renvois vers les guides depuis les sections API, Recherche, Sécurité, Desktop et Collaboration.
[2.16.5] â 2026-09-22
Corrigé
- BUG-071 (complément) - spec E2E mobile de la page Configurations :
tests/e2e/config-mobile.spec.js(nouveau, projetchromium-mobile, ignoré enchromium-desktopcommemobile-editor.spec.js) : le hamburger révÚle le sommaire, le choix d'une section y défile + lien actif + repli auto, aucun débordement horizontal à 393px. Vérifié en local contre l'instance de test (port 2029, auth désactivée) : 3/3.
[2.16.4] â 2026-09-22
Corrigé
- BUG-071 - Page « Configurations » inutilisable en mode mobile : trois
causes. (1) Le sommaire (
#config-nav) partageait la rĂšgle.help-navqui le masque sous 768px, mais â contrairement au Guide â la modale n'avait aucun bouton pour l'afficher : aucun moyen d'atteindre une section. Nouvel hamburger#config-hamburgerdans l'en-tĂȘte (mĂȘme traitement.help-hamburgerque le Guide, libellĂ© traduitconfig.toc_toggleFR/EN). (2) Les liens du sommaire Ă©taient des ancres brutes sans JS :config.jsles intercepte dĂ©sormais (dĂ©filement doux vers la section dans la modale, lien actif, repli automatique du sommaire sur mobile, rĂ©init Ă l'ouverture). (3) Les grilles 2 colonnes (fournisseur/modĂšle IA, clĂ©/modĂšle par fournisseur), les rangĂ©es d'ajout Ă largeurs fixes (jetons, webhooks) et les lignes webhook/jeton/partage en flex une ligne dĂ©bordaient en 360px : bloc CSS mobile scopĂ©#config-modal(1 colonne, wrap, largeurs inline neutralisĂ©es, cibles tactiles 44px, sommaire plafonnĂ© Ă 46vh).data-i18n-attraccepte dĂ©sormais plusieurs pairesattr:clĂ©sĂ©parĂ©es par;(titre + aria-label traduits). Tests :tests/frontend/config-mobile.test.mjs(nouveau, 11 â hamburger, i18n, cĂąblage JS, CSS mobile, garde-fou ancres mortes façon BUG-067), enregistrĂ© dans le CI.
[2.16.3] â 2026-09-22
Corrigé
- BUG-070 - Activation clé physique WebAuthn impossible (« Validation du
credential WebAuthn échouée ») : deux causes. (1) Les valeurs par défaut
(
rp_id localhost, origineshttp://localhostsans port) rejetaient toute URL rĂ©elle â logs :Unexpected client data origin "http://localhost:2020", expected one of ['http://localhost'].rp_id/origines sont dĂ©sormais dĂ©rivĂ©s de la requĂȘte (hĂŽte exact, port inclus ;X-Forwarded-Host/ProtosiOBSIGATE_TRUST_PROXY=true), la config explicite restant prioritaire (backend/auth/webauthn_mfa.py::resolve_relying_party, appliquĂ© aux 4 endpoints d'enregistrement et de login). (2) Challenge Ă usage unique fragile au double-clic/retry (challenge was not expected) : les 5 derniers challenges sont conservĂ©s et la vĂ©rification accepte le challenge correspondant Ă la cĂ©rĂ©monie en cours..env.exampledocumente le nouveau comportement. VĂ©rifiĂ© au navigateur avec authentificateur virtuel (Playwright CDP, instance Docker) : enregistrement 200 + clĂ© listĂ©e, puis clĂ© de test retirĂ©e. Tests :tests/test_webauthn.py(+8 : rĂ©solution RP, forwarded, retry, roundtrip sans config).
[2.16.2] â 2026-09-22
Corrigé
- BUG-069 - Login 2FA bloqué sans erreur : aprÚs user+mot de passe corrects
sur un compte avec 2FA, la page de login restait affichée sans erreur et le
challenge MFA n'apparaissait jamais. Cause :
showMfaChallenge(frontend/js/auth.js) montait le challenge dans.login-box, inexistant dansindex.html(marquage rĂ©el :#login-screen > .login-card) âreturnsilencieux. Correctif : montage dans.login-card(repli#login-screen) + erreur visible (mfa.challenge_unavailable, FR/EN) au lieu d'un retour silencieux si le point de montage manque. VĂ©rifiĂ© de bout en bout au navigateur (Playwright, instance Docker) : challenge affichĂ©, code erronĂ© â erreur, code valide â connectĂ©. Tests :tests/frontend/mfa-settings.test.mjs(+2 contrĂŽles d'ancrage DOM).
[2.16.1] â 2026-09-22
Corrigé
- BUG-068 - Configuration : section « đ SĂ©curitĂ© du compte » inachevĂ©e :
boutons
config-btn-primary/config-btn-dangerdĂ©finis depuis les variables du thĂšme (frontend/style.css) ; QR code TOTP gĂ©nĂ©rĂ© en local par le backend (POST /api/auth/mfa/totp/setupâqr_data_url, SVGdata:viasegno,backend/requirements.txt) au lieu de l'image tierce bloquĂ©e par la CSP (img-src 'self' data: blob:, secret TOTP exposĂ©) ; codes de rĂ©cupĂ©ration affichĂ©s aussi Ă la premiĂšre activation WebAuthn ; carte « Mot de passe » (changement viaPOST /api/auth/change-password) et Ă©chappement des libellĂ©s de clĂ©s WebAuthn. Tests :tests/test_mfa.py::test_mfa_setup_returns_local_qr_data_url,tests/frontend/mfa-settings.test.mjs(nouveau, 9 contrĂŽles).
[2.16.0] â 2026-09-22
Modifié
- #86 - Optimisation globale des performances (phase 3) : ferme les deux derniers
points de la phase 3 (recherche via inverted index, PDF lazy et caps regex déjà livrés
via BUG-033/BUG-040/BUG-025). Scan différentiel :
_scan_vaultrĂ©utilise les entrĂ©es inchangĂ©es (size+modified) d'un snapshot prĂ©cĂ©dent â seulsos.walk+stattournent Ă chaque rebuild (build_index,reload_single_vault). Extraction excalidraw diffĂ©rĂ©e : le scan ne lit plus les.excalidraw/.excalidraw.md(flagexcalidraw_text_pending),enrich_pdf_texts()extrait leur texte aprĂšs index comme pour les PDF. Garde-fouMAX_REPLACE_FILE_BYTES(5 Mio) surreplace_in_files. Tests :tests/test_perf_phase3.py(9). Voir docs/features/perf-phase3-86.md.
[2.15.0] â 2026-09-22
Ajouté
- #107 - Configuration : gestion des clĂ©s API & MCP â nouvelle section
« đ ClĂ©s API & MCP » dans le panneau de configuration : crĂ©ation, liste
(créée / expire / derniÚre utilisation) et révocation de jetons longue
durée utilisables aussi bien sur l'API REST que sur le serveur MCP
(
/mcp) â un seul et mĂȘme jeton Bearer pour les deux. Choix d'expiration Ă la crĂ©ation : 1 jour, 1 mois, 6 mois, 1 an, sans fin. Le secret n'est affichĂ© qu'une fois (jamais persistĂ© en clair,data/api_tokens.jsonne contient que les mĂ©tadonnĂ©es) ; rĂ©vocation immĂ©diate des deux cĂŽtĂ©s, plafond 50 clĂ©s par utilisateur, isolation par utilisateur, auditconfig_change. CorrigĂ© au passage : le store de rĂ©vocation (revoked_tokens.json) bornait toute entrĂ©e Ă 7 jours â un jeton longue durĂ©e rĂ©voquĂ© « reprenait vie » aprĂšs purge ; il est dĂ©sormais calĂ© sur l'expiration rĂ©elle du jeton. Voir docs/features/api-mcp-tokens-107.md.
[2.14.1] â 2026-09-22
[2.14.0] â 2026-09-19
Ajouté
- #106 - Assistant IA : actions instantanées contextuelles + catalogue de prompts :
la zone d'accueil remplace les 3 suggestions statiques par des actions suggérées
selon le contexte dĂ©tectĂ© (sĂ©lection dans l'Ă©diteur â concis/corriger/expliquer ;
fichier de code â expliquer/bugs/tests ; 2+ docs â fusionner/comparer/frictions ;
1 doc â rĂ©sumĂ© 3 points/checklist/frontmatter ; rĂ©pertoire ou gĂ©nĂ©ral sinon), avec
badge de contexte dans l'en-tĂȘte. Un bouton « Toutes les actions » ouvre un
tiroir catalogue (recherche instantanée, 6 catégories, 25 actions i18n FR/EN).
Nouveau prompt « Générer le frontmatter YAML » au format complet du vault
(titre, auteur, dates ISO-8601, tags, aliases, booléens, NomDeVoute, Description)
et « Mettre à jour le frontmatter » (conserve les champs existants, actualise
modification_date, recalcule tags/aliases/Description, complĂšte les manquants) â tous deux basculent en mode agent et appliquent le rĂ©sultat via la carte de confirmation. DĂ©tail : features/ai-quick-actions.md.
[2.13.1] â 2026-09-18
[2.13.0] â 2026-09-18
Ajouté
- #105 - Guide d'utilisation : audit de couverture, téléchargement Markdown/PDF,
section Architecture : le guide intégré est aligné sur l'application réelle aprÚs
~35 features livrĂ©es. Huit nouvelles sections â đïž Architecture (diagramme Mermaid
des grandes composantes : clients SPA/PWA/Tauri â serveur FastAPI REST, index de
recherche, rendu markdown, IA, MCP, WebSocket, webhooks â vaults,
data/*.json, backups), đ Diagrammes (Mermaid : zoom, plein Ă©cran, copie SVG/code, thĂšmes), â BibliothĂšque (signets, recherches sauvegardĂ©es, backlinks & graphe, conflits Syncthing, piĂšces jointes), đŽ Hors-ligne (PWA, file d'attente IndexedDB, replay, watcher), đ„ Collaboration (Yjs/CRDT, curseurs awareness), đ„ïž Desktop (Tauri, updater signĂ©, assistant premier lancement), đ API (OpenAPI 3.1 :/docs,/redoc,/api,/openapi.json, auth Bearer/cookie, serveur MCP, automatisation) et đ Multilingue â plus des complĂ©ments dans les sections existantes (recherche sĂ©mantique hybride, notifications web push, export PDF, export HTML/ePub/ZIP, anti-doublons d'upload, vue multi-panneaux, MFA TOTP/WebAuthn, tableau de bord admin). NouveauGET /api/guide/download?format=md|pdf&lang=fr|en(tag OpenAPI « Guide ») : le document est gĂ©nĂ©rĂ© depuis la modale d'aide rĂ©elle et les locales, il reflĂšte donc exactement le guide affichĂ©, dans la langue de l'utilisateur ; boutons Markdown et PDF ajoutĂ©s dans l'en-tĂȘte du guide. En desktop (Tauri,body.desktop-mode) et sur grand Ă©cran web, le guide s'Ă©largit (conteneur jusqu'Ă 1760 px, contenu 1280â1440 px) pour une lecture confortable. Source de vĂ©ritĂ© du nouveau contenu :scripts/guide_content.py(locales gĂ©nĂ©rĂ©es, jamais Ă©ditĂ©es Ă la main). Tests :tests/test_guide.py(11).
Modifié (ajustements retour utilisateur sur #105)
- Boutons de téléchargement du guide : icÎnes seules (plus de libellé « Markdown »/ « PDF »), tooltip i18n explicite sur chaque bouton.
- PDF du guide : le bloc Mermaid de la section Architecture est converti en diagramme
rendu (PNG pré-rendu commité via
scripts/build_guide_diagrams.py+scripts/render_guide_diagram.mjs, insĂ©rĂ© pardiagram_png_for()), au lieu du code brut ; le Markdown garde le fenced```mermaid(copiable). - PDF du guide : emoji rendus en couleur au lieu de rectangles â
fonts-noto-color-emojiajouté à l'image Docker et"Noto Color Emoji"en fin de pile de polices du PDF (la TOC était correcte car elle utilise DejaVu, qui n'a pas les emoji pleine chasse).
Corrigé
- BUG-067 - Guide : entrĂ©e « đ± Mobile » morte : le sommaire pointait vers
#help-mobile-editor, section inexistante (l'Ă©dition mobile n'Ă©tait qu'un<h3>de la section Ădition). Le bloc est devenu une section dĂ©diĂ©e ancrĂ©e ; l'ancre#help-ia(Ă©galement morte) a Ă©tĂ© corrigĂ©e en#help-aiet un attributdata-i18n-placeholderdupliquĂ© nettoyĂ©. Garde-fou :test_guide_nav_has_no_dead_anchors.
[2.12.2] â 2026-09-18
Corrigé
- BUG-066 â Configuration : icĂŽnes manquantes dans la table des matiĂšres :
les entrées « Fichiers cachés » et « Partages publics » du sommaire de la page de
configuration n'affichaient pas d'icĂŽne (les titres de section, eux, en avaient une).
Les libellés i18n
config.section_hidden(đïž) etconfig.section_shares(đ€) sont alignĂ©s sur leurs titres de section, en FR et EN. Test de non-rĂ©gression ajoutĂ© danstests/frontend/unit.test.mjs(toutes les entrĂ©es du sommaire doivent porter une icĂŽne dans les deux langues).
[2.12.1] â 2026-09-18
[2.12.0] â 2026-09-18
Ajouté
- #104 - Configuration : redesign UI de la section « đ€ ClĂ©s API Intelligence Artificielle » :
la longue liste plate de champs devient une interface structurĂ©e et dĂ©pliable â
- En-tĂȘte de section : titre + sous-titre explicatifs et une barre de recherche
(
#cfg-ai-search) pour filtrer les fournisseurs (normalisée, insensible à la casse et aux accents), avec état vide « Aucun fournisseur ne correspond ». - Carte « Configuration par défaut » visuellement distincte : grille 2 colonnes
fournisseur / modÚle par défaut, et capacités du modÚle rendues en badges colorés
(nouveau
renderCapabilityBadges()dansfrontend/js/ai.js, uniquement les capacités actives) au lieu des cases à cocher. - Fournisseurs d'API en cartes dépliables (rendu dynamique depuis
AI_PROVIDER_NAMESpar_renderAIProviderCards(),frontend/js/config.js) : Ă©tat repliĂ© = logo (initiale), nom, badge de statut (« ConfigurĂ© » vert / « Non configurĂ© » gris) et corbeille discrĂšte pour supprimer la clĂ© (visible uniquement si configurĂ©e, confirmation conservĂ©e) ; Ă©tat dĂ©pliĂ© = libellĂ©s au-dessus des champs, API key Ă 60 % / modĂšle Ă 40 % (grille3fr 2fr). Les boutons « ConfigurĂ©/Supprimer » redondants Ă l'intĂ©rieur des champs disparaissent â le statut vit dĂ©sormais uniquement dans l'en-tĂȘte de la carte. - Barre d'actions : « Sauvegarder » (primaire) et « Tester » (outline) dans un footer
sticky en bas de section, toujours accessible pendant le défilement, avec le statut de
test à cÎté.
Styles
.ai-keys-*/.ai-provider-*en variables CSS (profondeur fond/carte, espacement gĂ©nĂ©reux, chevron animĂ©, focus visible, responsive 1 colonne < 600 px) ; textes i18n FR/EN (config.ai_*). Les ID d'Ă©lĂ©ments (cfg-<provider>-key/model/badge/delete) et le comportement de sauvegarde/test/suppression restent inchangĂ©s (rĂ©trocompatible pickers IA). Tests :tests/frontend/config-ai-keys.test.mjs(7 â rendu, badges, bascule, filtre, save, suppression, badges de capacitĂ©s).
- En-tĂȘte de section : titre + sous-titre explicatifs et une barre de recherche
(
[2.11.6] â 2026-09-18
Corrigé
- BUG-064 - Ăditeur Excalidraw : le diagramme ne s'affiche jamais (canvas vide) â deux
causes cumulées :
- La feuille de style d'Excalidraw n'était jamais chargée (
@excalidraw/excalidrawexige un import CSS explicite). Sans elle, l'Ă©diteur est non stylisĂ© et.excalidrawn'a aucune hauteur fixe : la boucle de redimensionnement d'Excalidraw fait grossir le canvas jusqu'au plafond codĂ© en dur de2^25(33 554 432 px), que le navigateur ne peut pas dessiner â scĂšne blanche. Correctifs :<link>versâŠ/@excalidraw/[email protected]/dist/prod/index.cssdansfrontend/excalidraw-editor.htmlet ajout dehttps://esm.shĂstyle-srcde la CSP (backend/main.py). appState.collaboratorsest uneMapsĂ©rialisĂ©e en objet JSON ({}) par l'app Excalidraw / le plugin Obsidian ; rĂ©injectĂ©e viainitialData, Excalidraw 0.18 appelait.forEach()dessus et plantait (e.appState.collaborators.forEach is not a function).sanitizeAppState()la reconvertit enMapet Ă©carte la gĂ©omĂ©trie de viewport importĂ©e (width,height,offsetLeft,offsetTop) pour les deux formats (.excalidrawet.excalidraw.md). Tests de non-rĂ©gression :tests/frontend/excalidraw-viewer.test.mjs(CSS liĂ© + CSP),tests/test_security_hardening.py::TestCspExcalidrawStylesheet,tests/e2e/excalidraw.spec.js(hauteur de canvas bornĂ©e) + fixturestest_vault/diagram-app-export.excalidraw.
- La feuille de style d'Excalidraw n'était jamais chargée (
- BUG-064 (complĂ©ment) - Ăditeur Excalidraw : pleine largeur quand la navigation est masquĂ©e :
la rĂšgle
.sidebar.hidden ~ .content-wrapper .content-area { max-width: 1200px }(colonne de lecture centrée) s'appliquait aussi au viewer Excalidraw. Ajout de.content-area:has(iframe[src*="excalidraw-editor.html"])enmax-width: none; margin: 0, comme pour les viewers PDF/image (BUG-062). Fichier :frontend/style.css. - BUG-065 - Excalidraw : l'auto-save rechargeait la page en pleine édition : chaque
modification déclenchait, 2 s plus tard, un
PUT /api/file/âŠ/save; l'Ă©criture Ă©mettaitindex_updated(SSE) qui re-rendait la vue et recrĂ©ait l'iframe â un refresh visible qui interrompait le dessin. L'auto-save est supprimĂ©e (frontend/js/excalidraw-viewer.js) : sauvegarde explicite par le bouton « đŸ Save » ouCtrl+S. En complĂ©ment,reloadExternalWritene re-rend plus la vue quand un iframe Excalidraw est dĂ©jĂ ouvert sur le fichier (iframe[data-excalidraw-*]), et le badge « Modified » ne se dĂ©clenche plus sur les changements d'appState(resize, zoom) mais uniquement sur le contenu (signature des Ă©lĂ©ments). - #78 (complĂ©ment) - Bouton plein Ă©cran pour les diagrammes Excalidraw : nouveau bouton
#btn-fullscreendans la barre d'outils de l'éditeur (frontend/excalidraw-editor.html) qui bascule le mode plein écran natif ; l'iframe est créée avecallow="fullscreen" allowfullscreen(frontend/js/excalidraw-viewer.js). Fichiers :frontend/excalidraw-editor.html,frontend/js/excalidraw-viewer.js,tests/frontend/excalidraw-viewer.test.mjs. - #78 (complément) - Barre d'outils Excalidraw en icÎnes, verticale à droite : les boutons
Save / PNG / SVG / plein Ă©cran passent en icĂŽnes seules (34Ă34 px) dans une colonne
collée au bord droit (
right: 0), dĂ©butant Ă45%de la hauteur, empilĂ©e verticalement, avec infobulles etaria-label. L'icĂŽne du bouton Save devient une coche aprĂšs une sauvegarde rĂ©ussie. Fichier :frontend/excalidraw-editor.html.
[2.11.5] â 2026-09-17
Corrigé
- BUG-063 (complĂ©ment) â Viewer PDF : la table des matiĂšres ne dĂ©plaçait toujours pas la
page : le premier correctif réassignait
iframe.srcavec le seul fragment#page=N, ce qui ne change que le fragment â navigation same-document que le lecteur PDF natif ignore (il n'applique#page=Nqu'au chargement). Diagnostic en Chrome headful par comparaison de captures.navigatePdfToPage()ajoute dĂ©sormais un paramĂštre de query horodatĂ© (&_pdfpage=<ts>#page=N) pour forcer un vrai rechargement de l'iframe. Fichiers :frontend/js/viewer.js,tests/frontend/pdf-viewer.test.mjs,tests/e2e/pdf-viewer.spec.js.
[2.11.4] â 2026-09-17
Corrigé
- BUG-061 â Assistant IA : le bouton « Plein Ă©cran » n'agrandissait plus le panneau : la
largeur du panneau est écrite en style inline par la poignée de redimensionnement (et par la
largeur persistée en
localStorage) ; cet inline l'emportait sur la rĂšgle.bookslm-panel.fullscreen { width: 100vw }, donc le panneau restait Ă sa largeur courante. La rĂšgle plein Ă©cran est dĂ©sormais prioritaire (!important). Fichier :frontend/style.css. - BUG-062 â Viewer PDF : largeur incomplĂšte quand la navigation est masquĂ©e : la rĂšgle de
colonne de lecture centrée (
.sidebar.hidden ⊠{ max-width: 1200px }) s'appliquait aussi aux viewers plein cadre. Les conteneurs PDF et image sont maintenant exemptĂ©s (:has(.pdf-viewer-container)/:has(.image-viewer-container)âmax-width: none). Fichier :frontend/style.css. - BUG-063 â Viewer PDF : la table des matiĂšres ne naviguait pas : les liens faisaient
contentWindow.location.hash = 'page=N', mais le lecteur PDF natif vit dans une fenĂȘtreabout:blanket l'affectation n'atteignait jamais le document. Nouveau helpernavigatePdfToPage()qui recharge l'iframe avec le fragment#page=N; les entrĂ©es portent undata-pageet sont cĂąblĂ©es par des Ă©couteurs (plus d'onclickinline). Fichiers :frontend/js/viewer.js,frontend/style.css. - Tests :
tests/frontend/ai.test.mjs(+1),tests/frontend/pdf-viewer.test.mjs(TOC, plein largeur),tests/e2e/pdf-viewer.spec.js(TOC#page=N, largeur, fixturetest_vault/sample-pdf-toc.pdf).
[2.11.3] â 2026-09-17
Corrigé
- BUG-035 â
secret_redactor: faux positifs sur les hashs hex : la rĂšgle qui masquait tout jeton hexadĂ©cimal de 40 Ă 64 caractĂšres mutilait les hashs git/SHA lĂ©gitimes des notes. Le masquage des chaĂźnes hexadĂ©cimales n'a dĂ©sormais lieu que si un mot-clĂ© de secret (secret,token,key,password,bearerâŠ) figure dans les 60 caractĂšres prĂ©cĂ©dents ; un contexte de hash (commit,sha256,hash,checksum,git,etagâŠ) exempte explicitement la chaĂźne. Fichier :backend/secret_redactor.py. - BUG-036 â Collaboration WebSocket : jeton acceptĂ© en query string : le JWT n'est plus lu
depuis
?token=(URLs journalisĂ©es par les proxies et l'historique navigateur). Le cookie HttpOnlyaccess_token, envoyĂ© automatiquement par le navigateur lors du handshake same-origin, est le seul transport supportĂ© ; les trames brutes dĂ©passantMAX_MESSAGE_CHARS(16 Mio) sont rejetĂ©es avant analyse. Fichier :backend/collab.py. - BUG-037 â Mode sans authentification : au dĂ©marrage, un avertissement explicite est
journalisé quand
OBSIGATE_AUTH_ENABLED=false. Le serveur refuse dĂ©sormais de dĂ©marrer s'il est liĂ© Ă une adresse non-loopback sans l'opt-in expliciteOBSIGATE_ALLOW_INSECURE=true, pour empĂȘcher l'exposition publique d'une instance sans authentification (admin anonyme). Fichiers :backend/auth/middleware.py,backend/main.py. - BUG-038 â Argon2 : coĂ»t mĂ©moire recalibrĂ© :
memory_costpasse de 64 Mio Ă 19 Mio (m=19456 Kio, t=2, p=1, recommandation OWASP actuelle) pour supprimer le risque d'Ă©puisement mĂ©moire sous connexions simultanĂ©es ; les anciens hachages restent valides et sont migrĂ©s automatiquement (needs_rehash). Fichier :backend/auth/password.py. - BUG-039 â ĂnumĂ©ration de comptes au login : les comptes inconnus, dĂ©sactivĂ©s, verrouillĂ©s
et limités par le budget par compte répondent tous un
401 Identifiants invalidesavec un temps Ă©quivalent (hachage factice), au lieu d'un429/403distinctif ; seul le rate-limit par IP (non liĂ© Ă un compte) conserve le429. Fichier :backend/auth/router.py. - BUG-040 â Extraction PDF diffĂ©rĂ©e au scan :
_scan_vaultne lit plus que les mĂ©tadonnĂ©es des PDF ; l'extraction de texte intĂ©grale (100 kio) est dĂ©lĂ©guĂ©e Ăenrich_pdf_texts(), exĂ©cutĂ©e aprĂšs la construction de l'index/inverted index (dĂ©marrage) et aprĂšs chaque rĂ©indexation. Un vault contenant de nombreux/gros PDF dĂ©marre sans ĂȘtre bloquĂ© ; le texte reste recherchable une fois l'enrichissement terminĂ©. Fichiers :backend/indexer.py,backend/main.py. - Tests :
tests/test_api_main.py(redactor hex),tests/test_auth.py(coût Argon2, garde-fou d'instance non authentifiée),tests/test_auth_api.py(login uniforme),tests/test_collab.py(jeton query rejeté, trame surdimensionnée),tests/test_pdf.py(scan différé + enrichissement).
[2.11.2] â 2026-09-17
Modifié
- Tests E2E PDF (BUG-060) : le helper d'ouverture de fichier de
tests/e2e/pdf-viewer.spec.jsétend désormais le vault dans l'arborescence s'il est replié (cas d'une instance avec authentification activée) au lieu de supposer le vault déjà déplié.
[2.11.1] â 2026-09-17
Corrigé
- BUG-060 â Viewer PDF : l'affichage des pages ne fonctionnait pas : au clic sur un fichier
.pdf, seule la barre d'outils « PDF â N pages » s'affichait, le corps restant vide. La CSP durcie en BUG-034 poseobject-src 'none', directive qui gouverne<embed>/<object>, alors que le viewer rendait le PDF via<embed type="application/pdf">: le lecteur natif Ă©tait bloquĂ©. Le rendu passe dĂ©sormais par une<iframe>(autorisĂ©e parframe-src 'self', le stream/api/file/{vault}/pdf/streamĂ©tant same-origin) ;object-src 'none'est conservĂ©. Fichiers :frontend/js/viewer.js,tests/frontend/pdf-viewer.test.mjs(nouveau),tests/e2e/pdf-viewer.spec.js(nouveau, fixturetest_vault/sample-pdf.pdf).
[2.11.0] â 2026-09-17
Ajouté
- #103 â ClĂ©s des sources connectĂ©es configurables depuis la page Configurations : nouvelle
section « đ Sources connectĂ©es & recherche » (admin) permettant de saisir ses propres jetons
sans toucher aux variables d'environnement : clés de recherche web à clé (Tavily, Brave,
SerpAPI, Exa), URL Gitea + token, token GitHub. Stockage dans
data/api_keys.json(mĂȘme fichier que les clĂ©s des fournisseurs IA) via les endpointsGET/POST/DELETE /api/config/tool-keys(GET masque les secrets, URLs en clair ; liste blanche stricte ; admin requis). Les outils lisent la valeur stockĂ©e en prioritĂ© puis l'environnement (Infisical) âbackend/tools/secrets.py. Fichiers :backend/tools/{secrets,web,connected}.py,backend/main.py,frontend/index.html,frontend/js/config.js,frontend/locales/{fr,en}.json,tests/test_tool_keys.py(nouveau),tests/test_connected_tools.py.
[2.10.1] â 2026-09-17
Corrigé
- BUG-059 â Assistant IA : un clic dans la conversation faisait sauter le texte au bas de la
fenĂȘtre : dans une conversation ouverte (post ancrĂ© en haut), tout clic â lien de fichier,
Ă©tapes, sĂ©lection de texte â dĂ©pinait l'ancre via le gestionnaire
mousedownet retirait le padding d'ancre, bornant le scroll Ă la nouvelle hauteur max (saut au bas). Le dĂ©pintage est dĂ©sormais rĂ©servĂ© aux vrais gestes de scroll : molette, tactile et poignĂ©e de scroll uniquement (isScrollbarPress). Fichiers :frontend/js/bookslm.js,tests/frontend/ai.test.mjs. - #92 â
create_pdfde l'Assistant : tableaux mal formatĂ©s : l'outilcreate_pdf(gĂ©nĂ©ration PDF via l'assistant) utilisait un rendu reportlab simplifiĂ© sans support des tableaux. Il passe dĂ©sormais par le mĂȘme pipeline que le bouton « TĂ©lĂ©charger PDF » de la page document (mistune + plugintable+ WeasyPrint), avec repli automatique sur le rendu simple si WeasyPrint n'est pas disponible (GTK absent). Fichiers :backend/tools/documents.py,tests/test_document_tools.py.
[2.10.0] â 2026-09-17
Ajouté
- #92 â Assistant IA : Ă©cosystĂšme d'outils phase 2 (web Ă©tendu, sources connectĂ©es, documents) :
- Recherche web Ă clĂ© : fournisseurs optionnels essayĂ©s avant SearXNG â Tavily, Brave
Search, SerpAPI (Google) et Exa (
OBSIGATE_TAVILY_API_KEY,OBSIGATE_BRAVE_API_KEY,OBSIGATE_SERPAPI_API_KEY,OBSIGATE_EXA_API_KEY), avec ordre personnalisable viaOBSIGATE_WEB_PROVIDERS. - Transverse : réessais réseau avec backoff maison (
OBSIGATE_WEB_RETRY) et cache SQLite des résultats web avec TTL (OBSIGATE_WEB_CACHE_TTL, 900 s par défaut,OBSIGATE_WEB_CACHE_PATH). - Rendu dynamique :
fetch_url(render=True)délÚgue les pages SPA à un worker Playwright isolé (dépendance optionnelle, dégradation propre si non installée). - Crawl de site :
crawl_site(WRITE, confirmation) capture jusqu'Ă 20 pages d'un mĂȘme hĂŽte et enregistre un condensĂ© Markdown dans un vault. - Sources connectĂ©es : Gitea (
OBSIGATE_GITEA_URL/OBSIGATE_GITEA_TOKEN) et GitHub (OBSIGATE_GITHUB_TOKEN) âgit_list_repos,git_search_issues,git_get_file(READ, rate-limitĂ©s, auditĂ©s). Les drives cloud (Google Drive / OneDrive) restent orientĂ©s serveur MCP externe (#79), conformĂ©ment Ă la feuille de route. - Production de documents :
create_xlsx(openpyxl),create_docx(python-docx),create_csv,create_pdf(reportlab) â outils WRITE avec confirmation et sauvegarde dans le vault (backup avant Ă©crasement). - Chaque outil : libellĂ©
labels.py+ clés i18nai.step.*FR/EN + tests unitaires mockés (httpx). Dépendances ajoutées :openpyxl,python-docx,reportlab. Fichiers :backend/tools/{webcache,webrender,connected,crawler,documents,web,schemas,labels}.py,backend/services/mutations.py,tests/test_{web_cache,web_search_providers,webrender,connected_tools,document_tools,crawler}.py.
- Recherche web Ă clĂ© : fournisseurs optionnels essayĂ©s avant SearXNG â Tavily, Brave
Search, SerpAPI (Google) et Exa (
[2.9.1] â 2026-09-17
Corrigé
- BUG-058 â Ăditeur « Editer » : la barre de numĂ©rotation de ligne ne suit pas le thĂšme :
CodeMirror peint son gutter (colonne des numéros de ligne) avec des valeurs claires codées
en dur (
#f5f5f5, bordure#ddd), si bien qu'en thĂšme sombre la barre restait gris clair alors que le fond de l'Ă©diteur suivait le thĂšme. Le gutter est dĂ©sormais dĂ©rivĂ© des variables CSS du thĂšme ObsiGate (color-mix(in srgb, var(--text-primary) âŠ)pour un fond subtil,--text-secondarypour les numĂ©ros,--borderpour la sĂ©paration), ce qui le fait suivre tous les thĂšmes et modes (sombre, clair, contraste Ă©levĂ©, sĂ©pia). Fichiers :frontend/style.css. Tests :tests/frontend/editor-inline.test.mjs.
[2.9.0] â 2026-09-17
Ajouté
- #102 â Assistant IA : bouton « Ajouter la section » par bloc de code : chaque bloc
de code d'une réponse de l'assistant (par ex. une section
markdown) affiche un bouton discret « Ajouter la section » qui insÚre uniquement ce bloc dans le document ouvert (sans les délimiteurs de code), au lieu de la réponse complÚte. Fichiers :frontend/js/bookslm.js,frontend/style.css,frontend/locales/{fr,en}.json. Tests :tests/frontend/ai.test.mjs.
Corrigé
- BUG-057 â Assistant IA : bouton « Ajouter » inopĂ©rant dans l'Ă©diteur Forge : le
bouton ne ciblait que
state.editorView(CodeMirror de « Editer ») et affichait « Aucun document ouvert dans l'Ă©diteur » en Forge._insertIntoEditor()prend dĂ©sormais en charge les trois surfaces : CodeMirror, l'iframe Forge (dĂ©lĂ©gation parpostMessage({ type: 'parent-insert' })âinsertAtCursordanseditor-poc.html) et le textarea de repli. Fichiers :frontend/js/bookslm.js,frontend/editor-poc.html. Tests :tests/frontend/ai.test.mjs,tests/frontend/editor-inline.test.mjs.
[2.8.4] â 2026-09-17
[2.8.3] â 2026-09-17
Corrigé
- BUG-056 - Ăditeur Forge en plein Ă©cran : l'Assistant IA s'ouvre en arriĂšre-plan :
le panneau de l'assistant est monté dans le document parent, alors que le plein écran
Forge porte sur l'iframe â l'API Fullscreen n'affichant que l'Ă©lĂ©ment plein Ă©cran et ses
descendants, le panneau restait invisible. Le plein écran est désormais quitté avant
d'ouvrir le panneau : cÎté parent (
sync.js, surforge-open-aiâ le plein Ă©cran peut appartenir au document parent et non Ă l'iframe) et cĂŽtĂ© iframe (editor-poc.html,openAssistant), la demande d'ouverture Ă©tant Ă©mise une fois la sortie effective. Fichiers :frontend/editor-poc.html,frontend/js/sync.js. Tests :tests/frontend/forge-completion.test.mjs(+1),tests/frontend/editor-inline.test.mjs(+1).
[2.8.2] â 2026-09-17
Corrigé
- BUG-055 (complĂ©ment) - Ăditeur Forge : une complĂ©tion acceptĂ©e au
TabĂ©tait supprimĂ©e 1â2 s plus tard : l'auto-sauvegarde (2 s) dĂ©clenche un Ă©vĂ©nement SSEindex_updatedsur le fichier en cours, et le parent rechargeait alors le tampon de Forge depuis le disque â Ă©crasant une complĂ©tion (ou toute frappe) faite aprĂšs la sauvegarde. Le rechargement SSE est dĂ©sormais ignorĂ© tant que le tampon local est modifiĂ© (isDirty) ; seul un Ă©crit externe (assistant IA) force le rechargement. L'auto-sauvegarde ne repasse plus l'Ă©tat « enregistrĂ© » si des modifications sont arrivĂ©es pendant la requĂȘte (Forge et Ă©diteur CodeMirror), et l'acceptation du ghost annule la requĂȘte de prĂ©diction en attente. Fichiers :frontend/editor-poc.html,frontend/js/utils.js. Tests :tests/frontend/forge-completion.test.mjs(+3),tests/frontend/editor-inline.test.mjs(+1).
[2.8.1] â 2026-09-17
Corrigé
- BUG-055 - Ăditeur Forge : autocomplĂ©tion Tab naturelle et fiable : la touche
TabdĂ©clenchait simultanĂ©ment trois actions indĂ©pendantes (indentation, complĂ©tion d'un mot du document, acceptation de la prĂ©diction IA), ce qui insĂ©rait un ou deux espaces avant le mot complĂ©tĂ© â et le retour arriĂšre effaçait alors l'ajout. La gestion deTabest dĂ©sormais unifiĂ©e avec une prioritĂ© claire (liste de suggestions ouverte â prĂ©diction IA â complĂ©tion de mot du document â indentation), une seule action par appui. Les helpers de complĂ©tion sont extraits en fonctions pures partagĂ©es avec CodeMirror (getWordFragment,findWordCompletions,normalizeGhost,chooseTabAction) ; plusieurs candidats affichent une liste positionnĂ©e au curseur ; la complĂ©tion fantĂŽme n'affiche plus un miroir transparent de tout le document (source du dĂ©calage visuel et des espaces fantĂŽmes) mais uniquement la prĂ©diction, positionnĂ©e exactement au curseur et nettoyĂ©e dĂšs que le curseur bouge ou que la vue dĂ©file ; une complĂ©tion de mot ne peut plus introduire d'espace. Le prompt/api/ai/inline-completeest simplifiĂ© et bornĂ© Ă 128 tokens pour des suggestions plus courtes et plus rapides. Fichiers :frontend/editor-poc.html,frontend/js/autocomplete.js,backend/ai.py. Tests :tests/frontend/forge-completion.test.mjs(nouveau, 28 tests).
[2.8.0] â 2026-09-17
Ajouté
- #101 - Forge : Assistant IA partagé et plein écran (Forge & Editer) : le bouton
« AI Panel » de Forge ouvre désormais le panneau Assistant IA existant (barre latérale)
au lieu d'un mini-chat isolĂ© â mĂȘme contenu, mĂȘme fournisseur/modĂšle, mĂȘme historique, mĂȘmes
menus
/et@, sans duplication. Forge lit la sĂ©lection du sĂ©lecteur de l'assistant (localStorage['obsigate_ai_picker'], mĂȘme origine) et l'injecte dans ses appels/api/ai/*et sa complĂ©tion fantĂŽme (repliollamasi aucun fournisseur choisi) ; au passage, les endpoints erronĂ©s sont corrigĂ©s (make-longer/make-shorter,target_lang). Un bouton plein Ă©cran natif est ajoutĂ© Ă Forge (iframeallow="fullscreen") et Ă l'Ă©diteur Editer (plein Ă©cran sur le conteneur, fonctionne en modale comme en inline, sortie Ă la fermeture). LibellĂ©s i18n FR/EN. Fichiers :frontend/editor-poc.html,frontend/js/sync.js,frontend/js/viewer.js,frontend/js/utils.js,frontend/index.html,frontend/style.css,frontend/locales/{fr,en}.json. Tests :tests/frontend/editor-inline.test.mjs(+10).
[2.7.5] â 2026-09-17
Corrigé
- BUG-054 - Ăditeur « Editer » : le bouton Sauvegarder restait bloquĂ© sur le spinner de
chargement : le bouton
#editor-saveest un nĆud DOM partagĂ© entre toutes les sessions d'Ă©dition (y compris en mode en ligne). Une sauvegarde manuelle y remplaçait le crochet par un spinner et le dĂ©sactivait, mais cet Ă©tat n'Ă©tait jamais remis Ă zĂ©ro : aprĂšs une sauvegarde rĂ©ussie (l'Ă©diteur se ferme puis se rouvre), aprĂšs une sauvegarde Forge, ou aprĂšs un Ă©chec de requĂȘte (lecatchne restaurait ni l'icĂŽne ni l'Ă©tat), le spinner persistait jusqu'Ă un rechargement complet de la page. Un helperresetSaveButton()restaure dĂ©sormais le crochet et rĂ©active le bouton Ă l'ouverture (openEditor), Ă la fermeture (closeEditor) et en cas d'Ă©chec (saveFile). Fichier :frontend/js/utils.js. Tests :tests/frontend/editor-inline.test.mjs(+4).
[2.7.4] â 2026-09-17
Corrigé
- BUG-053 - Assistant IA (mode agent) : le fichier demandé n'est pas créé : le prompt
systÚme du mode Général (et du dossier vide) enseignait encore le protocole texte
obsigate-action, si bien que le modĂšle dĂ©crivait l'action dans un bloc texte au lieu d'appeler l'outil natifcreate_fileâ rien n'Ă©tait donc créé (et le bloc, volumineux, Ă©tait tronquĂ© avant sa fermeture). En mode agent, le prompt demande dĂ©sormais d'appeler directement les outils natifs (create_file,create_directory, âŠ) et interdit les blocsobsigate-action; le chat classique conserve le protocole texte. La limite de sortie de l'agent passe Ă 8 192 jetons pour laisser place au contenu complet d'un fichier. Fichiers :backend/bookslm.py,backend/bookslm_routes.py. Tests :tests/test_bookslm.py(+3).
[2.7.3] â 2026-09-16
Corrigé
- BUG-052 - Assistant IA : recherche web sans réponse finale (étapes et sources affichées, aucun texte) :
quand le budget d'itérations (
DEFAULT_MAX_ITERATIONS = 10) ou le quota d'appels d'outils Ă©tait Ă©puisĂ© pendant que le modĂšle enchaĂźnait encore des recherches/lectures, la boucle d'agent renvoyait un contenu vide â la conversation n'affichait que les Ă©tapes et les sources. La boucle effectue dĂ©sormais un dernier appel sans outil qui demande au modĂšle de synthĂ©tiser les informations recueillies (_finalize_answer), avec un repli dĂ©terministe listant les sources si cet appel Ă©choue ou reste vide. Les appels d'outils non atteints du lot en cours de quota reçoivent un rĂ©sultatdeferredpour garder la conversation valide. Fichier :backend/agent/loop.py. Tests :tests/test_agent_loop.py(+2).
[2.7.2] â 2026-09-16
Corrigé
- BUG-051 (complĂ©ment) - Repli Bing : en-tĂȘtes de navigation navigateur : un
User-Agentnavigateur seul ne suffit pas â Bing renvoie des rĂ©sultats factices (SERP sans rapport avec la requĂȘte) aux appels dĂ©pourvus des en-tĂȘtes de navigation habituels. Les fournisseurs HTML (DuckDuckGo, Bing) envoient dĂ©sormaisAccept-Language,Sec-Fetch-*etUpgrade-Insecure-Requests(BROWSER_HEADERS). VĂ©rifiĂ© en conteneur : recherche « Canadien de MontrĂ©al 2026-2027 » â rĂ©sultats NHL / RDS / WikipĂ©dia pertinents (provider: bing). Fichier :backend/tools/web.py.
[2.7.1] â 2026-09-16
Corrigé
- BUG-051 - Assistant IA : « je ne peux pas accéder à internet » malgré la recherche web :
lorsque l'instance SearXNG auto-hébergée ne remontait aucun résultat (moteurs amont
suspendus/CAPTCHA),
web_searchrenvoyait une liste vide et le modĂšle concluait Ă une absence d'accĂšs rĂ©seau. L'outil essaie dĂ©sormais une chaĂźne de repli sans clĂ© â SearXNG, puis DuckDuckGo (endpoint HTML sans JS), puis Bing (page de rĂ©sultats HTML) â et ne s'arrĂȘte qu'au premier fournisseur qui renvoie des rĂ©sultats (providerdans le rĂ©sultat,OBSIGATE_WEB_FALLBACK=0pour dĂ©sactiver les replis). Le message d'avertissement final nomme les fournisseurs essayĂ©s. Fichier :backend/tools/web.py. Tests :tests/test_web_tools.py(+4).
[2.7.0] â 2026-09-16
Ajouté
- Assistant IA â 30 skills intĂ©grĂ©s (au lieu de 11) et prompts enrichis : les skills
déclenchés par
/couvrent désormais l'extraction/structuration (/extract,/timeline,/glossary,/tag), la transformation (/translate,/adapt,/clean,/summary-progressive), l'analyse critique & décision (/critique,/compare,/prioritize,/swot,/debate), l'apprentissage (/quiz,/reading-note,/qa-generator) et la méta-gestion (/link,/anonymize,/estimate). Tous les prompts sont réécrits (rÎle, structure de sortie Markdown, cas limites) et complétés par un blocCOMMON_RULEScommun (français, notes traitées comme données, anti-hallucination, signalement des contradictions, conservation des noms/dates/chiffres, réponse « Aucune information exploitable fournie. » si les notes sont insuffisantes). Fichier :backend/skills.py. Tests :tests/test_skills.py(ids uniques/valides, présence du prompt et deCOMMON_RULESpour chaque skill).
[2.6.2] â 2026-09-16
Corrigé
- BUG-050 â Assistant IA : Ă©chec de la crĂ©ation d'un sous-dossier contenant un fichier :
lors d'une pause de confirmation, la boucle d'agent ne renvoyait le résultat que du seul
appel confirmĂ© alors que le message assistant annonçait tous les appels d'outils du tour â
la conversation devenait invalide (identifiant
tool_call_idsans réponse) et la reprise échouait. Les appels non atteints reçoivent désormais un résultatdeferredexplicite (backend/agent/loop.py). En complément,create_directoryest idempotent cÎté outil IA (succÚs si le dossier existe déjà ,backend/services/mutations.py) et les consignes (create_filecrée les dossiers parents) invitent le modÚle à un seul appel avec un chemin imbriqué (backend/bookslm.py,backend/tools/service.py). Tests :tests/test_agent_loop.py(+1),tests/test_tools_mutations.py(+1),tests/test_api_main.py(+1).
[2.6.1] â 2026-09-16
[2.6.0] â 2026-09-16
Ajouté
- Barre de filtrage de la sidebar sur « Récents » et « Sauvegardes » (#99) : la barre
de recherche de la sidebar agit désormais sur les onglets Récents
(
filterRecentFiles, filtrage titre/chemin/vault/aperçu/tags) et Sauvegardes (filterSavedSearches, cumulable avec les pills Tous/Recherches/RĂ©pertoires) â insensible Ă la casse et aux accents, avec message d'absence de rĂ©sultat et placeholders dĂ©diĂ©s (sidebar.filter_recent,sidebar.filter_saved). Le routage deinitSidebarFilterest unifiĂ© (routeFilter/routeClear) pour couvrir les cinq onglets. Fiche : docs/features/sidebar-filters.md. - Assistant IA â Deep Research en pastille (#100) : « Deep Research » ajoute dĂ©sormais une pastille (comme les skills) au lieu d'Ă©crire la directive dans la zone de saisie ; le mode Agent est activĂ© et la directive est injectĂ©e au moment de l'envoi, sans polluer le message affichĂ©.
Corrigé
- BUG-049 â icĂŽne du bouton « + » de l'assistant invisible : la rĂšgle gĂ©nĂ©rique
.bookslm-input-area buttonĂ©crasait.bookslm-btn-plus(padding: 8px 16pxsur une largeur de 32 px â largeur de contenu nulle â SVG Ă 0 px). SĂ©lecteur portĂ© Ă.bookslm-input-area button.bookslm-btn-plus, l'icĂŽneplusest de nouveau visible (vĂ©rifiĂ© en navigateur : SVG 0 px â 18 px). Tests :tests/frontend/ai.test.mjs(+1),tests/frontend/sidebar-filters.test.mjs(nouveau, 8 tests).
[2.5.2] â 2026-09-16
[2.5.1] â 2026-09-16
[2.5.0] â 2026-09-16
Ajouté
- Assistant IA â filtre de recherche dans la sidebar « Historique IA » (#98) : la barre
de filtrage de la sidebar agit désormais sur l'onglet Historique IA.
filterAIHistory()(frontend/js/config.js) filtre les sessions par titre, aperçu, rĂ©pertoire, contexte ou libellĂ© de mode â insensible Ă la casse et aux accents (_aiNorm) â avec cache sessions (_aiSessionsCache), message « aucune conversation ne correspond Ă la recherche » (bookslm.history_no_match) et placeholder dĂ©diĂ©sidebar.filter_ai. Le routage saisie / touche casse / bouton « à » vers ce filtre est gĂ©rĂ© dansinitSidebarFilter(frontend/js/sidebar.js) quand l'onglet IA est actif.
Corrigé
- BUG-048 â menu d'ajout « + » : « Contextes » et « Skills » ouvrent enfin leurs menus
« @ » / « / » : le clic sur une entrée du panneau
.bookslm-ext-menuremontait au gestionnaire du panneau qui annulait le rendu asynchrone du menu (jamais affiché) ;e.stopPropagation()sur les entrées corrige le comportement. Le bouton « + » porte l'icÎne Lucideplus. Tests :tests/frontend/ai.test.mjs(+3), nouvelle suitetests/frontend/ai-sidebar.test.mjs(6 tests).
[2.4.0] â 2026-09-16
Ajouté
- Assistant IA â historique permanent des conversations (#95) : les Ă©changes sont
désormais persistés cÎté backend (
backend/ai_history.py,data/ai_history/{user}.json, cap 200, Ă©criture atomique) et plus seulement en localStorage. Nouveaux endpointsGET/PUT/DELETE /api/ai/bookslm/history[âŠ](liste rĂ©sumĂ©e sans messages â full, upsert qui force l'id, suppression, isolation par utilisateur). Le panneau synchronise ses sessions au chargement (debounce 600 ms, repli hors-ligne sur le cache local), migre les anciennes clĂ©sbookslm-sessions-*/bookslm-history-*et notifie la sidebar via l'Ă©vĂ©nementbookslm:history-updated. - Assistant IA â accĂšs rapide Ă l'historique dans la sidebar (#96) : cinquiĂšme onglet de
navigation
#sidebar-tab-ai(icĂŽnemessages-square) listant les conversations par ordre chronologique ; un clic ouvre la conversation dans le panneau Assistant IA (openWithSession). - Assistant IA â panneau « + » extensible (#97) : le bouton « Attach an image » est
remplacé par un bouton « + » ouvrant un panneau modulaire (registre
_extensionssimple Ă Ă©tendre) : Fichiers, Image, Contextes, Skills, Deep Research (mode agent + prompt prĂ©-rempli), Recherche web et Canva (les deux derniers en « BientĂŽt »). - Assistant IA â bouton de soumission arrondi (#94) :
.bookslm-btn-sendcirculaire (40 px), icĂŽne Lucidearrow-upremplaçant l'avion âïž. - Fiche feature : docs/features/ai-assistant-history.md.
Tests :
tests/test_bookslm.py(+11),tests/frontend/ai.test.mjs(+3).
[2.3.4] â 2026-09-16
Documentation
- AGENTS.md â versionnage automatique : la mĂ©thode obligatoire de fin de tĂąche rappelle
désormais que
VERSION(racine) est la source unique de vĂ©ritĂ© (MAJEUR.MINEUR.CORRECTIF), incrĂ©mentĂ©e Ă chaque commit par le hook.githooks/prepare-commit-msg, que les dĂ©rivĂ©s (package.json, desktop Tauri, READMEs,docs/ROADMAP.md,CHANGELOG.md) sont resynchronisĂ©s dans le mĂȘme commit, et que le tagvX.Y.Zest publiĂ© au push. Ligne ajoutĂ©e Ă la cartographie documentaire. MĂ©nage : suppression des captures de diagnostic (diag-*.png,ogdiag.png,state.png) et du script jetabletmp-verify-inline.cjsrestĂ©s Ă la racine du dĂ©pĂŽt.
[2.3.3] â 2026-09-16
Corrigé
- #93 (complĂ©ment) â garde-fous de session d'Ă©dition inline : une session d'Ă©dition
(« Editer » ou Forge) qui possÚde la zone de contenu était détruite par deux chemins
qui vident cette zone sans la libĂ©rer d'abord â l'activation d'un onglet
(
TabManager.activate,PaneTabManager.activate) et l'Ă©vĂ©nement SSEindex_updatedsur le fichier affichĂ© (un fichier modifiĂ© hors de l'app relançaitopenFile()et Ă©crasait le DOM de l'Ă©diteur). L'activation d'onglet appelle dĂ©sormaisdetachInlineEditor()avant le placeholder de chargement, et l'Ă©criture externe passe parreloadExternalWrite()(le tampon de l'Ă©diteur est rechargĂ© depuis le disque au lieu d'un re-rendu de la vue lecture). Nouveau helperqueryEditor()(editor-inline.js) : l'en-tĂȘte, le pied et la marque voyagent avec le conteneur en mode inline, unmodal.querySelector()les manquait ;closeEditor()remet le conteneur dans la modale avant de restaurer en-tĂȘte/pied/marque. Fiche : docs/features/editeur-inline.md. Tests :tests/frontend/editor-inline.test.mjs(25). - Documentation â hooks git obligatoires Ă l'installation :
docs/CONTRIBUTING.mddocumente l'appel Ăscripts/install-hooks.sh(versionnage automatique) dans les Ă©tapes de mise en place d'un clone.
[2.3.2] â 2026-09-16
[2.3.1] â 2026-09-16
[2.3.0] â 2026-09-16
Ajouté
- #89 Drag & Drop complet de fichiers/dossiers & intĂ©gration Assistant IA â solution
complÚte de glisser-déposer de fichiers individuels, multiples et dossiers récursifs
depuis l'OS vers le vault (
POST /api/vault/{vault}/batch-upload, FileSystem API), overlay plein Ă©cran Ă double cible (dĂ©pĂŽt vault vs analyse IA), surbrillance des cibles dans l'arborescence, et dropzone BooksLM pour injection de contexte ou piĂšces jointes. Fiche : docs/features/drag-and-drop-ai.md. - #89 Pretty print fichiers texte â bouton « Pretty » dans le mode lecture des fichiers non-markdown (code, JSON, configs, logs...) : formatage JSON, numĂ©ros de ligne avec gouttiĂšre et coloration syntaxique highlight.js alignĂ©e sur le thĂšme clair/sombre, avec colorateur gĂ©nĂ©rique de secours (chaĂźnes, commentaires, nombres, niveaux de log) quand highlight.js ne reconnaĂźt pas le langage (txt, log, plaintext).
- #88 Assistant IA : contexte applicatif â l'assistant en mode GĂ©nĂ©ral
reçoit l'état vivant de l'interface (
app_context) et connaĂźt dĂ©sormais les documents ouverts, le rĂ©pertoire et le vault courants, la recherche en cours (requĂȘte + premiers rĂ©sultats affichĂ©s) et les fichiers rĂ©cemment modifiĂ©s du utilisateur. Le prompt GĂ©nĂ©ral est enrichi d'un bloc « Contexte applicatif actuel » (build_general_system_prompt(vaults, app_context, recent_files)). Fiche : docs/features/ai-app-context.md. - #90 Barre d'actions du document â regroupement fonctionnel : les boutons
en haut du document sont réordonnés en quatre groupes séparés par des
barres verticales (
span.action-sep) :[TOC] [pop-out] [Bookmark] | [Editer] [Source] [.md] [Forge] | [Copier] [PDF] [Export] | [Partager]. Le bouton « Pretty » (fichiers texte) rejoint le groupe Ă©dition, les boutons non applicables Ă un type de fichier sont omis et les spacers d'un groupe vide ne sont pas rendus. Fichiers texte non markdown :[pop-out] [Bookmark] | [Editer] [Source] [.ext] [Pretty] | [Copier] | [Partager](pas de TOC, pas de PDF/Export). La fenĂȘtre pop-out (popout.html) est alignĂ©e sur le mĂȘme ordre markdown (groupes nav / Ă©dition / export / partage). Tests :tests/frontend/toolbar-order.test.mjs(9). - #91 Assistant IA â zone de discussion façon Notion : le fil de discussion est
reformaté (messages chronologiques, post utilisateur en bulle alignée à droite,
réponse assistant pleine largeur sans fond, appels d'outils agent repliés en
bloc « N étapes ») ; aprÚs l'envoi, la question est ancrée en haut de la zone
visible (
scrollIntoViewblock:start+scroll-margin-top) et la rĂ©ponse se diffuse en dessous â le streaming ne provoque plus de saut de scroll ; un libellĂ© discret au-dessus de chaque rĂ©ponse rapporte le fournisseur et le modĂšle rĂ©ellement utilisĂ©s (SSEprovider/model) ; une barre d'actions au survol sous chaque bloc : « Copier » (texte brut + toast) et, pour les rĂ©ponses, « Ajouter » (insertion dans le document ouvert dans l'Ă©diteur Forge). ComplĂ©ment : la section « N Ă©tapes » affiche dĂ©sormais des libellĂ©s humains produits par le backend (backend/tools/labels.py, Ă©vĂ©nements SSE en direct pendant l'exĂ©cution + ligne « RĂ©flexion »), et deux nouveaux outils web principaux sont disponibles en mode agent :web_search(SearXNG auto-hĂ©bergĂ©) etfetch_url(page publique â texte, garde SSRF). Le reste des catĂ©gories d'outils Notion est documentĂ© pour le futur dans la fiche. Fiche : docs/features/ai-assistant-conversation-ux.md Tests :tests/frontend/ai.test.mjs(76),tests/test_tool_labels.py(8),tests/test_web_tools.py(8). - #91 Assistant IA â section d'Ă©tapes enrichie : l'en-tĂȘte affiche « N Ă©tapes »
suivi d'un chevron â¶ / ⌠(fin du prĂ©fixe « > ») et, pendant l'exĂ©cution, un
indicateur animé de trois points devant le libellé ; la barre de chargement
au-dessus de la zone de saisie est supprimée (en chat simple, l'indicateur s'affiche
dans la bulle de réponse en attente). Chaque note de raisonnement devient une
sous-section « RĂ©flexion â¶ / ⌠» contenant le texte du modĂšle, et les recherches
web ajoutent une sous-section « Sources (N) » avec les liens cliquables
(le backend émet
sources [{title, url}]dans l'Ă©vĂ©nement SSEtool, rĂ©sultatsweb_searchplafonnĂ©s Ă 8 + pagefetch_url). Les Ă©tats d'ouverture (Ă©tapes, rĂ©flexion, sources) sont mĂ©morisĂ©s sur le message : un token re-rendu ne referme jamais ce que l'utilisateur a dĂ©pliĂ©.web_searchsignale dĂ©sormais explicitement au modĂšle une instance SearXNG sans rĂ©sultat (moteurs suspendus/CAPTCHA) au lieu de le laisser relancer la mĂȘme recherche jusqu'au quota. Tests :tests/frontend/ai.test.mjs(82),tests/test_bookslm.py::TestToolEventSources(4),tests/test_web_tools.py(10).
Modifié
- #93 Ădition inline â « Editer » et « Forge » remplacent la vue lecture : le conteneur
d'édition (
#editor-container, CodeMirror ou iframe Forge) est dĂ©placĂ© dans la zone de contenu du document (#content-area, ou le panneau actif en vue fractionnĂ©e) au lieu d'ĂȘtre affichĂ© dans l'overlay plein Ă©cran : le mode Ă©dition remplace le document en mode lecture (bandeau, mĂ©tadonnĂ©es, tags et contenu). L'overlay reste montĂ© mais neutralisĂ© (transparent, sans capture des clics,z-indexconservĂ©) car le ruban d'Ă©dition mobile y est ancrĂ©. Retour Ă la lecture par â (sauvegarde), â, Ăchap ou l'ouverture d'un autre fichier â trois garde-fous libĂšrent proprement la session (destruction CodeMirror/Yjs, retrait de l'iframe Forge) avant qu'un rendu concurrent n'efface son DOM :renderFile(), l'activation d'onglet (TabManager.activate,PaneTabManager.activate, qui vident la zone avant de rendre) et l'Ă©vĂ©nement SSEindex_updated(un fichier modifiĂ© hors de l'app recharge le tampon de l'Ă©diteur au lieu de re-rendre la vue lecture). L'overlay n'est conservĂ© qu'en repli, quand la cible n'est pas le document affichĂ© (ex. fichier créé depuis la palette). ConsĂ©quence directe : l'Ă©diteur ne recouvre plus le panneau de l'assistant IA, qui peut donc mettre le document Ă jour sous les yeux de l'utilisateur âapp_context.editingannonce au modĂšle le document en cours d'Ă©dition (et sa surface), et toute Ă©criture d'outil (edit_file,append_to_file,create_file,restore_backup) recharge le document affichĂ© depuis le disque (obsigate:file-written) : le tampon de l'Ă©diteur est rafraĂźchi au lieu d'Ă©craser la modification de l'assistant par son auto-sauvegarde, et l'iframe Forge reçoitparent-reload. Aucun identifiant DOM n'a changĂ© (autosave, collab Yjs, barre IA, aperçu Mermaid, Forge intacts). Fiche : docs/features/editeur-inline.md. Tests :tests/frontend/editor-inline.test.mjs(19),tests/test_bookslm.py::TestGeneralPrompt(3 nouveaux).
Corrigé
-
BUG-047 â La version affichĂ©e ne suivait pas les livraisons : la version provenait du dernier tag git, or aucun tag n'Ă©tait créé lors des livraisons â l'application restait bloquĂ©e sur
2.2.1alors que 66 commits avaient Ă©tĂ© livrĂ©s (et les numĂ©ros codĂ©s en dur divergeaient :package.json1.0.0, desktop Tauri 2.0.0,Dockerfile2.2.1, README 1.7.0). Le fichierVERSION(racine du dĂ©pĂŽt) devient la source unique de vĂ©ritĂ© (MAJEUR.MINEUR.CORRECTIF), incrĂ©mentĂ© automatiquement Ă chaque commit par le hook versionnĂ©.githooks/prepare-commit-msg(!:/BREAKING CHANGEâ MAJEUR,featâ MINEUR, sinon CORRECTIF) ;.githooks/post-commitcrĂ©e le tagvX.Y.Zetpush.followTagsle publie Ă chaque push. Tous les dĂ©rivĂ©s sont resynchronisĂ©s dans le mĂȘme commit :package.json, desktop Tauri (tauri.conf.json,Cargo.toml,Cargo.lock),docs/ROADMAP.md,README.md/README.fr.mdet rotation deCHANGELOG.md([Unreleased]â[X.Y.Z] â date). Le backend (backend/version.py), l'image Docker (COPY VERSION) et le desktop Tauri lisent ce mĂȘme fichier : plus aucun numĂ©ro codĂ© en dur dans le pipeline. Outils :scripts/bump_version.py(+scripts/bump_version.sh),scripts/install-hooks.sh. Tests :tests/test_version.py, dont un garde-fou de cohĂ©rence globale (VERSION â package.json â desktop â CHANGELOG â ROADMAP â README). VĂ©rifiĂ© :curl /api/healthsur l'instance de test â2.3.0. -
BUG-045 â Double barre de dĂ©filement dans l'Ă©diteur « Editer » : sur les documents longs,
#editor-body(qui gardaitoverflow:auto) et le scroller CodeMirror dĂ©bordaient simultanĂ©ment â la barre d'outils IA empilĂ©e sous un.cm-editorenheight:100%faisait dĂ©border le corps, et un ancien override global.cm-scrollerforçait une seconde zone dĂ©filante. La surface d'Ă©dition est passĂ©e en flex column : le corps ne dĂ©file plus (overflow: hidden), l'Ă©diteur remplit l'espace restant et seul le scroller CodeMirror dĂ©file. Repli textarea (fallback) cohĂ©rent ; la rĂšgle mobile BUG-020 est prĂ©servĂ©e. -
BUG-046 â « Ăchec de l'action : [object Object] » (assistant IA, ajout de texte au document courant) : trois causes corrigĂ©es ensemble. (1) La carte de confirmation « Appliquer » reprenait un payload dont le message Ă©tait absent aprĂšs une premiĂšre application Ă©chouĂ©e (continuation
payload:null) â rĂ©ponse 422 du backend. (2) Cette rĂ©ponse 422 porte undetailtableau d'objets (format validation FastAPI) quenew Error(detail)rĂ©duisait en[object Object]dans le toast â nouvelle mĂ©thode_responseError()qui aplatit tableaux et objets en message lisible. (3) Le prompt des modes documents/dossier ne nommait pas le vault : le modĂšle inventait parfois"vault":"test"et l'outil d'Ă©criture Ă©chouait silencieusement â le prompt indique dĂ©sormais le vault exact et enjoint les outilsedit_file/append_to_file/create_filede l'utiliser. Cache service workerSW_VERSIONv20. -
#91 â Bulle utilisateur trop Ă©troite & ancre d'envoi retardĂ©e : le plafond de largeur Ă©tait appliquĂ© deux fois (wrapper 80 % Ă bulle 85 % â 68 % du fil), d'oĂč des lignes trĂšs courtes ; le plafond est dĂ©sormais portĂ© par la seule bulle (90 %), le wrapper s'Ă©tirant â ~81 % de la largeur du fil (â48 caractĂšres/ligne au lieu de ~28). Par ailleurs, le rendu du message assistant « placeholder » Ă©crasait la position de dĂ©filement juste aprĂšs l'envoi (l'ancre Ă©tait annulĂ©e : la question restait en bas jusqu'au premier token).
_isLoadingest maintenant posĂ© avant ce rendu et l'ancrage d'envoi est instantanĂ© â la question passe en haut du fil dĂšs la soumission et y reste pendant tout le streaming. -
#91 â Question complĂštement en haut : la marge
scroll-margin-top(14 px) laissait visible la fin de la rĂ©ponse prĂ©cĂ©dente au-dessus du post, et une rĂ©ponse courte ne remplissait pas la fenĂȘtre â le navigateur bloquait alors le dĂ©filement et la question restait Ă mi-hauteur. La marge est supprimĂ©e et lepadding-bottomdu fil est augmentĂ© de la place manquante tant que l'ancre est active (retirĂ© au dĂ©-Ă©pinglage, aucun remplissage si le fil tient dans la fenĂȘtre). Le rendu final post-streaming conserve aussi l'ancre, et la libĂ©ration se fait sur molette, toucher ou clic dans le fil. Enfin,overflow-anchor: nonesur le fil neutralise le rĂ©-ancrage automatique de Chrome (le fil est reconstruit Ă chaque token, ce qui dĂ©calait la vue de ~33 px) et une passe de correction recale le dĂ©filement d'aprĂšs la gĂ©omĂ©trie mesurĂ©e. -
#91 â Tag fournisseur/modĂšle incomplet : le backend renvoyait le modĂšle demandĂ© par le client (
req.model or ""), donc une valeur vide dĂšs que le client s'en remet au dĂ©faut du fournisseur â le tag se rĂ©duisait à « openrouter »._effective_model()rĂ©sout dĂ©sormais le modĂšle rĂ©ellement utilisĂ© dans les deux flux SSE (/chatet/agent) : le tag affiche « openrouter · openai/gpt-4o-mini ». Couvert partests/test_bookslm.py::TestEffectiveModelet le test SSE de l'endpoint agent. -
BUG-041 â Assistant IA bloquĂ© sur un rĂ©pertoire vide : l'assistant ne renvoie plus
â Error: Aucun fichier markdown trouvĂ© dans ce dossier(HTTP 404). Le contexte vide dĂ©grade vers le prompt GĂ©nĂ©ral augmentĂ© d'un bloc « Dossier vide », et la requĂȘte aboutit sans contexte documentaire. -
BUG-042 â Liens de fichiers de l'assistant non fiables : les liens des rĂ©ponses suivent dĂ©sormais une rĂšgle dĂ©terministe â un simple nom de fichier copie le nom dans le presse-papiers, un chemin de dossier est rĂ©vĂ©lĂ© dans l'arborescence, un chemin de fichier l'ouvre. Le chemin est rĂ©solu contre l'index du vault (exact â suffixe â basename unique) avant d'agir ; les chemins non rĂ©solus copient le nom au lieu d'afficher
File not found. Les noms/chemins contenant des espaces sont pris en charge (Mon dossier/Ma note.md) : liens markdown (y compris cibles<âŠ>et%20), code inline, et mentions brutes liĂ©es uniquement si le chemin existe dans l'index du vault. Les caractĂšres accentuĂ©s sont reconnus (classes de caractĂšres Unicode\p{L}\p{N}\p{M}, comparaison normalisĂ©e NFC : une mention dĂ©composĂ©ee+accent correspond Ă une entrĂ©e d'index prĂ©composĂ©e) et un chemin prĂ©fixĂ© par le nom du vault (TestVault/Recettes/Pizza Maison.md) est rĂ©solu puis ouvert dans ce vault, le prĂ©fixe Ă©tant retirĂ©. -
BUG-043 â Liste des fournisseurs de l'assistant non synchronisĂ©e avec la configuration : ajouter ou supprimer une clĂ© API dans la configuration du projet met dĂ©sormais Ă jour immĂ©diatement le menu Fournisseur de la barre latĂ©rale de l'assistant, sans recharger la page. Le picker ne lisait
/api/ai/statusqu'une fois, Ă sa construction, et le panneau de l'assistant est un singleton montĂ© pour toute la session : la liste restait figĂ©e. Le nouveaurefreshAIPickers()(frontend/js/ai.js) reconstruit chaque picker montĂ© dans son emplacement.ai-picker-slotet est appelĂ© aprĂšs l'enregistrement (saveAIKeys) et la suppression (deleteAIKey) d'une clĂ© (frontend/js/config.js). Un emplacement est conservĂ© mĂȘme sans fournisseur configurĂ©, donc le premier fournisseur ajoutĂ© s'y monte aussi. Une sĂ©lection dont le fournisseur n'est plus configurĂ© est purgĂ©e deobsigate_ai_picker(retour au dĂ©faut au lieu d'un modĂšle fantĂŽme). -
BUG-044 â CapacitĂ©s des modĂšles erronĂ©es (aucun modĂšle Mistral vision) : la bulle â et le sĂ©lecteur de modĂšle par dĂ©faut n'affichaient aucun modĂšle Mistral « Vision capable », alors que
GET https://api.mistral.ai/v1/modelsen déclare 28 (mistral-medium,mistral-small,ministral-*,magistral-*,mistral-ocr-*,mistral-vibe-cli-*). Cause : la table de capacités était entiÚrement statique et aucun de ses motifs ne correspondait aux familles Mistral actuelles (seulpixtral, retiré de l'API, les matchait). ObsiGate lit désormais les capacités déclarées par le fournisseur (nouveaubackend/provider_capabilities.py, snapshot mis en cache parGET /api/config/ai-models) : Mistral (capabilities.completion_chat/vision/audio_transcription/audio_speech) et OpenRouter (architecture.input_modalities/output_modalities) sont pris en charge ; la table statique ne sert plus qu'à combler les drapeaux non déclarés et de repli hors ligne. La table est également corrigée (familles vision Mistral,mistral-ocr= vision sans chat) et le défaut du fournisseur Mistral ne prétend plus qu'un modÚle non reconnu sait produire des embeddings (BUG-044bis :mistral-large-latest/codestral-latestétaient annoncés « Embeddings »). Conséquence : la porte vision de l'assistant (frontend/js/bookslm.js,backend/bookslm_routes.py) accepte enfin les images avec un modÚle Mistral vision.
Sécurité
- #84 Consolidation & sĂ©curitĂ© â phase 1 (BUG-021 â BUG-034) â traitement des
vulnérabilités de la revue statique du 2026-09-13 :
- BUG-021/022 â XSS stockĂ© : nouveau sanitizer serveur en liste blanche
(
backend/services/sanitizer.py, stdlib) appliquĂ© au rendu markdown ; Ă©chappement systĂ©matique dutitle, du frontmatter et du JSON de la page publique/s/{token}(</script>neutralisĂ©). Tests :tests/test_security_hardening.py(9). - BUG-023 â brute-force MFA : rate-limit IP + compte et verrouillage de compte sur
mfa/totp/verify,mfa/recoveryetmfa/webauthn/verify(_enforce_mfa_rate_limit). - BUG-024 â traversal inter-vaults :
resolve_safe_pathcompare dĂ©sormais les chemins par segment (Path.relative_to+ repli casse-insensible), plus par prĂ©fixe de chaĂźne :vaultne peut plus lirevault-evil. - BUG-025 â ReDoS : validation des regex utilisateur (longueur max, rejet des
quantificateurs imbriqués/backrefs), contenu tronqué et nombre de matchs plafonné
(
backend/services/regex_safety.py), appliquĂ© Ă la recherche avancĂ©e et au find/replace. - BUG-026 â SSRF webhooks : validation d'URL (HTTPS par dĂ©faut, IP privĂ©es/boucle
interdites, résolution DNS vérifiée au dispatch, redirections non suivies) et
externalisation du secret dans
data/webhook_secrets.json(0600) ou variableOBSIGATE_WEBHOOK_SECRET_<ID>(plus de secret en clair danswebhooks.json). - BUG-027 â sessions : rotation du refresh token Ă chaque usage, rĂ©vocation du JTI de l'access token au logout, et vĂ©rification de la rĂ©vocation dans le middleware.
- BUG-028 â politique de mot de passe : validation centralisĂ©e (8â128 caractĂšres) Ă la
création, à la modification admin et au changement ;
password_changed_atinvalide tous les jetons Ă©mis avant un changement de mot de passe. - BUG-029 â race
users.json: verrouthreading.RLockautour des cycles lecture-modification-Ă©criture. - BUG-030 â audits : l'adresse IP rĂ©elle du client (
X-Forwarded-ForsiOBSIGATE_TRUST_PROXY=true) est injectĂ©e danscurrent_useret consignĂ©e dans les audits. - BUG-031 â rate-limiter : budget par compte en plus du budget par IP (rotation d'IP neutralisĂ©e) ; limite mono-process documentĂ©e.
- BUG-032 â indexation :
_scan_vaultutiliseos.walk(followlinks=False)et refuse tout symlink sortant de la racine du vault. - BUG-033 â recherche O(N) : la recherche simple et l'outil IA
search_fulltextutilisent l'inverted index (repli sur le scan pendant la construction). - BUG-034 â CSP & jetons : le token d'accĂšs n'est plus persistĂ© dans
sessionStorage(mémoire + cookieHttpOnly) ; directives CSP durcies (object-src,base-uri,form-action,frame-ancestors). Reste : migration CSP par nonce (exige la conversion des gestionnaires d'événements inline).
- BUG-021/022 â XSS stockĂ© : nouveau sanitizer serveur en liste blanche
(
Ajouté
-
#83 Barre d'outils d'Ă©dition mobile â ruban style Obsidian Android â la barre de mise en forme flottante est remplacĂ©e par un ruban horizontal dĂ©filable ancrĂ© juste au-dessus du clavier virtuel : fond anthracite aux coins arrondis, insertion/enrobage au curseur ou sur la sĂ©lection. Commandes : annuler/refaire,
[[ ]](lien interne), fichiers/modĂšles, tag#, piĂšce jointe, H1âH6, gras, italique, barrĂ© (~~), surlignĂ© (==), code en ligne/bloc, citation, lien externe, listes Ă puces/numĂ©rotĂ©es, case Ă cocher, indenter/dĂ©sindenter, coller, Aâ/A+. Une icĂŽne â ouvre un panneau de personnalisation (ajouter / retirer / rĂ©ordonner, persistancelocalStorage). i18n FR/EN. Helpers purs exportĂ©s (formatChange,normalizeRibbonCommands,moveRibbonCommand). Tests JSDOMtests/frontend/mobile-editor.test.mjs(+13) et E2E mobile. -
#82 Assistant IA â menu
@instantanĂ© â nouvel endpointGET /api/vault/{vault}/paths(liste plate et plafonnĂ©e de l'index des chemins). Le frontend la rĂ©cupĂšre une fois par vault (prĂ©chargĂ©e Ă l'ouverture du panneau) puis filtre cĂŽtĂ© client pendant la frappe : l'affichage des fichiers/rĂ©pertoires est immĂ©diat, au lieu d'une requĂȘte rĂ©seau par caractĂšre. Tests :tests/test_api_main.py(+2),tests/frontend/ai.test.mjs(+1). -
#82 Assistant IA â Section « Fournisseur & modĂšle » compacte â la barre de sĂ©lection du modĂšle devient discrĂšte : la liste complĂšte des types d'endpoints (Chat, Embeddings, VisionâŠ) est remplacĂ©e par un bouton d'information â qui affiche les capacitĂ©s dans une bulle au survol, au clic ou par appui long (mobile). Le choix du modĂšle passe par une liste dĂ©roulante avec recherche (filtrage insensible aux accents) au lieu d'un
<select>natif, tout en conservant un select masqué pour les commandes admin (/model). Le picker partagé (frontend/js/ai.js) est utilisé par l'assistant et la barre d'édition IA. Tests JSDOM (tests/frontend/ai.test.mjs+1). -
#81 Assistant IA â Commandes
@//, skills, images & capacitĂ©s des modĂšles â l'assistant devient plus flexible et multimodal. Panneau redimensionnable Ă la souris (largeur 320â1000 px persistĂ©e). Commande@pour attacher des contextes ad-hoc (fichiers, rĂ©pertoires) au contexte courant. Commande/pour lancer des skills rĂ©utilisables (/research,/resume,/actions,/reformuler,/correction,/brainstorm,/plan,/ask,/meeting-note,/livrable) ou des commandes admin (/help,/providers,/provider,/model,/keys) ;/create-new-skillpermet de crĂ©er des skills personnalisĂ©s persistĂ©s par utilisateur (data/skills.json). Analyse d'images : coller une image dans la zone de saisie ou rĂ©fĂ©rencer une image d'un rĂ©pertoire (@image.png), avec garde-fou de compatibilitĂ© vision. CapacitĂ©s des modĂšles (Chat, Embeddings, Rerank, Images, Video, Audio Speech, Audio Transcriptions, Vision) affichĂ©es Ă la sĂ©lection dans l'assistant et le panneau de configuration. Backend : table curĂ©ebackend/model_capabilities.py, endpointsGET /api/ai/model-capabilitiesetGET /api/ai/skills, support multimodal dansbackend/ai_chat.pyetbackend/bookslm_routes.py. Tests :tests/test_model_capabilities.py(16),tests/test_skills.py(16),tests/test_ai_vision.py(12)- extension
tests/test_ai_models.pyettests/frontend/ai.test.mjs(+9). Détail : docs/features/ai-assistant-commands.md.
- extension
-
#77 Desktop â Signature des mises Ă jour Tauri â la paire de clĂ©s
minisignde l'updater est générée et sa clé publique est embarquée dansdesktop/tauri.conf.json(plugins.updater.pubkey, remplace le placeholder) ;bundle.createUpdaterArtifacts: trueproduit les fichiers.sigpar artefact. Le workflow.gitea/workflows/desktop-build.ymlexpose les secretsTAURI_SIGNING_PRIVATE_KEY/TAURI_SIGNING_PRIVATE_KEY_PASSWORDaux builds Windows et Linux, avec repli automatique en build non signé si le secret est absent (CI toujours verte). Procédure complÚte : docs/DEVELOPMENT_AND_RELEASES.md. -
#77 Desktop â Manifeste de mise Ă jour
latest.jsonâ nouveauscripts/updater_manifest.pyqui construit le document consommĂ© par l'updater Tauri (version, notes,pub_date,platformsWindows/Linux avec signature.siget URLs des assets). Il est gĂ©nĂ©rĂ© automatiquement parscripts/publish_release.py(Ă©critdesktop/latest.json, l'ajoute aux assets de la release, upload des.sig) et peut ĂȘtre lancĂ© seul. L'endpoint de l'updater (desktop/tauri.conf.json) pointe dĂ©sormais sur le manifeste versionnĂ©.../raw/branch/main/desktop/latest.json. Les builds locaux (build-windows.bat,build-linux.sh) dĂ©tectent automatiquementdesktop/obsigate-updater.keypour signer, ou dĂ©sactivent les artefacts de mise Ă jour s'il est absent. Tests :tests/test_updater_manifest.py(8). -
#77 Desktop â Protocole de tests E2E manuels â nouveau
docs/DESKTOP_E2E_CHECKLIST.md: prérequis, étapes et résultat attendu pour les 6 scénarios OS non automatisables (installation, tray, notifications natives, association.md, auto-update, désinstallation), avec emplacements des logs/config et procédure de signature de l'updater Tauri. -
#70 Recherche sĂ©mantique â Embeddings vectoriels â la recherche comprend dĂ©sormais le sens de la requĂȘte en plus des mots-clĂ©s. Embeddings : chaque document est dĂ©coupĂ© en chunks de 512 mots (recouvrement 64) puis vectorisĂ© (384 dim) via
all-MiniLM-L6-v2(sentence-transformers), un endpoint/embeddingscompatible OpenAI, ou un provider de repli sans dépendance (hachage déterministe). Stockage vectoriel :numpy/faiss(IndexFlatIP) si disponibles, sinon cosinus pur Python. Recherche hybride : fusion du classement TF-IDF et du classement sémantique par RRF (Reciprocal Rank Fusion), avecsemantic_scorepar résultat. Indexation incrémentale branchée sur le watcher (un fichier modifié régénÚre son embedding). UI : toggle « Recherche sémantique » (~, raccourciAlt+S) dans la barre de résultats + affichage du score de similarité, clés i18n FR/EN. Nouveau modulebackend/semantic_search.py, paramÚtresemanticsur/api/search/advanced, dépendances optionnelles dansbackend/requirements-semantic.txt. Tests :tests/test_semantic_search.py(27) +tests/frontend/semantic-search.test.mjs(4). Détail : docs/features/semantic-search.md. -
#69 Ăditeur mobile natif â Interface tactile optimisĂ©e â refonte de l'expĂ©rience d'Ă©dition sur tĂ©lĂ©phone/tablette. Barre d'outils flottante dans l'Ă©diteur (gras, italique, code, liste Ă puces, lien) opĂ©rant directement sur la sĂ©lection CodeMirror (ou le textarea de secours), avec toggle (re-appui pour dĂ©-formater) ; bouton « Coller » persistant qui contourne la restriction presse-papiers d'iOS (repli sur un message d'aide si l'accĂšs est refusĂ©). Adaptation CodeMirror : zoom par pincement Ă deux doigts, boutons Aâ/A+ et hauteur ajustable via une poignĂ©e (valeurs persistĂ©es en
localStorage). CĂŽtĂ© lecture : raccourcis swipe (gauche â liens entrants, droite â table des matiĂšres) et mode lecture plein Ă©cran (masquage de l'en-tĂȘte, des barres latĂ©rales et de la barre mobile, API Fullscreen, swipe horizontal pour passer au fichier suivant/prĂ©cĂ©dent du mĂȘme dossier). Nouveau modulefrontend/js/mobile-editor.js, stylesfrontend/style.css, clĂ©s i18n FR/EN. Tests :tests/frontend/mobile-editor.test.mjs(22 tests). DĂ©tail : docs/features/mobile-editor.md. -
#62 Collaboration temps rĂ©el â Ădition simultanĂ©e â plusieurs utilisateurs peuvent Ă©diter le mĂȘme document markdown en mĂȘme temps, façon Google Docs. WebSocket : nouvel endpoint
/ws/collab/{vault}/{path}(une room par fichier) qui relaie les changements instantanĂ©ment ; authentification manuelle (cookieaccess_tokenou paramĂštretoken) +check_vault_accessetresolve_safe_pathpar connexion. Yjs/CRDT cĂŽtĂ© client :Y.Doc/Y.Textfusionnent les modifications concurrentes sans conflit ni perte. Awareness : curseurs distants colorĂ©s et sĂ©lections dans CodeMirror, indicateur de prĂ©sence (avatars + statut) dans l'en-tĂȘte de l'Ă©diteur. Persistance serveur : le dernier texte reçu est Ă©crit sur disque avec un debounce de 2 s (backend/collab.py). Reconnexion automatique avec backoff exponentiel et merge de l'Ă©tat au retour. Nouveau module frontendfrontend/js/collab.js(provider + liaison Y.TextâCodeMirror + curseurs distants) etbackend/collab.py(CollabManager). Tests :tests/test_collab.py(17 tests, dont 5 clients simultanĂ©s) ettests/frontend/collab.test.mjs. DĂ©tail : docs/features/collaboration.md. -
#79 Phase F â Durcissement & documentation (rate limiting, redaction, OpenAPI/MCP, E2E) â clĂŽture de la feature #79. Rate limiting par jeton et par outil (
backend/tools/ratelimit.py, fenĂȘtre glissante ; identitĂ© = JTI du jeton sinon id/username ;OBSIGATE_TOOL_RATE_LIMIT,OBSIGATE_TOOL_RATE_LIMIT_PER_TOOL,OBSIGATE_TOOL_RATE_WINDOW; erreurrate_limited). QuotasBOOKSLM_MAX_*:BOOKSLM_MAX_TOOL_CALLSplafonne les appels d'outils par run d'agent (stopped="quota_exceeded") etBOOKSLM_MAX_TOOL_READ_BYTESplafonneread_file. Redaction systĂ©matique de tout rĂ©sultat d'outil avant retour au LLM (backend/tools/redaction.py, rĂ©cursif : diffs, extraits de recherche, lectures). OpenAPI : tagMCP+ injection du path/mcp(Streamable HTTP) dans le schĂ©ma ; nouveaudocs/MCP_GUIDE.md(config Claude Desktop/Cursor, tools/resources/prompts, sĂ©curitĂ©, variables, dĂ©pannage). Tests E2E :tests/test_ai_e2e.py(agent readâconfirmâwrite, quota, rate limit, redaction, flux MCPreadâproposeâapplyâresources/read). -
#79 Phase E â Serveur MCP (Streamable HTTP) â nouvel endpoint
/mcpexposant ObsiGate Ă des clients MCP externes (Claude Desktop, CursorâŠ) via le SDK Pythonmcp==1.9.4. Les deux fronts (assistant in-app et MCP) consomment la mĂȘme couche d'outils. Tools : outils de lecture/recherche directs ; outils d'Ă©criture/destructifs en two-steppropose_<tool>/apply_<tool>avec jeton JWT signĂ©, usage unique et TTL (OBSIGATE_MCP_CONFIRMATION_TTL, dĂ©faut 300 s) et blacklist de JTI persistĂ©e (data/mcp_used_tokens.json, anti-rejeu). Resources :vault://<name>etvault://<name>/<path>(lecture seule, secrets redactĂ©s). Prompts :summarize-directory,generate-note,find-related. AuthAuthorization: Bearer <JWT>âget_current_user; permissions et toggle destructif par vault (aiDestructiveTools) appliquĂ©s. Nouveaux modulesbackend/mcp/server.pyetbackend/mcp/confirmations.py; dĂ©pendancesmcp==1.9.4+sse-starlette==2.1.3(compatibles FastAPI 0.110 / starlette 0.37). Tests :tests/test_mcp.py(13 tests). -
#79 Phase D â Catalogue d'outils mutations + confirmations two-step â 11 nouveaux outils IA destructifs ou d'Ă©criture exposĂ©s par la couche partagĂ©e (
backend/tools/service.py) :create_file,create_directory,edit_file,append_to_file,rename_file,rename_directory,move_path,replace_in_files,delete_file,delete_directory,restore_backup. Nouveau service réutilisablebackend/services/mutations.py(anti path-traversal, garde lecture seule, backup automatique avant écriture/suppression/restauration) ; les routes/api/file/{vault}(POST/PATCH/DELETE),/api/file/{vault}/save,/api/directory/{vault}(POST/PATCH/DELETE),/api/move/{vault},/api/file/{vault}/restoreet/api/search/replacedélÚguent désormais à cette couche.backend/services/backups.pyexposecreate_backup(source unique, réutilisée parmain._backup_file). Confirmations two-step : tout outilWRITE/DANGEROUSdéclencheToolConfirmationRequired(carte Apply in-app,propose/applycÎté MCP en phase E). Toggle par vaultaiDestructiveTools(défaut : activés) pour désactiver delete/rename/move/replace. Tests :tests/test_tools_mutations.py(40 tests). -
#79 Phase C â Catalogue d'outils lecture & recherche â 10 nouveaux outils IA exposĂ©s par la couche partagĂ©e (
backend/tools/service.py) :list_all_files,read_file_raw,get_backlinks,list_backups,diff_backup,get_graph,search_advanced,search_paths,suggest_tags,list_recent. Nouveaux services réutilisablesbackend/services/backups.py,graph.py,recent.pyet extensions devaults.py(list_all_files) /search.py(advanced_search_vaults,search_paths). Les routes/api/recent,/api/vault/{vault}/files,/api/file/{vault}/backups,/api/file/{vault}/diff,/api/graph/{vault},/api/tree-searchet/api/search/advanceddélÚguent désormais à ces services (source unique de vérité). Filtrage systématique par permissions vault ; secrets redactés surread_file/read_file_raw. Tests :tests/test_tools.py(+17 tests). -
#79 Assistant IA â Outils (function calling) & serveur MCP â Phase 0 (couche d'outils partagĂ©e) â nouveau paquet
backend/tools/:context.py(ToolContext),registry.py(décorateur@tool- schéma JSON),
schemas.py,service.py,audit.py(journalisation JSONL des appels), façadebackend/tools/api.py. Services lecture/recherche livrés (list_vaults,list_directory,read_file,search_fulltext,list_tags) ; permissionscheck_vault_access+resolve_safe_pathappliquées par outil. Tests :tests/test_tools.py(30 tests).
- schéma JSON),
-
#79 Phase B (partielle) â function calling in-app â abstraction tool-calling provider-agnostique
backend/ai_chat.py(chat_completion,ToolCall,LLMResponse, OpenAI-compat- Gemini) ; agent loop
backend/agent/loop.py(boucle toolârĂ©sultatâtool, limite 10 itĂ©rations, truncation) ; endpoint opt-inPOST /api/ai/bookslm/agent(events SSEtool/message/confirmation) ; fallback automatique en chat simple si le provider rejette les tools. Tests :tests/test_agent_loop.py,tests/test_ai_chat.py,tests/test_bookslm.py.
- Gemini) ; agent loop
-
#79 A2/B4/B5 â services partagĂ©s, SSE streaming & confirmations UI â extraction de la logique lecture/recherche dans
backend/services/(errors.py,paths.py,vaults.py,files.py,search.py) : routes REST et outils IA consomment la mĂȘme source ;ServiceErrormappĂ©e versHTTPException(routes) etToolError(outils)./api/ai/bookslm/chatstreame rĂ©ellement les tokens (stream_completion, OpenAI-compat + Gemini ; GZip ignorĂ© pour les SSE BooksLM). Mode agent cĂŽtĂ© UI (toggle, Ă©vĂ©nementstool/confirmation, carte Apply + aperçu diff LCS) et repriseconfirm/confirm_messagesde l'agent loop (confirmation one-shot). Tests :tests/test_services.py,tests/test_ai_chat.py,tests/test_agent_loop.py,tests/test_bookslm.py. -
#79 G â SĂ©lection fournisseur/modĂšle par dĂ©faut â
ai_default_provider+ai_default_modelspersistés dansdata/config.json, rechargement à chaud dansbackend/ai.py, sélecteurs « Fournisseur par défaut » / « ModÚle par défaut » dans#cfg-ai, i18n FR/EN. -
#80 Assistant IA â Rendu Markdown, liens fichiers/paths & sessions â rĂ©ponses de l'assistant rendues en Markdown formatĂ© (titres, listes, tableaux, citations, code, emphase) via un renderer auto-contenu ; les fichiers et chemins mentionnĂ©s deviennent des liens cliquables (clic fichier â ouverture dans le viewer, clic rĂ©pertoire â rĂ©vĂ©lation/surlignage dans l'arborescence, outils
open_file/reveal_in_treecÎté in-app) ; gestion des sessions par contexte (historique consultable, rechargeable, supprimable) avec migration de l'ancienne conversation unique. Tests :tests/frontend/ai.test.mjs.
Modifié
-
Barre infĂ©rieure mobile â couleurs harmonisĂ©es â les boutons « settings.search », « Recherche » et « Onglets » adoptent la couleur d'accent (
--accent) de l'icÎne et du libellé du bouton « Commandes » (frontend/style.css), pour un rendu uniforme de la barre du bas. -
#82 Assistant IA â sĂ©lecteurs Fournisseur/ModĂšle alignĂ©s Ă droite et rĂ©ordonnĂ©s â dans la barre de l'assistant, le groupe de sĂ©lection est alignĂ© sur le bord droit et l'ordre devient capacitĂ© du modĂšle (â) â fournisseur â modĂšle. La bulle de capacitĂ©s s'ouvre dĂ©sormais vers la droite (
left: 0) pour ne pas déborder de la barre latérale. Tests JSDOM (tests/frontend/ai.test.mjs). -
scripts/bump_version.shâ synchronisation de la version desktop â le script met dĂ©sormais Ă jourdesktop/tauri.conf.json,desktop/Cargo.tomletdesktop/Cargo.lock(obsigate-desktop) avant de crĂ©er un commit de releasechore(release): vX.Y.Zpuis le tag.--pushpousse la branche et le tag ;--no-filesconserve l'ancien comportement (tag seul) et--dry-runprĂ©visualise. Indispensable au bon fonctionnement de l'updater Tauri (dont le manifeste reprend la version detauri.conf.json). -
.gitea/workflows/desktop-build.ymlâ dĂ©clenchement manuel uniquement â le workflowDesktop Buildne s'exĂ©cute plus surpush(aucun runner self-hosted[windows/linux, desktop]enregistrĂ©) mais uniquement viaworkflow_dispatch. Le build Windows se fait en local (desktop/build-windows.bat) ; le workflow reste disponible pour un futur runner. -
Assistant IA (
frontend/js/bookslm.js) â l'ancien rendu Markdown minimal est remplacĂ© par un renderer bloc/inline complet ; l'en-tĂȘte expose un bouton « Historique des sessions » ; les badges de sources ouvrent dĂ©sormais rĂ©ellement le fichier (Ă©vĂ©nementobsigate:open-file). -
Assistant IA (
frontend/js/bookslm.js) â bouton « mode agent » dans l'en-tĂȘte (persistĂ© enlocalStorage) : l'envoi bascule vers/api/ai/bookslm/agent, affiche la trace des appels d'outils et les cartes de confirmation (Apply + aperçu diff) ;/chatreste le dĂ©faut. i18n FR/EN.
Modifié
- #82 Assistant IA â barre latĂ©rale Ă©purĂ©e & suivi visuel des requĂȘtes â la section
« Fournisseur & modÚle » perd ses intitulés (titre de section et libellé « Fournisseur : »)
pour rester discrÚte ; la description du contexte Général n'est plus affichée (bandeau de
statut masquĂ©, description accessible au survol de l'en-tĂȘte) ; le placeholder
« Posez une question sur ces documents⊠» est retiré ; l'indice clavier
« Entrée pour envoyer · Ctrl+Entrée⊠» est retiré ; le bouton « Envoyer » devient un emoji
compact (âïž). Les sĂ©lecteurs Fournisseur/ModĂšle adoptent la taille des autres contrĂŽles du
site (police 0,8 rem, hauteur 34 px, rayon 6 px) au lieu d'ĂȘtre plus fins. Un indicateur
d'activité apparaßt pendant le traitement et détaille le workflow : envoi, réception de la
réponse, appels d'outils (
Outil : XâŠ), attente de confirmation, succĂšs ou Ă©chec. Le menu contextuel de la racine d'une vault expose aussi « đ§ BooksLM », comme les rĂ©pertoires. i18n FR/EN (ai.activity_*,ai.composer_label). Tests JSDOM (tests/frontend/ai.test.mjs+2).
Corrigé
-
BUG-017 â Accueil mobile : tuiles « Favoris » / « RĂ©cents » mal dimensionnĂ©es â les cartes de tableau de bord dĂ©bordaient horizontalement Ă cause d'un titre/chemin
nowrap: ajout demin-width: 0etoverflow: hiddensur.dashboard-card(et ses en-tĂȘtes/pieds) pour que la grille mobile (1 colonne) respecte la largeur du viewport. Les tuiles « PartagĂ©s » Ă©taient dĂ©jĂ conformes. -
BUG-018 â Ăditeur mobile : boutons « Annuler » / « Sauvegarder » inaccessibles â l'en-tĂȘte cumulait marque, titre, nom de fichier et actions, poussant les boutons hors Ă©cran. Sur mobile, les Ă©lĂ©ments secondaires (marque, sĂ©parateur, espaceur, prĂ©sence) sont masquĂ©s, les champs titre/nom de fichier deviennent compressibles (
flex,min-width: 0) et le libellé « Saved » est masqué (le point d'état reste). La barre d'outils IA reçoit des cibles tactiles plus grandes. -
BUG-019 â Ăditeur mobile : barre d'outils masquĂ©e par le clavier â le ruban est dĂ©sormais ancrĂ© via
window.visualViewport(--kb-offset) pour rester juste au-dessus du clavier, quel que soit le défilement, et le scroller CodeMirror reçoit unpadding-bottompour ne pas cacher le curseur. -
BUG-020 â Ăditeur mobile : double barre de dĂ©filement â
.editor-bodypasse enoverflow: hidden+ colonne flex ; seul le scroller CodeMirror défile. -
BUG-016 â Mobile : le bouton « mode lecture » recouvre le bouton d'envoi de l'assistant â le bouton flottant
đ(#me-reading-btn,z-index: 890) passait au-dessus du panneau assistant plein Ă©cran sur mobile (z-index: 100) et masquait le bouton d'envoiâïž. Il n'apparaĂźt dĂ©sormais que lorsqu'un fichier est ouvert (state.currentPath) et que le panneau assistant est fermĂ© ; sa visibilitĂ© est resynchronisĂ©e Ă chaque mutation de#content-areaet sur les Ă©vĂ©nementsbookslm:opened/bookslm:closed. Tests JSDOM (tests/frontend/mobile-editor.test.mjs+2) et E2E mis Ă jour. -
BUG-015 â Assistant IA : sĂ©lection des menus
/et@invisible au clavier â l'Ă©lĂ©ment actif utilisaitbackground: var(--surface2), or--surface2est identique Ă--bg-primary(fond du menu) dans le thĂšme sombre par dĂ©faut : la ligne sĂ©lectionnĂ©e par les flĂšches â/â ne se distinguait pas. L'Ă©tat actif (et le survol) utilise dĂ©sormais--bg-hoveravec une barre d'accent Ă gauche (box-shadow: inset 3px 0 0 var(--accent)), pour les menus de commandes/mentions et la liste de modĂšles. Test JSDOM mis Ă jour. -
BUG-014 â Assistant IA : navigation clavier â/â des menus inopĂ©rante â la navigation Ă©tait liĂ©e au
keydowndu champ de saisie : dĂšs que le focus quittait la zone de texte (clic sur le menu, bouton EnvoyerâŠ), les flĂšches ne faisaient plus dĂ©filer les items. La gestion est dĂ©placĂ©e au niveau du panneau en phase de capture, ce qui fonctionne quel que soit l'Ă©lĂ©ment focalisĂ© dans la barre latĂ©rale. Tests JSDOM (tests/frontend/ai.test.mjs+1). -
BUG-013 â Assistant IA : « Aucun vault actif pour ouvrir ce lien » â les liens fichiers/rĂ©pertoires des rĂ©ponses utilisaient
_resolveVault()seul, nul en mode Général sans document ouvert._openFileLink()et_revealPath()utilisent désormais_activeVault()qui retombe sur le vault de contexte, le vault sélectionné dans la barre latérale, puis le premier vault disponible. Tests JSDOM (tests/frontend/ai.test.mjs+1). -
Assistant IA â caches obsolĂštes â
SW_VERSIONportĂ© Ă v6 et migration de purge Ă©largie Ă tous les cachesobsigate-*(clĂ©obsigate-sw-migrationâv3), afin que les clients bloquĂ©s sur une ancienne version rĂ©cupĂšrent bien le menu@et les correctifs. -
BUG-012 â Assistant IA : la commande
@n'affichait aucun menu en mode GĂ©nĂ©ral â sans vault rĂ©solu, la dĂ©tection@ne listait rien (menu masquĂ©) et le backend ignorait ensuite le contexte. Le menu est dĂ©sormais toujours rendu et_mentionVault()retombe sur le vault de contexte de la barre latĂ©rale, puis sur le premier vault disponible, avant de basculer survault=allpour les recherches. Tests JSDOM (tests/frontend/ai.test.mjs+1). -
BUG-011 â Assistant IA : noms de modĂšles illisibles dans la liste dĂ©roulante â la liste dĂ©roulante des modĂšles s'ouvrait alignĂ©e Ă gauche (
left: 0) et pouvait dĂ©passer le bord droit de la barre latĂ©rale (ancrĂ©e Ă droite), rendant les noms tronquĂ©s/illisibles ; elle est dĂ©sormais alignĂ©e Ă droite du dĂ©clencheur, large de 340 px (bornĂ©e Ă100vw - 24px), et les noms reviennent Ă la ligne (overflow-wrap: anywhere, police 0,78 rem) avec l'info-bulletitlecomplĂšte. Tests JSDOM (tests/frontend/ai.test.mjs). -
BUG-010 â Assistant IA : la commande
@n'ajoutait pas le contexte en mode GĂ©nĂ©ral â les fichiers/rĂ©pertoires choisis via@Ă©taient bien ajoutĂ©s sous forme de puces, mais le vault n'Ă©tait pas transmis : en mode GĂ©nĂ©ral (_vaultnul), la requĂȘte partait sansvaultet le backend ignorait le contexte ad-hoc. La sĂ©lection capture maintenant levaultrenvoyĂ© par/api/tree-search,_contextVault()le propage aux requĂȘtes/contextet/chat, et les recherches suivantes restent dans ce vault. Tests JSDOM (tests/frontend/ai.test.mjs). -
BUG-009 â Assistant IA : liste de modĂšles corrompue et clĂ©s i18n brutes â deux causes : (1) les fichiers de locale n'Ă©tant pas content-hashed, un
fr.jsonen cache HTTP affichait les clĂ©s brutes (ai.model_search,mobile_editor.*, âŠ) ; le chargement i18n utilise dĂ©sormaiscache: 'no-store'etSW_VERSIONest incrĂ©mentĂ© pour purger les anciens caches du service worker. (2) la liste de modĂšles (OpenRouter = plusieurs centaines d'entrĂ©es) pouvait se retrouver non stylĂ©e si la feuille de style Ă©tait en cache ; le picker applique maintenant les styles critiques en ligne (popover, liste en colonne, optionsdisplay:block), plafonne le rendu Ă 200 entrĂ©es avec un indicateur « ⊠N autres â affinez la recherche », et la recherche filtre le reste. Tests JSDOM (tests/frontend/ai.test.mjs+1). -
BUG-007 â Assistant IA : menus
/et@(navigation â/â et filtrage accentuĂ©) â la dĂ©tection des commandes/mentions et le filtrage des skills utilisaient des motifs ASCII ([a-z0-9-],\w) : dĂšs qu'un caractĂšre accentuĂ© Ă©tait saisi (/rĂ©sumĂ©,@cafĂ©), le menu se fermait. Les motifs sont dĂ©sormais Unicode (\p{L}) et la recherche est insensible aux accents (normalisation NFD). La navigation clavier est fiabilisĂ©e par un jeton de sĂ©quence qui ignore les rendus asynchrones obsolĂštes (frappe rapide) et fait dĂ©filer l'Ă©lĂ©ment actif dans la vue (scrollIntoView). Tests JSDOM (tests/frontend/ai.test.mjs+3). -
BUG-008 â Assistant IA : commande
@et contexte ad-hoc en mode GĂ©nĂ©ral â deux causes : (1) le backend ignorait les fichiers/rĂ©pertoires ad-hoc en mode GĂ©nĂ©ral car_resolve_system_promptne rĂ©solvait pas de vault (backend/bookslm_routes.py) ; le vault optionnel est maintenant rĂ©solu dĂšs que du contexte@est prĂ©sent. (2) sans vault courant, la recherche de mention Ă©chouait ; elle bascule dĂ©sormais survault=all. Tests backend (tests/test_bookslm.py+2) et frontend. -
#77 Desktop â banniĂšre de premier lancement rĂ©affichĂ©e Ă chaque dĂ©marrage â l'Ă©tat du wizard « Choisissez votre vault » n'Ă©tait mĂ©morisĂ© que dans le
localStoragede la webview et le paramĂštrehasVaultPathn'Ă©tait jamais renseignĂ©. Ajout d'un boolĂ©en persistantwizard_donedans la config desktop (desktop/src/main.rs, commandesget_wizard_state/complete_wizard, rĂ©tro-compatible via#[serde(default)]) : la banniĂšre ne rĂ©apparaĂźt plus aprĂšs un choix de dossier ou un clic « Plus tard », mĂȘme si le stockage webview est vidĂ©. Tests Rust (desktop/src/main.rs) et JSDOM (tests/frontend/desktop.test.mjs) ajoutĂ©s. -
Build Docker â « No space left » lors de
apt-get installâ le stage builder installait inutilementlibpango-1.0-0,libpangocairo-1.0-0etshared-mime-info(libs runtime de WeasyPrint, sans usage Ă la compilation), dupliquant les tĂ©lĂ©chargements apt. Ces paquets sont retirĂ©s du builder etapt-get cleanest ajoutĂ© dans les deux stages pour purger les.debconservĂ©s par dĂ©faut sous Debian trixie, rĂ©duisant l'empreinte disque et le temps de build. En complĂ©ment, purge du cache de build (docker builder prune) ayant libĂ©rĂ© l'espace nĂ©cessaire. -
BUG-005 â Chargement mobile incomplet derriĂšre Cloudflare (
og.dracodev.net) â le service worker utilisait une stratĂ©gie cache-first avec un nom de cache fixe (obsigate-v1) et un prĂ©cache de chemins erronĂ©s (/frontend/js/âŠ) : le Cache Storage du SW (distinct du cache navigateur/Cloudflare) servait un ancien build indĂ©finiment, mĂȘme aprĂšs purge. Le middleware renvoyait en plusCache-Control: public, max-age=31536000, immutablesur des assets non fingerprintĂ©s. Correctifs :frontend/sw.jsréécrit (network-first pour HTML/JS/CSS, caches versionnĂ©sSW_VERSION, prĂ©cache corrigĂ©/static/js/âŠ,skipWaiting/clients.claim) ; migration ponctuellelocalStorage(suppression des anciens caches) en remplacement du kill-switch de session ; en-tĂȘtesno-cachesur/static,index.html,manifest.jsonet pages HTML ; rechargement unique surcontrollerchange. Tests :tests/frontend/sw.test.mjs+TestStaticCaching. Guide Cloudflare : docs/PWA_GUIDE.md. -
Typage backend (mypy) â 33 erreurs corrigĂ©es (
backend/main.py,indexer.py,auth/router.py,pdf_reader.py,export.py,bookslm_routes.py) : annotations de types, gardesNonesurget_user(),PdfReader: Anyet importPROVIDERSmanquant dansmain.py(bug latent : le modÚle par défaut n'était jamais prépendé à la liste des modÚles live). L'étapemypydu CI devient bloquante (elle était en mode advisory). -
README â lien « Contributing » corrigĂ© vers
docs/CONTRIBUTING.md(était cassé vers la racine) ; arbre du projet mis à jour. -
#79 façade
backend/tools/api.pyâ gestion des namespace packages et du__init__ignorĂ© lors du chargement des modules d'outils.
Documentation
-
Guide d'architecture IA â
docs/AI_ARCHITECTURE_GUIDE.md(architecture, catalogue d'outils, sécurité, phases). -
Refonte de la documentation â la Roadmap ne contient plus que le travail Ă venir + un index compact ; les fonctionnalitĂ©s livrĂ©es sont archivĂ©es dans
docs/archive/COMPLETED_v1-v2.mdet documentées par feature dansdocs/features/. -
MĂ©thode de livraison unifiĂ©e â nouveau
docs/DELIVERY_WORKFLOW.md(Definition of Done : tests, documentation, commit, push, CI) etAGENTS.md(instructions obligatoires lues à chaque session). Référencés depuis la Roadmap, CONTRIBUTING et ISSUES_TODOLIST.
[2.2.1] â 2026-09-11
Ajouté
- Mobile â assistant AI central â bouton assistant dans la barre du bas (commit
50b823e).
Corrigé
- Version affichĂ©e dans l'UI â affichait
2.1.0au lieu de2.2.0(commit84bda90). - Mobile â boĂźte d'Ă©dition de l'assistant relevĂ©e au-dessus de la barre du bas (commit
f307ecb).
[2.2.0] â 2026-09-11
Ajouté
-
Assistant AI contextuel (sidebar) â l'assistant s'adapte dĂ©sormais au contexte d'ouverture :
- Répertoire (
directory) : ouvert depuis le menu contextuel d'un dossier â le contexte est le dossier et son contenu (mode historique BooksLM). - Documents (
documents) : ouvert via le bouton flottant quand un ou plusieurs documents sont ouverts â le contexte est la liste des fichiers ouverts (tous onglets/panneaux). - GĂ©nĂ©ral (
general) : ouvert via le bouton flottant quand aucun document n'est ouvert â l'assistant rĂ©pond sur l'application et peut proposer des actions (crĂ©er un fichier/dossier) via un blocobsigate-actionrendu en carte avec bouton « Appliquer » (aucune exĂ©cution automatique). - Le contexte est affichĂ© dans le header de la sidebar (icĂŽne, titre, sous-titre) et les suggestions de questions s'adaptent au mode.
- Backend :
/api/ai/bookslm/contextet/chatacceptentmode(directory/documents/general) etcontext_files;collect_files_context(),empty_context()etbuild_general_system_prompt()dansbackend/bookslm.py; le mode documents dégrade proprement vers le mode général si aucun fichier n'est lisible. - Tests :
tests/test_bookslm.py(+13 tests modes/documents/général) ettests/frontend/ai.test.mjs(+8 tests détection de contexte, clavier, actions, header).
- Répertoire (
-
#72 API publique documentĂ©e â OpenAPI 3.1 enrichie â documentation interactive complĂšte de l'API REST, gĂ©nĂ©rĂ©e automatiquement et enrichie.
- Backend
backend/openapi_docs.py: mĂ©tadonnĂ©es de tags (18 catĂ©gories : System, Auth, Files, PDF, Vaults, Search, Bookmarks, Backups, Export, AI, BooksLM, Sharing, Webhooks, Conflicts, Admin, Plugins, Push, Frontend), assignation automatique des tags par prĂ©fixe de route (normalisation des tags des routeurs), schĂ©mas de sĂ©curitĂ© (bearerAuth,cookieAuth), exemples de requĂȘte/rĂ©ponse sur les endpoints clĂ©s, rĂ©ponses d'erreur documentĂ©es (401/403/404/422/500), serveur etexternalDocs. backend/schemas.py: nouveauxresponse_modelPydantic pour les endpoints qui n'en avaient pas (recent, bookmarks, saved searches, backups, diff/restore/backlinks, pdf/info, replace, vaults, attachments, settings, config, AI keys/models, diagnostics, dashboard, webhooks, shares, conflicts, BooksLM context, AI status).backend/main.py:FastAPI(...)enrichi (description Markdown, contact, licence, tags) et overrideapp.openapipour post-traiter le schĂ©ma ; page de documentation/api(HTML autonome listant les endpoints groupĂ©s par catĂ©gorie, liens vers/docs,/redoc,/openapi.json).- Frontend : entrĂ©e « API » dans le menu d'options (i18n FR/EN) ouvrant Swagger UI.
- Tests :
tests/test_openapi.py(58 tests â version 3.1, tags, sĂ©curitĂ©, erreurs, exemples, schĂ©mas de rĂ©ponse, pages/api,/docs,/redoc,/openapi.json).
- Backend
-
#61 Plugins systĂšme au complet â systĂšme de plugins permettant d'Ă©tendre ObsiGate (renderers personnalisĂ©s, filtres de recherche, actions d'Ă©diteur), sandboxĂ© pour la sĂ©curitĂ©.
- Backend
backend/plugins.py: validation du manifestplugin.json(name regex lowercase, semver, hooks/permissions autorisés), stockage par vault<vault>/.obsigate-plugins/, lifecycle complet (install/uninstall/enable/disable via marker.disabled), validation ZIP à l'upload (anti path-traversal, max 100 fichiers, 500KB/fichier, 5MB upload), 9 endpoints/api/plugins/*(list/get/hooks/code/template + install/uninstall/enable/disable admin-gated), template API, scan au démarrage par vault (get_plugin_registry().scan_vault). - Frontend
frontend/js/plugins.js: PluginManager (install/uninstall/enable/disable/view-code), sandbox d'exécution via Web Worker (code chargé par blob URL, protocolepostMessagestructuré, isolation DOM/localStorage/network selon permissions), hooks dispatch (executeHook,onFileRender,onSearchFilter,onEditorAction,onSidebarItem,onFileCreate,onFileDelete,onVaultMount), UI Settings > Plugins. - Sécurité : manifest de permissions (
read_files,write_files,network_request, ⊠restreint), CSP stricte sansimportScripts, limites de taille. - Tests :
tests/test_plugins.py(44 tests â validation manifest, lifecycle manager, validation ZIP/directory, dĂ©marrage scan) +tests/frontend/plugins.test.mjs(21 tests JSDOM â protocole sandbox Worker, isolation DOM, lifecycle mirror). - CI : job lint ajoute
node plugins.test.mjsaux tests JSDOM. - Docs :
docs/PLUGINS.md(manifest, hooks, permissions, modÚle de sécurité, API, guide).
- Backend
-
#78 Excalidraw â finitions : dĂ©compression lz-string du format plugin Obsidian, crĂ©ation depuis la modale et le menu contextuel, extraction du texte pour la recherche (B5), support
.excalidraw.md(commitac16fc1+ correctifs associés). -
#67 Notifications web (Push API) :
backend/push.py,POST /api/push/subscribe, clés VAPID dansconfig.json, toggle par vault, payload (fichier/vault/action) et ouverture du fichier au clic (commitac16fc1). -
#68 Health check enrichi :
GET /api/health/detailed(admin-gated) exposant index, mémoire (RSS/heap), uptime, connexions SSE, backups et espace disque (commitac16fc1). -
#77 Desktop â jumplist vaults rĂ©cents dans le menu DĂ©marrer (commit
ac16fc1). -
#75 Split View â matrice E2E complĂšte (37 tests) : 16 tests
split-view.spec.js(raccourcis, drag & drop, persistance, navigation clavier) + 21 testssplit-view-matrix.spec.jscouvrant 100% des cas d'ouverture/fermeture.
Documentation
- #78 Excalidraw â doc utilisateur finalisĂ©e :
.excalidraw/.excalidraw.mdajoutés aux formats supportés (README FR/EN), nouvelle section « Diagrammes Excalidraw » dans le guide intégré (i18n FR/EN) et note de compatibilité avec le plugin Obsidian Excalidraw. - Roadmap : #78 marqué terminé (B5 extraction texte, C8 menu contextuel, F3 E2E
tests/e2e/excalidraw.spec.js, H1-H3 docs) ; F2 non retenu. Points optionnels #61 (dépÎt communautaire de plugins) et #74 (D2/E4/H2/I2) explicitement marqués non retenus.
Corrigé
-
Assistant AI â sidebar qui ne s'ouvrait plus & erreur de contexte :
- Le bouton flottant passait le chemin d'un fichier comme rĂ©pertoire de contexte, d'oĂč l'erreur « Aucun fichier markdown trouvĂ© dans ce dossier » Ă l'ouverture sur un document. Le contexte est maintenant dĂ©tectĂ© automatiquement (documents ouverts â mode documents, sinon mode gĂ©nĂ©ral).
- Un panneau précédemment masqué (
obsigate-bookslm-hidden=truepersistĂ© en localStorage) restait cachĂ© lors d'une ouverture explicite â l'ouverture force dĂ©sormais l'affichage. - Ergonomie du header : le sĂ©lecteur fournisseur/modĂšle Ă©tait sur la mĂȘme ligne que les actions et masquait ces derniĂšres ; il est dĂ©placĂ© sur une seconde ligne dĂ©diĂ©e (toolbar) pour que « nouvelle conversation / export / plein Ă©cran / fermer » restent toujours visibles.
- Clavier de la boĂźte de chat :
EntrĂ©eenvoie la requĂȘte,Ctrl+EntrĂ©einsĂšre un saut de ligne (au lieu de l'inverse), avec un texte d'aide sous le champ.
-
Outil AI de l'UI â fiabilisation :
- BooksLM (chat IA par rĂ©pertoire) : les requĂȘtes
context/chatn'envoyaient pas le jeton d'authentification (Ă©chec 401 quand l'auth est activĂ©e) et la rĂ©ponse SSE Ă©tait mal parsĂ©e (le backend Ă©met{token: ...}, le front lisaitdata.content) â les rĂ©ponses n'apparaissaient jamais. Le message utilisateur envoyĂ© Ă©tait le placeholder assistant vide au lieu du texte saisi. CorrigĂ© : requĂȘtes authentifiĂ©es viaAuthManager(retry 401), parsing SSEevent:/data:avec supporttoken/error, historique construit avant l'ajout du message courant, barre de progression basĂ©e surmax_total_chars. - AI Editor : le raccourci
Ctrl/Cmd+J(complĂ©tion inline) Ă©tait re-liĂ© Ă chaque ouverture de l'Ă©diteur (N listeners â N requĂȘtes) ; un seul listener global est dĂ©sormais posĂ©. Les libellĂ©s de la barre d'outils AI Ă©taient codĂ©s en dur (FR/EN mĂ©langĂ©s) â i18n complet. La réécriture personnalisĂ©e utilisaitwindow.prompt()â remplacĂ©e par une modale accessible (Ăchap annule, Ctrl/Cmd+EntrĂ©e valide).
- BooksLM (chat IA par rĂ©pertoire) : les requĂȘtes
-
Recherche cassée (régression plugins) :
onSearchFilter()Ă©tait appelĂ©e avec 2 arguments au lieu de 3 (frontend/js/search.js), renvoyaitundefined, faisait Ă©chouer le rendu des rĂ©sultats et basculait silencieusement sur la recherche hors-ligne (0 rĂ©sultat). CorrigĂ© â la recherche full-text et l'autocomplĂ©tion refonctionnent (20 tests E2E). -
.excalidraw.mdcorrompu à l'ouverture : Excalidraw émetonChangeau montage, ce qui déclenchait un auto-save 2 s plus tard réécrivant le fichier au format JSON brut et détruisant le format plugin Obsidian (frontend/excalidraw-editor.html+frontend/js/excalidraw-viewer.js). Les changements initiaux sont désormais ignorés et le formatfrontmatter + compressed-jsonest préservé à la sauvegarde. -
Splash / tests E2E :
window.__OBSIGATE_BOOTEDĂ©tait posĂ© avant la fin deinit()â le splash disparaissait trop tĂŽt et les tests E2E interagissaient avant que les handlers soient liĂ©s. Le flag est maintenant posĂ© aprĂšs rĂ©solution deinit()(frontend/js/app.js), etgoHome()/login()attendent ce signal. -
Tests E2E Excalidraw : réécriture de
tests/e2e/excalidraw.spec.jsavec les sélecteurs réels (modale.obsigate-modal+#file-ext-select/#file-name-input, menu contextuel,canvas.first()pour les deux couches canvas).
[2.1.0] â 2026-09-08
Ajouté
- #74 Support PDF au complet â
GET /api/file/{vault}/pdf/info(mĂ©tadonnĂ©es sans contenu), streaming avec HTTP Range / 206 Partial Content (rendu progressif des gros PDF), configOBSIGATE_PDF_MAX_SIZE_MB(50) +OBSIGATE_PDF_EXTRACT_TIMEOUT(30s). 16 tests supplĂ©mentaires (26 au total danstest_pdf.py). - #64 MFA â WebAuthn (second facteur en plus du TOTP) : enregistrement de clĂ©s de
sécurité / biométrie (Windows Hello, Touch ID), assertion au login, gestion des clés dans
« Sécurité du compte », codes de récupération émis à l'activation. Nouveau module
backend/auth/webauthn_mfa.py(libwebauthn==2.6.0, challenges in-memory TTL 180s Ă usage unique). 10 tests avec authentificateur virtuel (CBOR rĂ©el, ECDSA P-256). i18n FR/EN (13 clĂ©s). Config :OBSIGATE_WEBAUTHN_RP_ID/_RP_NAME/_ORIGINS. - #77 Desktop â port auto-increment :
pick_free_port()scanne 17890..17899 si le port est occupé (2 instances cÎte à cÎte possibles) + 3 tests Rust (19 au total cÎté desktop). - Docs : sections PDF README FR/EN (Range, /pdf/info), variables env, guide WebAuthn.
- #75 Split View â matrice E2E complĂšte (37 tests) : 16 tests
split-view.spec.js(raccourcis, drag & drop, persistance, navigation clavier) + 21 testssplit-view-matrix.spec.jscouvrant 100% des cas d'ouverture/fermeture : boutons ââ/ââ, menu contextuel (diviser bas, fermer, fermer les autres/Ă droite/tout, fermer le panneau, flyout « DĂ©placer vers⊠»), palette (diviser, focus suivant/prĂ©cĂ©dent, reset), fermeture par X/double-clic/molette/Ctrl+W, auto-collapse d'un panneau vidĂ©, plafond 4 panneaux, drag-to-split bas, pas de doublon Ă la rĂ©ouverture. - Fix
scripts/run-e2e-local.sh: chemins Windows viacygpath(les env vars MSYS n'Ă©taient pas converties â vaults vides, les 16 tests split-view Ă©chouaient en local alors qu'ils passaient en CI).
Corrigé
- PDF stream 500 :
api_pdf_streamplantait systĂ©matiquement (NameError: current_usernon injectĂ© â endpoint jamais couvert par un test). DĂ©sormais authentifiĂ© + testĂ©. - Indexation incrĂ©mentale des PDF : le chemin watcher (
_index_single_file_sync) lisait les PDFs enread_text()â contenu garbage indexĂ©. Utilise maintenantextract_pdf_text()comme le scan complet.
[2.0.0] â 2026-08-25
ObsiGate passe à 2.0.0 avec sa version bureau native et de nombreuses fonctionnalités de productivité (branch main, 341 commits aprÚs le tag v1.8.0).
Ajouté
- Application bureau native (Tauri 2) â Porte d'entrĂ©e desktop pour vaults Obsidian (
desktop/) - Dashboard administrateur (#71, backend) â 4 endpoints admin-gated pour monitoring serveur
GET /api/admin/statsâ CPU/RAM/Disk/Uptime via psutilGET /api/admin/auditâ 500 derniĂšres entrĂ©es d'audit avec filtresuser/action/limit/offsetGET /api/admin/backup-statsâ compte + taille + age par vaultGET /api/admin/streamâ Server-Sent Events qui push les stats toutes les 5s- Nouveau module
backend/admin.py+ 13 tests pytest
- Tests JSDOM PaneManager (#75, sous-tĂąche I2) â 9 tests d'intĂ©gration frontend via JSDOM 30
- Couvre : factory, init, open/activate/close, isolation entre panes, drag/drop smoke
- Wired dans le CI Gitea (
.gitea/workflows/ci.yml) - Shell Rust + Tauri 2 (tray icon, notifications OS, auto-update depuis Gitea)
- Backend Python embarqué (python-embed) avec health check, démarrage ~2s
- Sélecteur de dossiers natif, config persistante des vaults (type VAULT vs DIR)
- FenĂȘtre console masquĂ©e, arrĂȘt propre via tray, associations de fichiers
.md - Packages : Windows MSI + NSIS, Linux .deb + AppImage
- Pipeline CI/CD Desktop (
.gitea/workflows/desktop-build.yml) - ThÚme systÚme auto (clair/sombre) + RAM réduite (~80 MB au repos)
- Ăcran de chargement inline (staging backend/frontend pour le bundle desktop)
- Internationalisation FR/EN complĂšte â 1357 clĂ©s i18n, prĂ©fĂ©rence serveur, guide entiĂšrement traduit
- Vue multi-panneaux (Split View #75) â PaneManager + TabManager par panneau
- Split droite/bas, drag & drop cross-pane, drag-to-split (bord droit/bas)
- Boutons de split, navigation clavier, fermeture auto des panneaux vides
- Mermaid.js â Rendu de diagrammes (22 templates, thĂšme dark synchronisĂ©)
- Header bar Code/Preview, zoom, export SVG + PNG, plein écran / focus 480px
- Pré-processeur Obsidian (
[[liens]],![[img]],==highlight==)
- Gestionnaire de Backups complet â Page, filtres, purge, restauration
- Diff viewer (unifié + cÎte à cÎte), preview 100 Ko, compression gzip
- Backup automatique, auto-nettoyage (max_backups_per_file)
- Support Excalidraw (#78) â Fichiers
.excalidraw/.excalidraw.md- Décompression lz-string, création depuis modale/menu contextuel
- Ăditeur Forge + autocomplĂ©tion IA â Auto-height, Mermaid QI, ghost text
- Autocomplétion Ollama (qwen2.5-coder), Alt+/, auto-continuation listes/checkboxes
- Support PDF + multi-format â PDF avec TOC, images/CSV/JSON/TXT
- 15 thĂšmes clair/sombre (#65) â SystĂšme de thĂšmes configurable
- Mode hors-ligne PWA (#59) â Badge hors-ligne + gestion des conflits
- Tests E2E Playwright (#58) â Suite desktop (44 tests) + CI
Modifié
desktop/â Nouveau : application Tauri (Cargo.toml, build.rs,src/main.rs, scripts build)frontend/â i18n, split view, Mermaid, Excalidraw, Forge, thĂšmesbackend/â Endpoints backups, Excalidraw, multi-format, versioning gitdocs/ROADMAP.mdâ Feuille de route passĂ©e Ă 2.0.0-dev, items #75/#78 complĂ©tĂ©s
[1.8.0] â 2026-06-04
Ajouté
- Palette de commandes â Navigation rapide fichiers + commandes
- Raccourcis :
Ctrl+Pfichiers,Ctrl+Alt+Espacecommandes,Ctrl+Shift+Espace - Navigateur de dossiers : créer/supprimer fichiers/dossiers par sélection
- Opérateurs
+include/-excludedans la recherche globale - 6 nouvelles commandes : créer/supprimer fichiers/dossiers, éditer, pop-out
- Raccourcis :
- Barre d'outils mobile de bas de page â Type Obsidian đ±
- Explorateur, recherche, palette, changement d'onglet
- Indicateur de vault contextuel sous le header, pull-to-refresh
- Diff viewer des backups â Comparaison unifiĂ©e + cĂŽte Ă cĂŽte, restauration
- Indicateur AI Actif â Badge/statut IA dans le header (lecture runtime des clĂ©s)
- Page d'accueil de vault â Liste rĂ©cursive des fichiers par date
- Drag & drop de fichiers dans l'arborescence
- Guide d'aide enrichi â Recherche, scroll spy, slide-over mobile, section webhooks
- Indexation inversée non-bloquante (
run_in_executor) - Infrastructure de tests â Couverture pytest portĂ©e Ă 70% (+109 tests)
Modifié
frontend/â Palette, mobile toolbar, aide, AI indicator, vault homebackend/â Indexation non-bloquante, statut IA, diff/restauration backupsdocs/â Guide d'utilisation enrichi (navigation clavier), CHANGELOG/README/ROADMAP
Corrigé
- Correctifs UI mobile, palette, aide et AI toolbar (thĂšme clair, menu clipping)
[1.7.0] â 2026-05-30
Ajouté
- AI Editor Toolbar â Barre d'outils IA intĂ©grĂ©e Ă l'Ă©diteur CodeMirror
- Menus dropdown : Edit (improve, fix spelling, shorter, longer, simplify), Tone (professional, casual), Translate (multi-langue), Generate (explain, summarize, continue), Custom Rewrite, Toolbox (to list, to table, frontmatter, to canvas)
- Multi-provider : DeepSeek / OpenRouter / Gemini, configurable via
.env - 16 endpoints REST :
POST /api/ai/{edit|tone|translate|generate|rewrite|toolbox} - Auto-save silencieux (2s debounce) avec feedback visuel toast
- Cache toolbar si pas de clé API configurée
- Messages d'erreur clairs (401âclĂ© invalide, etc.)
- Graph view â AmĂ©liorations majeures
- Header flat design 2 lignes responsives (titre flexible + recherche dédiée + barre statut)
- Navigation historique â â + â Parent
- Sticky panels : tuile info (top-left/right) avec métadonnées, preview pleine hauteur (droite)
- Ctrl+survol â aperçu contenu formatĂ© (via
/raw) dans tooltip - Filtre par tag dans la vue graphe
- Boutons close â sur les panneaux
- Fond hover foncé unifié
Modifié
- backends/ai.py â Nouveau module IA backend
- backends/ai_routes.py â Routes API pour l'Ă©diteur IA
- frontend/js/ai.js â Module frontend de la toolbar IA (404 lignes)
- frontend/js/graph.js â Refonte complĂšte : sticky panels, nav historique, aperçu markdown
[1.6.0] â 2026-05-29
Ajouté
- Vue graphe des wikilinks â Canvas force-directed
- Phase 1 : Full-vault view, filtre par tag, backlinks entrants, mĂ©triques de nĆud
- Phase 2 : Recherche visuelle, tooltips survol, couleurs adaptatives, slider profondeur (0-3)
- Phase 3 : Filtre par type (dossier/fichier/.md/autre), mode focus, plein écran, export PNG
- Phase 4 : Barnes-Hut O(n log n), cache graphe
- sortedcontainers â O(log n) insert/remove dans l'index inversĂ©
- CI/CD Pipeline complet â Gitea Actions
- Ruff linting (0 erreur)
- Mypy type checking (0 erreur)
- Pytest â 175 tests, 49% coverage
- Bandit SAST â scan de sĂ©curitĂ©
- Pip-audit â vulnĂ©rabilitĂ©s dĂ©pendances
- Docker build â vĂ©rification image
- Coverage artifact â uploadĂ© via
actions/upload-artifact@v3 - Runner Gitea auto-hébergé (
gitea/act_runner:0.2.11sur Alpine/Proxmox)
Modifié
backend/search.pyâ Remplacement bisect â SortedList pour le vocabulaire.gitea/workflows/ci.ymlâ Pipeline CI/CD complet
Corrigé
- Résolution de 28 erreurs mypy pré-existantes
- Fix lint ruff + faux positifs bandit + pip-audit non-bloquant
[1.5.1] â 2026-05-28
Ajouté
- Split
app.js(8 875 lignes) en 16 modules ES- Modules :
state.js,utils.js,auth.js,ui.js(76KB),viewer.js(47KB),sidebar.js,search.js(45KB),config.js,dashboard.js,graph.js(33KB),sync.js,legacy.js,ai.js - Import/export validator CI (
tests/frontend/validate-imports.mjs) - Tests unitaires frontend (
tests/frontend/unit.test.mjs)
- Modules :
- Stemming français â
snowballstemmerintégré au tokenizer- "manger" trouve "mangé", "mangeons", "mangeait"
- Performance O(T) au lieu de O(SĂT) â fix freeze 15min sur gros vaults
- Crash guard : try/except snowballstemmer IndexError sur tokens exotiques
Modifié
frontend/js/app.jsâ entrypoint ES module important les 16 modulesbackend/search.pyâ tokenizer avec FrenchStemmer
Corrigé
- Nombreuses régressions post-split : imports manquants, exports oubliés, shadowing de variables
- Réécriture state.js â mutable object (
export const state = {...}) pour éviter les erreursassignment to constant - Plus de 60 correctifs d'imports/exports validés par le validator CI
- Tags de template
{{...}}exclus du tag cloud via filtre configurable
[1.5.0] â 2026-05-26
Ajouté
- Publication publique â GĂ©nĂ©ration de lien partageable avec token unique (64-char hex)
- Expiration configurable, lecture seule, sans authentification
backend/share.py+ endpoints CRUD + vue publique/s/{token}- Export PDF via WeasyPrint (lazy import) dans la vue publique
- Support fichiers non-Markdown dans la vue publique
- Webhooks â Notifications HTTP POST vers services externes
- Signature HMAC-SHA256 optionnelle
backend/webhooks.py+ CRUD endpoints + UI dans Configuration
- Dashboard statistiques â MĂ©triques agrĂ©gĂ©es par vault
- Widget
DashboardStatsWidgetavec 4 cartes (fichiers, tags, taille, vaults) - Widget "Derniers fichiers ouverts" avec timestamps
- Widget
- Documentation OpenAPI enrichie â Tous les modĂšles Pydantic documentĂ©s (
Field(description=...))- Visible dans
/docs(Swagger UI) et/redoc
- Visible dans
- Documentation complĂšte â
ANALYSE_REVIEW.md,AUDIT_TECHNIQUE.md,ROADMAP.md
Modifié
frontend/js/app.jsâ Nouveau systĂšme d'onglets (TabManager), dashboardfrontend/style.cssâ Dashboard, share view, webhooks UIbackend/main.pyâ Nouveaux endpoints share/webhooks/dashboardbackend/search.pyâ Index inversĂ© incrĂ©mental (hook pattern)
[1.4.0] â 2026-05-25
Ajouté
- Rate limiting â IP-based (10 tentatives/15min) + lockout par compte (5 tentatives)
backend/ratelimit.pyâ RateLimiter thread-safe avec nettoyage pĂ©riodique- IntĂ©grĂ© Ă
backend/auth/router.py
- Secret redactor â Masquage automatique des secrets dans les aperçus
backend/secret_redactor.pyâ JWT, API keys, tokens GitHub, clĂ©s privĂ©es, connection strings
- Audit log â Traçage des Ă©critures/suppressions/changements de config
backend/audit.pyâ JSON lines dansdata/audit.log, rotation 10MB
- Backup automatique avant écriture
- Sauvegarde du contenu original dans
.obsigate-backup/avant PUT/DELETE
- Sauvegarde du contenu original dans
- Backlinks panel â Fichiers avec wikilinks pointant vers le fichier courant
GET /api/file/{vault}/backlinks+ index inversé dansindexer.py
- Gestion des conflits Syncthing
- Détection automatique des fichiers
.sync-conflict-* - Résolution : garder local, garder conflit
GET /api/conflicts,POST /api/conflicts/resolve
- Détection automatique des fichiers
- Syncthing conflicts dashboard â Vue dĂ©diĂ©e dans l'UI
- IGNORED_DIRS configurable â
OBSIGATE_IGNORED_DIRS(liste sĂ©parĂ©e par virgules) - Timeout de session configurable â
OBSIGATE_ACCESS_TOKEN_TTL/OBSIGATE_REFRESH_TOKEN_TTL
Modifié
backend/main.pyâ +audit, +backup, +redaction, +backlinks endpoint, +conflicts endpointbackend/indexer.pyâ +backlink index, +IGNORED_DIRSbackend/auth/router.pyâ +IP rate limitingbackend/auth/jwt_handler.pyâ +configurable TTLbackend/watcher.pyâ +configurable IGNORED_DIRS
[1.3.0] â 2026-05-23
Ajouté
- Authentification complĂšte â JWT + Argon2id
- Login/logout, refresh tokens, cookies httpOnly
- ContrĂŽle d'accĂšs par vault
- Interface d'administration : création/modification/suppression d'utilisateurs
- "Se souvenir de moi", sessions persistantes
backend/auth/â 5 modules (~600 lignes)
- CodeMirror 6 â Ăditeur de fichiers intĂ©grĂ©
- Syntax highlighting multi-langage
- Sauvegarde, annulation, fallback textarea si CM6 échoue
- Auto-sync frontmatter YAML
- Find-in-page (Ctrl+F) avec regex, barre de navigation
- PWA complet â
manifest.json,sw.js, icĂŽnes multi-tailles- Installation via bouton "Installer l'application"
- ThĂšme synchronisĂ© entre fenĂȘtres popout
- Service Worker avec mise en cache
- Synchronisation temps rĂ©el â Watchdog + SSE
- Surveillance automatique des fichiers
- Mise à jour incrémentale de l'index
- SSE Manager avec reconnexion automatique
backend/watcher.pyâ watchdog observer avec debounce 2s
- Drag & drop / rename â Menu contextuel arborescence
- Création fichier/dossier, rename inline, suppression
- Boutons d'action toujours visibles, support mobile long-press
Modifié
frontend/app.jsâ Refonte majeure : authentication flows, code editor, PWA, syncfrontend/style.cssâ CodeMirror themes, auth forms, PWA UI, responsivedocker-compose.ymlâ auth env vars, data volume, non-root userbackend/main.pyâ auth middleware, file CRUD, code editor API, SSE, PWArequirements.txtâ argon2-cffi, python-jose, python-multipart
[1.2.0] â 2026-05-18
Ajouté
- Rendu d'images Obsidian â Support complet de toutes les syntaxes
- Standard Markdown avec attributs HTML
- Wiki-link embed (
![[path/to/image.png]]) - Markdown standard (
) - Résolution multi-stratégies (7 niveaux)
- Indexation des attachements au démarrage
- Cache de résolution pour performance
- SystĂšme de fichiers cachĂ©s â Configuration par vault
includeHidden,hiddenWhitelistâ UI + env vars- Filtrage cĂŽtĂ© client (hideHiddenFiles)
Modifié
backend/attachment_indexer.pyâ Scan et indexation d'imagesbackend/image_processor.pyâ PrĂ©traitement Markdown pour les syntaxes d'imagesGET /api/image/{vault}?path=â Serve images avec MIME typesPOST /api/attachments/rescan/{vault}â Rescan manuelHIDDEN_FILES_GUIDE.md,IMAGE_RENDERING_GUIDE.md
[1.1.0] â 2026-05-15
Ajouté
- Recherche TF-IDF avancĂ©e â Moteur complet avec index inversĂ©
- Opérateurs :
tag:,vault:,title:,path:,ext: - Autocomplétion intelligente (fichiers, tags, historique)
- Facettes, pagination, tri par pertinence
- Snippets surlignés
<mark>, accent-insensitive - Search history (localStorage, max 50, LIFO, dédupliqué)
- Opérateurs :
- Recherche regex â
extractRegexSnippet()avec surlignage - Recherches sauvegardĂ©es â CRUD API + sidebar UI
- Sauvegarde/chargement/suppression de requĂȘtes
- Filtres de recherche â toggles (case, mot entier, regex), chemins
- Onglets sidebar â vaults, tags, rĂ©cents, saved searches
- Auto-expand vault dans le filtre sidebar
- Tree search â Filtrage temps rĂ©el de l'arborescence avec surlignage
Modifié
backend/search.pyâ Nouveau : InvertedIndex, TF-IDF, autocompletefrontend/app.jsâ Refonte recherche : nouveau systĂšme de requĂȘtes, facettes, pagination, autocompletefrontend/style.cssâ Search results cards, autocomplete dropdown, tags
[1.0.0] â 2026-05-10
Ajouté
- PremiĂšre version stable â Porte d'entrĂ©e web pour vaults Obsidian
- Multi-vault â Visualisation de plusieurs vaults simultanĂ©ment
- Arborescence â Navigation hiĂ©rarchique avec lazy-loading
- Rendu Markdown â Conversion HTML via mistune (tables, task lists, footnotes, strikethrough)
- Extraction YAML frontmatter â Tous les champs parsĂ©s avec carte pliable, badges, tags
- Vue Source (raw) â Toggle markdown brut + frontmatter
- Ădition â PUT/DELETE fichiers via API
- Breadcrumbs â Navigation avec auto-expand et highlight
- TOC â Table des matiĂšres avec scroll spy et barre de progression
- ThĂšme clair/sombre â Toggle localStorage + synchronisĂ© fenĂȘtres popout
- Popout â FenĂȘtre dĂ©tachĂ©e pour affichage standalone
- Configuration UI â ParamĂštres persistants par vault
- Docker multi-stage â Image ~180MB, linux/amd64 + arm64 + arm/v7 + i386
- Healthcheck â Endpoint
/api/health - Headers sĂ©curitĂ© â CSP, X-Frame-Options, XSS-Protection, Referrer-Policy
- Path traversal protection â
_resolve_safe_path()symlink-aware - Security hardening â Utilisateur non-root (UID 1000)
- Compression GZip (SSE-safe), Cache-Control immutable
- build.sh â Script de build automatisĂ©
Architecture
- Backend : FastAPI 0.110.3, uvicorn 0.30.0, Python 3.11+
- Frontend : Vanilla JS SPA (0 dépendances npm), CSS custom properties
- Indexation : In-memory, mise à jour incrémentale, watcher watchdog
- Recherche : TF-IDF inversé, sans I/O disque