163 lines
6.0 KiB
Python
163 lines
6.0 KiB
Python
|
|
"""
|
||
|
|
trilium_init.py — Initialisation idempotente de l'arborescence Trilium
|
||
|
|
Usage :
|
||
|
|
python trilium_init.py
|
||
|
|
python trilium_init.py --with-example
|
||
|
|
python trilium_init.py --show-ids
|
||
|
|
"""
|
||
|
|
import argparse
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
from trilium_api import (check_api, create_note, get_note_id,
|
||
|
|
find_note_by_title, set_label, update_note_content)
|
||
|
|
|
||
|
|
GREEN, YELLOW, RESET, BOLD = "\033[32m", "\033[33m", "\033[0m", "\033[1m"
|
||
|
|
def ok(m): print(f" {GREEN}✓{RESET} {m}")
|
||
|
|
def warn(m): print(f" {YELLOW}⚠{RESET} {m}")
|
||
|
|
def head(m): print(f"\n{BOLD}{m}{RESET}")
|
||
|
|
|
||
|
|
IDS_FILE = os.path.join(os.path.dirname(__file__), "trilium_ids.json")
|
||
|
|
|
||
|
|
def get_or_create(parent_id, title, note_type="text", labels=None):
|
||
|
|
existing = find_note_by_title(title, parent_id)
|
||
|
|
if existing:
|
||
|
|
warn(f"Existant : {title} (ID: {existing})")
|
||
|
|
return existing
|
||
|
|
result = create_note(parent_id, title, note_type=note_type)
|
||
|
|
note_id = get_note_id(result)
|
||
|
|
if labels:
|
||
|
|
for k, v in labels.items():
|
||
|
|
set_label(note_id, k, v)
|
||
|
|
ok(f"Créé : {title} (ID: {note_id})")
|
||
|
|
return note_id
|
||
|
|
|
||
|
|
def init_structure():
|
||
|
|
head("Initialisation de l'arborescence Trilium")
|
||
|
|
ids = {}
|
||
|
|
|
||
|
|
root_id = get_or_create("root", "Context Continuity", "book",
|
||
|
|
{"type": "projet"})
|
||
|
|
ids["root"] = root_id
|
||
|
|
|
||
|
|
children_map = {
|
||
|
|
"Projets": "Projets",
|
||
|
|
"Conversations": "Conversations",
|
||
|
|
"Backlog": "Backlog",
|
||
|
|
"Décisions": "Decisions",
|
||
|
|
"Historique": "Historique",
|
||
|
|
"Glossaire": "Glossaire",
|
||
|
|
"Contextes Reprise": "ContextesReprise",
|
||
|
|
}
|
||
|
|
for title, key in children_map.items():
|
||
|
|
ids[key] = get_or_create(root_id, title, "book",
|
||
|
|
{"type": "container"})
|
||
|
|
|
||
|
|
with open(IDS_FILE, "w") as f:
|
||
|
|
json.dump(ids, f, indent=2, ensure_ascii=False)
|
||
|
|
ok(f"IDs sauvegardés dans {IDS_FILE}")
|
||
|
|
return ids
|
||
|
|
|
||
|
|
def create_example_project(ids):
|
||
|
|
head("Création du projet exemple : Sliding Automation")
|
||
|
|
projet_id = get_or_create(
|
||
|
|
ids["Projets"], "Sliding Automation", "text",
|
||
|
|
{"type": "projet", "projet": "SlidingAutomation", "statut": "actif"}
|
||
|
|
)
|
||
|
|
update_note_content(projet_id,
|
||
|
|
"<h2>Sliding Automation</h2>"
|
||
|
|
"<p><b>Objectif</b> : Pipeline de génération automatique de "
|
||
|
|
"présentations PPTX via agents Mistral.</p>"
|
||
|
|
"<p><b>Stack</b> : Python, python-pptx, Mistral Large/Small, YAML</p>"
|
||
|
|
"<p><b>LLM</b> : Claude → architecture & rédaction longue | "
|
||
|
|
"Le Chat → génération code & itérations</p>"
|
||
|
|
)
|
||
|
|
|
||
|
|
head("Backlog Items")
|
||
|
|
backlog_items = [
|
||
|
|
("Déployer patch_render_engine.py (chantiers A/B/C/D)", "haute", "à faire"),
|
||
|
|
("Analyser feedbacks slides 5-17", "haute", "à faire"),
|
||
|
|
("Fix two_cols_text : tirets Markdown visibles", "moyenne", "à faire"),
|
||
|
|
("Fix executive_summary : blocs SCR mal positionnés", "moyenne", "à faire"),
|
||
|
|
("Initialiser versioning Git (Forgejo ou Codeberg)", "basse", "à faire"),
|
||
|
|
]
|
||
|
|
for titre, prio, statut in backlog_items:
|
||
|
|
get_or_create(ids["Backlog"], titre, "text",
|
||
|
|
{"type": "backlogItem", "projet": "SlidingAutomation",
|
||
|
|
"priorite": prio, "statut": statut})
|
||
|
|
|
||
|
|
head("Historique")
|
||
|
|
historique = [
|
||
|
|
("Fix semantic key : self.theme['semantic']",
|
||
|
|
"Fait établi",
|
||
|
|
"Clé corrigée dans render_engine.py — ne pas revenir en arrière."),
|
||
|
|
("Fix polices : détection via assets/fonts/ (pas fc-list)",
|
||
|
|
"Fait établi",
|
||
|
|
"fc-list indisponible sur DS218 ARM64. Détection locale obligatoire."),
|
||
|
|
("Fix Python 3.9 : Union[X|Y] non supporté",
|
||
|
|
"Contrainte découverte",
|
||
|
|
"DS218 tourne Python 3.9. Utiliser Union[X, Y] / Optional[X]."),
|
||
|
|
]
|
||
|
|
for titre, type_h, detail in historique:
|
||
|
|
nid = get_or_create(ids["Historique"], titre, "text",
|
||
|
|
{"type": "historiqueItem",
|
||
|
|
"projet": "SlidingAutomation",
|
||
|
|
"typeHistorique": type_h,
|
||
|
|
"encoreValide": "true"})
|
||
|
|
update_note_content(nid, f"<p>{detail}</p>")
|
||
|
|
|
||
|
|
head("Glossaire")
|
||
|
|
glossaire = [
|
||
|
|
("render_engine.py",
|
||
|
|
"Script principal de rendu PPTX. "
|
||
|
|
"NE PAS confondre avec facilitator.py."),
|
||
|
|
("Chantier A/B/C/D",
|
||
|
|
"4 ensembles de corrections visuelles regroupées "
|
||
|
|
"dans patch_render_engine.py."),
|
||
|
|
("Layout",
|
||
|
|
"Template de slide défini dans layouts.yaml. "
|
||
|
|
"28 layouts disponibles (L01-L28)."),
|
||
|
|
]
|
||
|
|
for terme, definition in glossaire:
|
||
|
|
nid = get_or_create(ids["Glossaire"], terme, "text",
|
||
|
|
{"type": "termeGlossaire",
|
||
|
|
"projet": "SlidingAutomation"})
|
||
|
|
update_note_content(nid, f"<p><b>Définition</b> : {definition}</p>")
|
||
|
|
|
||
|
|
ok("Projet Sliding Automation initialisé.")
|
||
|
|
|
||
|
|
def show_ids():
|
||
|
|
if not os.path.exists(IDS_FILE):
|
||
|
|
print("❌ trilium_ids.json introuvable. "
|
||
|
|
"Lance d'abord : python trilium_init.py")
|
||
|
|
return
|
||
|
|
with open(IDS_FILE) as f:
|
||
|
|
ids = json.load(f)
|
||
|
|
head("IDs Trilium")
|
||
|
|
for k, v in ids.items():
|
||
|
|
print(f" {k:<20} : {v}")
|
||
|
|
|
||
|
|
def main():
|
||
|
|
parser = argparse.ArgumentParser(
|
||
|
|
description="Initialise l'arborescence Trilium")
|
||
|
|
parser.add_argument("--with-example", action="store_true",
|
||
|
|
help="Crée aussi les données Sliding Automation")
|
||
|
|
parser.add_argument("--show-ids", action="store_true",
|
||
|
|
help="Affiche les IDs existants")
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
if args.show_ids:
|
||
|
|
show_ids()
|
||
|
|
return
|
||
|
|
|
||
|
|
check_api()
|
||
|
|
ids = init_structure()
|
||
|
|
|
||
|
|
if args.with_example:
|
||
|
|
create_example_project(ids)
|
||
|
|
|
||
|
|
head("Done ✓")
|
||
|
|
print(" Lance : python trilium_context.py list-backlog "
|
||
|
|
"--projet SlidingAutomation")
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|