Files
ObsiGate/CHANGELOG.md
T
bruno d6cdd670b1
CI / lint (push) Successful in 1m14s
CI / security (push) Successful in 44s
CI / test (push) Successful in 3m0s
CI / build (push) Successful in 1m3s
CI / e2e (push) Successful in 10m38s
fix(ai): selection visible des menus et retrait de l'indice clavier (BUG-015)
BUG-015: l'etat actif des menus / et @ (et de la liste de modeles) utilise --bg-hover + barre d'accent a gauche, car --surface2 est identique a --bg-primary en theme sombre. Retrait de l'indice 'Entree pour envoyer...' sous la zone de saisie.
2026-09-12 19:00:05 -04:00

904 lines
56 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog — ObsiGate
Toutes les modifications notables d'ObsiGate sont documentées dans ce fichier.
Format basé sur [Keep a Changelog](https://keepachangelog.com/fr/1.1.0/),
et [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
> **En cours de développement** : les changements non publiés sont dans la section
> [Unreleased](#unreleased). La dernière version publiée est **2.2.1**.
---
## [Unreleased]
### Ajouté
- **#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-skill` permet 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ée
`backend/model_capabilities.py`, endpoints `GET /api/ai/model-capabilities` et `GET /api/ai/skills`,
support multimodal dans `backend/ai_chat.py` et `backend/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.py` et `tests/frontend/ai.test.mjs` (+9). Détail :
[docs/features/ai-assistant-commands.md](./docs/features/ai-assistant-commands.md).
- **#77 Desktop — Signature des mises à jour Tauri** — la paire de clés `minisign`
de l'updater est générée et sa clé publique est embarquée dans
`desktop/tauri.conf.json` (`plugins.updater.pubkey`, remplace le placeholder) ;
`bundle.createUpdaterArtifacts: true` produit les fichiers `.sig` par artefact.
Le workflow `.gitea/workflows/desktop-build.yml` expose les secrets
`TAURI_SIGNING_PRIVATE_KEY` / `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` aux 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](./docs/DEVELOPMENT_AND_RELEASES.md#2bis-signature-des-mises-à-jour-updater-tauri).
- **#77 Desktop — Manifeste de mise à jour `latest.json`** — nouveau
`scripts/updater_manifest.py` qui construit le document consommé par l'updater
Tauri (version, notes, `pub_date`, `platforms` Windows/Linux avec signature
`.sig` et URLs des assets). Il est généré automatiquement par
`scripts/publish_release.py` (écrit `desktop/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 automatiquement
`desktop/obsigate-updater.key` pour 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`](./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 `/embeddings` compatible 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), avec
`semantic_score` par résultat. **Indexation incrémentale** branchée sur le watcher (un fichier
modifié régénère son embedding). **UI** : toggle « Recherche sémantique » (`~`, raccourci
`Alt+S`) dans la barre de résultats + affichage du score de similarité, clés i18n FR/EN.
Nouveau module `backend/semantic_search.py`, paramètre `semantic` sur
`/api/search/advanced`, dépendances **optionnelles** dans
`backend/requirements-semantic.txt`. Tests : `tests/test_semantic_search.py` (27) +
`tests/frontend/semantic-search.test.mjs` (4). Détail :
[docs/features/semantic-search.md](./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 module
`frontend/js/mobile-editor.js`, styles `frontend/style.css`, clés i18n FR/EN. Tests :
`tests/frontend/mobile-editor.test.mjs` (22 tests). Détail :
[docs/features/mobile-editor.md](./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 (cookie `access_token` ou paramètre `token`) + `check_vault_access` et
`resolve_safe_path` par connexion. **Yjs/CRDT** côté client : `Y.Doc`/`Y.Text` fusionnent 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 frontend `frontend/js/collab.js` (provider + liaison Y.Text↔CodeMirror +
curseurs distants) et `backend/collab.py` (`CollabManager`). Tests : `tests/test_collab.py`
(17 tests, dont 5 clients simultanés) et `tests/frontend/collab.test.mjs`. Détail :
[docs/features/collaboration.md](./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` ;
erreur `rate_limited`). **Quotas** `BOOKSLM_MAX_*` : `BOOKSLM_MAX_TOOL_CALLS` plafonne les appels
d'outils par run d'agent (`stopped="quota_exceeded"`) et `BOOKSLM_MAX_TOOL_READ_BYTES` plafonne
`read_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** :
tag `MCP` + injection du path `/mcp` (Streamable HTTP) dans le schéma ; nouveau
[`docs/MCP_GUIDE.md`](./docs/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 MCP `read`→`propose`→`apply`→`resources/read`).
- **#79 Phase E — Serveur MCP (Streamable HTTP)** — nouvel endpoint `/mcp` exposant ObsiGate à des
clients MCP externes (Claude Desktop, Cursor…) via le SDK Python `mcp==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-step `propose_<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>` et `vault://<name>/<path>` (lecture seule, secrets redactés). **Prompts** :
`summarize-directory`, `generate-note`, `find-related`. Auth `Authorization: Bearer <JWT>` →
`get_current_user` ; permissions et toggle destructif par vault (`aiDestructiveTools`) appliqués.
Nouveaux modules `backend/mcp/server.py` et `backend/mcp/confirmations.py` ; dépendances
`mcp==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éutilisable `backend/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}/restore` et `/api/search/replace`
délèguent désormais à cette couche. `backend/services/backups.py` expose `create_backup`
(source unique, réutilisée par `main._backup_file`). Confirmations **two-step** : tout outil
`WRITE`/`DANGEROUS` déclenche `ToolConfirmationRequired` (carte Apply in-app, `propose`/`apply`
côté MCP en phase E). **Toggle par vault** `aiDestructiveTools` (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éutilisables `backend/services/backups.py`, `graph.py`,
`recent.py` et extensions de `vaults.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-search`
et `/api/search/advanced` délèguent désormais à ces services (source unique de vérité).
Filtrage systématique par permissions vault ; secrets redactés sur `read_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çade
`backend/tools/api.py`. Services lecture/recherche livrés (`list_vaults`, `list_directory`,
`read_file`, `search_fulltext`, `list_tags`) ; permissions `check_vault_access` + `resolve_safe_path`
appliquées par outil. Tests : `tests/test_tools.py` (30 tests).
- **#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-in `POST /api/ai/bookslm/agent` (events SSE `tool`/`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`.
- **#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 ; `ServiceError` mappée vers
`HTTPException` (routes) et `ToolError` (outils). `/api/ai/bookslm/chat` **streame réellement** les
tokens (`stream_completion`, OpenAI-compat + Gemini ; GZip ignoré pour les SSE BooksLM). Mode agent
côté UI (toggle, événements `tool`/`confirmation`, carte Apply + aperçu diff LCS) et reprise
`confirm`/`confirm_messages` de 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_models`
persistés dans `data/config.json`, rechargement à chaud dans `backend/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_tree` cô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é
- **`scripts/bump_version.sh` — synchronisation de la version desktop** — le script met
désormais à jour `desktop/tauri.conf.json`, `desktop/Cargo.toml` et `desktop/Cargo.lock`
(`obsigate-desktop`) avant de créer un commit de release `chore(release): vX.Y.Z` puis le
tag. `--push` pousse la branche **et** le tag ; `--no-files` conserve l'ancien comportement
(tag seul) et `--dry-run` prévisualise. Indispensable au bon fonctionnement de l'updater
Tauri (dont le manifeste reprend la version de `tauri.conf.json`).
- **`.gitea/workflows/desktop-build.yml` — déclenchement manuel uniquement** — le workflow
`Desktop Build` ne s'exécute plus sur `push` (aucun runner self-hosted `[windows/linux, desktop]`
enregistré) mais uniquement via `workflow_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énement `obsigate:open-file`).
- **Assistant IA (`frontend/js/bookslm.js`)** — bouton « mode agent » dans l'en-tête (persisté en
`localStorage`) : l'envoi bascule vers `/api/ai/bookslm/agent`, affiche la trace des appels d'outils
et les cartes de confirmation (Apply + aperçu diff) ; `/chat` reste 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** (✈️). 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. i18n FR/EN (`ai.activity_*`, `ai.composer_label`). Tests JSDOM
(`tests/frontend/ai.test.mjs` +1).
### Corrigé
- **BUG-015 — Assistant IA : sélection des menus `/` et `@` invisible au clavier** — l'élément
actif utilisait `background: var(--surface2)`, or `--surface2` est **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-hover` avec 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 `keydown` du 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_VERSION` porté à **v6** et migration de purge élargie à
tous les caches `obsigate-*` (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 sur
`vault=all` pour 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-bulle
`title` complè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 (`_vault` nul), la requête partait sans `vault` et le
backend ignorait le contexte ad-hoc. La sélection capture maintenant le `vault` renvoyé par
`/api/tree-search`, `_contextVault()` le propage aux requêtes `/context` et `/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.json` en cache HTTP affichait
les clés brutes (`ai.model_search`, `mobile_editor.*`, …) ; le chargement i18n utilise désormais
`cache: 'no-store'` et `SW_VERSION` est 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, options `display: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_prompt`
ne 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 sur `vault=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
`localStorage` de la webview et le paramètre `hasVaultPath` n'était jamais
renseigné. Ajout d'un booléen persistant `wizard_done` dans la config desktop
(`desktop/src/main.rs`, commandes `get_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 inutilement `libpango-1.0-0`, `libpangocairo-1.0-0` et `shared-mime-info`
(libs runtime de WeasyPrint, sans usage à la compilation), dupliquant les téléchargements
apt. Ces paquets sont retirés du builder et `apt-get clean` est ajouté dans les deux
stages pour purger les `.deb` conservé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 plus `Cache-Control: public, max-age=31536000,
immutable` sur des assets **non fingerprintés**. Correctifs : `frontend/sw.js` réécrit
(**network-first** pour HTML/JS/CSS, caches versionnés `SW_VERSION`, précache corrigé
`/static/js/…`, `skipWaiting`/`clients.claim`) ; migration ponctuelle `localStorage`
(suppression des anciens caches) en remplacement du kill-switch de session ; en-têtes
`no-cache` sur `/static`, `index.html`, `manifest.json` et pages HTML ; rechargement unique
sur `controllerchange`. Tests : `tests/frontend/sw.test.mjs` + `TestStaticCaching`.
Guide Cloudflare : [docs/PWA_GUIDE.md](./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,
gardes `None` sur `get_user()`, `PdfReader: Any` et import `PROVIDERS` manquant dans `main.py`
(bug latent : le modèle par défaut n'était jamais prépendé à la liste des modèles live).
L'étape `mypy` du 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](./docs/ROADMAP.md) ne contient plus que le travail
à venir + un index compact ; les fonctionnalités livrées sont archivées dans
`docs/archive/COMPLETED_v1-v2.md` et documentées par feature dans `docs/features/`.
- **Méthode de livraison unifiée** — nouveau [`docs/DELIVERY_WORKFLOW.md`](./docs/DELIVERY_WORKFLOW.md)
(Definition of Done : tests, documentation, commit, push, CI) et [`AGENTS.md`](./AGENTS.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.0` au lieu de `2.2.0` (commit 84bda90).
- **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 bloc `obsigate-action` rendu 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/context` et `/chat` acceptent `mode` (`directory`/`documents`/
`general`) et `context_files` ; `collect_files_context()`, `empty_context()` et
`build_general_system_prompt()` dans `backend/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) et
`tests/frontend/ai.test.mjs` (+8 tests détection de contexte, clavier, actions, header).
- **#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 et `externalDocs`.
- `backend/schemas.py` : nouveaux `response_model` Pydantic 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
override `app.openapi` pour 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`).
- **#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 manifest `plugin.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, protocole `postMessage` structuré,
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 sans `importScripts`, 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.mjs` aux tests JSDOM.
- Docs : `docs/PLUGINS.md` (manifest, hooks, permissions, modèle de sécurité, API, guide).
- **#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` (commit ac16fc1 + correctifs associés).
- **#67 Notifications web (Push API)** : `backend/push.py`, `POST /api/push/subscribe`,
clés VAPID dans `config.json`, toggle par vault, payload (fichier/vault/action) et
ouverture du fichier au clic (commit ac16fc1).
- **#68 Health check enrichi** : `GET /api/health/detailed` (admin-gated) exposant index,
mémoire (RSS/heap), uptime, connexions SSE, backups et espace disque (commit ac16fc1).
- **#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 tests
`split-view-matrix.spec.js` couvrant 100% des cas d'ouverture/fermeture.
### Documentation
- **#78 Excalidraw — doc utilisateur finalisée** : `.excalidraw` / `.excalidraw.md` ajouté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=true` persisté 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ée` envoie la requête, `Ctrl+Entrée` insè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`/`chat` n'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 lisait `data.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 via `AuthManager` (retry 401),
parsing SSE `event:`/`data:` avec support `token`/`error`, historique construit avant
l'ajout du message courant, barre de progression basée sur `max_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 utilisait `window.prompt()` → remplacée par une modale
accessible (Échap annule, Ctrl/Cmd+Entrée valide).
- **Recherche cassée (régression plugins)** : `onSearchFilter()` était appelée avec 2 arguments
au lieu de 3 (`frontend/js/search.js`), renvoyait `undefined`, 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.md` corrompu à l'ouverture** : Excalidraw émet `onChange` au 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 format `frontmatter + compressed-json`
est préservé à la sauvegarde.
- **Splash / tests E2E** : `window.__OBSIGATE_BOOTED` était posé avant la fin de `init()` — 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 de `init()` (`frontend/js/app.js`), et
`goHome()`/`login()` attendent ce signal.
- **Tests E2E Excalidraw** : réécriture de `tests/e2e/excalidraw.spec.js` avec 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),
config `OBSIGATE_PDF_MAX_SIZE_MB` (50) + `OBSIGATE_PDF_EXTRACT_TIMEOUT` (30s).
16 tests supplémentaires (26 au total dans `test_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` (lib `webauthn==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 tests `split-view-matrix.spec.js` couvrant
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 via `cygpath` (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_stream` plantait systématiquement (`NameError: current_user`
non 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 en `read_text()` → contenu garbage indexé. Utilise maintenant `extract_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 psutil
- `GET /api/admin/audit` — 500 dernières entrées d'audit avec filtres `user`/`action`/`limit`/`offset`
- `GET /api/admin/backup-stats` — compte + taille + age par vault
- `GET /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èmes
- `backend/` — Endpoints backups, Excalidraw, multi-format, versioning git
- `docs/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+P` fichiers, `Ctrl+Alt+Espace` commandes, `Ctrl+Shift+Espace`
- Navigateur de dossiers : créer/supprimer fichiers/dossiers par sélection
- Opérateurs `+include` / `-exclude` dans la recherche globale
- 6 nouvelles commandes : créer/supprimer fichiers/dossiers, éditer, pop-out
- **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 home
- `backend/` — Indexation non-bloquante, statut IA, diff/restauration backups
- `docs/` — 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.11` sur 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`)
- **Stemming français** — `snowballstemmer` inté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 modules
- `backend/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 erreurs `assignment 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 `DashboardStatsWidget` avec 4 cartes (fichiers, tags, taille, vaults)
- Widget "Derniers fichiers ouverts" avec timestamps
- **Documentation OpenAPI enrichie** — Tous les modèles Pydantic documentés (`Field(description=...)`)
- Visible dans `/docs` (Swagger UI) et `/redoc`
- **Documentation complète** — `ANALYSE_REVIEW.md`, `AUDIT_TECHNIQUE.md`, `ROADMAP.md`
### Modifié
- `frontend/js/app.js` — Nouveau système d'onglets (TabManager), dashboard
- `frontend/style.css` — Dashboard, share view, webhooks UI
- `backend/main.py` — Nouveaux endpoints share/webhooks/dashboard
- `backend/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 dans `data/audit.log`, rotation 10MB
- **Backup automatique avant écriture**
- Sauvegarde du contenu original dans `.obsigate-backup/` avant PUT/DELETE
- **Backlinks panel** — Fichiers avec wikilinks pointant vers le fichier courant
- `GET /api/file/{vault}/backlinks` + index inversé dans `indexer.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`
- **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 endpoint
- `backend/indexer.py` — +backlink index, +IGNORED_DIRS
- `backend/auth/router.py` — +IP rate limiting
- `backend/auth/jwt_handler.py` — +configurable TTL
- `backend/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, sync
- `frontend/style.css` — CodeMirror themes, auth forms, PWA UI, responsive
- `docker-compose.yml` — auth env vars, data volume, non-root user
- `backend/main.py` — auth middleware, file CRUD, code editor API, SSE, PWA
- `requirements.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 (`![alt](path)`)
- 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'images
- `backend/image_processor.py` — Prétraitement Markdown pour les syntaxes d'images
- `GET /api/image/{vault}?path=` — Serve images avec MIME types
- `POST /api/attachments/rescan/{vault}` — Rescan manuel
- `HIDDEN_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é)
- **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, autocomplete
- `frontend/app.js` — Refonte recherche : nouveau système de requêtes, facettes, pagination, autocomplete
- `frontend/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