- Ajoute la reconnaissance de la syntaxe Obsidian [[#Titre|Texte]] pour
créer des liens d'ancre vers les titres du document courant.
- Corrige _heading_slugify pour ignorer les balises HTML et décoder les
entités HTML (ex. &) avant de générer l'ID, évitant ainsi la
pollution par les wikilinks placés dans les titres.
- Ajoute le style .wikilink-anchor et des tests couvrant ces cas.
Fixe le rendu du document TestDir/Agents IA - Panorama Complet 2026.md.
CSP directive 'font-src' only allowed self, data:, and fonts.gstatic.com.
Excalidraw loads its handwriting fonts (*.woff2) from esm.sh via
EXCALIDRAW_ASSET_PATH. All ~12 font files were blocked (blocked:csp)
→ Excalidraw fails to initialize → infinite 'Loading...' spinner.
Fix: added https://esm.sh to font-src directive.
Add _normalize_line_breaks() pre-processor that converts single \n to
two-spaces+\n (hard break) before mistune rendering, while protecting
fenced code blocks. This matches Obsidian's default 'Strict Line Breaks
= off' behavior where standalone lines render on separate rows instead
of merging into a single paragraph.
- Dockerfile: COPY .git/HEAD + .git/refs/ → génère backend/VERSION avec hash
- version.py: fallback lit backend/VERSION (à côté du module, pas racine repo)
- Format: 1.8.0-0-g<8-char-hash> ou 1.8.0-dev si indisponible
#74 — Support PDF complet:
- backend/pdf_reader.py — pymupdf/pypdf text extraction
- .pdf added to SUPPORTED_EXTENSIONS in indexer.py
- PDF-aware file view API endpoint (metadata, text preview)
- Streaming endpoint /api/file/{vault}/pdf/stream
- Frontend PDF viewer with iframe, toolbar, download
- CSS for PDF viewer container
#75 — Split View (PaneManager):
- New module frontend/js/pane-manager.js — ES module
- 1-4 pane CSS grid with resize handles
- Split right/down via keyboard (Ctrl+Alt+\) or PaneManager API
- Persistence in localStorage (obsigate-panes)
- Collapse to single pane, per-pane active state
285 tests passent
Problem: language preference stored only in localStorage, lost on
'clear site data'. French users with browser lang=fr always got French
UI even when profile was English.
Solution:
- Backend: add 'language' field to user profile (default 'fr')
- Backend: PATCH /api/auth/me to update language preference
- Frontend: initI18n() priority: server > localStorage > navigator > 'fr'
- Frontend: initAuth() runs before initI18n() so server check works
- Frontend: profile Save persists language to server via PATCH
Verified: tabs show English after server profile set to 'en'
Add Ollama autocomplete status endpoint to AI routes, update sync panel
UI to display autocomplete state, replace monolithic test compose files
with separate Linux/Windows variants, and add PowerShell build script
for Windows deployment
- Backend: delete_cookie access_token (/) + refresh_token
- Logout ne requiert plus auth (graceful si token expire)
- Bouton Deconnexion toujours visible dans le menu
- Ollama provider ajoute dans ai.py (OpenAI-compatible API)
- Service ollama dans docker-compose (auto-pull qwen2.5-coder:1.5b)
- Ghost overlay dans Forge: prediction en texte pale apres le curseur
- Tab pour accepter, Escape pour rejeter, taper pour annuler
- Declenchement automatique apres 800ms de pause
- Scroll sync entre overlay et textarea
- Env vars: AI_DEFAULT_PROVIDER, OLLAMA_BASE_URL, OLLAMA_MODEL
- CSP script-src: ajout https://static.cloudflareinsights.com
- legacy.js ligne 98 a deja le null-check if(filterBtn)
- L'erreur production vient d'un ancien deploy, sera resolu au prochain rebuild
Add standalone /editor-poc page demonstrating all 5 toolbar zones:
- Zone 1: Top Fixed Bar (hamburger, title, AI glow button, save indicator)
- Zone 2a: Slash Command Menu (/ on empty line, 15 commands, filtering)
- Zone 2b: Bubble Menu (on text selection, formatting + AI dropdown)
- Zone 3: Floating Quick Insert (per-line, Image/PDF/Code/Table/AI)
- Zone 4: AI Side Panel (Ctrl+J toggle, chat, suggestions)
- Zone 5: Drag & Drop overlay with dashed border
Files:
- new: frontend/editor-poc.html (46KB standalone vanilla JS)
- backend/main.py: +/editor-poc route before catch-all
- frontend/index.html: Editor POC button in header menu
- frontend/js/config.js: initEditorPocBtn() function + export
- frontend/js/legacy.js: re-export initEditorPocBtn
- frontend/js/app.js + frontend/app.js: init call in both versions
#15: Click backup item to preview content in side panel (100KB limit)
#16: Purge all backups per vault (red 'Vider' button)
#17: /api/backups/compress — gzip backups older than N days
#18: /api/backups/auto — backup files modified since N hours
#19: Restore button per backup in manager with timestamp extraction
+ Professional side-panel preview, action buttons on hover, vault grouping
- Config: max_backups_per_file (default 10) in config.json + UI field
- Auto-cleanup: _backup_file deletes oldest backups when limit exceeded
- New endpoints: GET /api/backups (list all), POST /api/backups/delete,
POST /api/backups/purge (by file or vault)
- New module: backup-manager.js - full-page view with filter, grouped by
vault/file, individual delete, per-file purge, stats
- Link from backup viewer footer: 'Gerer tous les backups'
- _get_backup_dir: now resolves relative path using the SPECIFIC vault's
directory (matching _backup_file exactly), not the first vault in index
- Removed _get_backup_root (unused after refactor)
- backups.js: global document click handler for #backup-close (same
pattern as Graph View's initGraphView)
- _backup_file: resolve relative backup path against vault parent (survives CWD changes)
- _get_backup_root: same resolution logic for listing
- backups.js: global document-level capture-phase click handler for .backup-close-btn
(works regardless of innerHTML replacements, text node targets, or event bubbling)
- Vault home (#12): recursive file listing (rglob), rel_dir in metadata,
'recursif' badge, updated roadmap description
- Backup viewer: fix close button (inline onclick + event delegation
fallback for text nodes), improve error messages
- Backup API: remove response_model to prevent Pydantic 500 errors,
add try/except + logging on backups/diff/restore endpoints,
per-entry error handling in _list_backup_files,
encoding safety (errors='replace') on read_text
- AI status: call /api/ai/status at startup in _initAIStatus
instead of waiting for user click on sync badge
Problème: l'indicateur affichait 'IA non configurée' alors que les
actions AI fonctionnaient.
Causes:
1. Deux endpoints /api/ai/status en conflit (main.py + ai_routes.py)
2. ai_routes.py lisait PROVIDERS évalué à l'import (os.getenv figé)
3. Cache côté frontend (_aiStatusChecked) empêchait de re-vérifier
Fixes:
- Suppression de l'endpoint redondant dans main.py
- ai_routes.py: lecture os.getenv au runtime (pas depuis PROVIDERS)
- sync.js: _checkAIStatus() appelée à chaque ouverture du panneau
L'étape 'Building inverted index...' au démarrage bloquait l'event loop
asyncio, empêchant le serveur de répondre aux requêtes HTTP (navigation,
refresh) jusqu'à la fin de l'indexation.
- init_inverted_index() exécuté dans ThreadPoolExecutor via run_in_executor
- get_inverted_index() ne fait plus de rebuild auto bloquant
- Le serveur répond immédiatement, même pendant l'indexation
Point 11a — Indicateur AI Actif:
- Badge sync flashe en blanc pendant traitement AI (animation CSS)
- Événements ai-processing-start/end dans ai.js
- Section statut IA dans panneau sync (configurée/non configurée/en cours)
- Endpoint GET /api/ai/status vérifiant les clés API configurées
Point 11b — Page d'accueil de voute:
- Endpoint GET /api/vault/{vault}/files?dir=... (trié par mtime)
- Module vaulthome.js: affichage style résultats de recherche
- Breadcrumb navigable, mise à jour auto sur clic dossier dans tree
- Déclenché auto quand un vault spécifique est sélectionné
- Backend: 3 nouveaux endpoints
- GET /api/file/{vault}/backups — liste les backups horodatés
- GET /api/file/{vault}/diff — diff unifié entre versions
- POST /api/file/{vault}/restore — restaure une version (backup auto avant)
- Frontend: module backups.js — UI modale avec:
- Sélecteur gauche (backup) / droite (version actuelle ou autre backup)
- Diff coloré: vert pour ajouts, rouge pour suppressions
- Bouton Restaurer avec confirmation
- Menu contextuel: clic droit fichier → 'Backups / Versions'
- CSS: styles complets pour la modale, toolbar, table de diff
- ROADMAP: point 6 marqué comme complété
- Backend: nouvel endpoint POST /api/move/{vault_name} pour déplacer
fichiers et dossiers vers un autre répertoire parent
- Frontend: module dragdrop.js avec délégation d'événements sur le
vault-tree (dragstart, dragover, dragleave, drop)
- CSS: styles pour drag-source, drag-valid-target, drag-over
- Protections: pas de drop sur soi-même, pas dans un enfant,
pas de cross-vault
- Mise à jour de l'index et broadcast SSE après move
- ROADMAP: portion 5 marquée comme complétée
Replace double-nested stem loop (stems × tokens) with single-pass
stem frequency map. For 100 unique tokens per file: 10,000 iterations
→ 100 iterations per file. Critical for large vaults.
Backend (main.py):
- GraphNode: added tags, incoming_count, outgoing_count
- GraphEdge: added 'backlink' relation
- GraphResponse: added 'scope' field
- api_graph: scope=full|directory, tag= filter, backlinks
- Full-vault tree walk with configurable depth 0-3
- Tag index from in-memory file index for fast filtering
- Incoming/outgoing link count per node
Frontend (graph.js + index.html):
- Theme-adaptive colors via CSS custom properties
- Depth slider (0-3) with live reload
- Full-vault toggle button (🌐 Tout / 📁 Dossier)
- Search input with tag filtering + visual highlighting
- Tooltip on hover (name, path, tags, link counts)
- Backlink edges rendered in red dashed
- Node size proportional to link count
- Larger modal (1000px, 85vh)
Add French snowball stemmer to tokenization pipeline:
- Index both original tokens AND their stems in InvertedIndex
- Query terms are also stemmed before lookup
- Stemmed forms accumulate TF from all original forms
- Lazy-init singleton pattern for stemmer