Aggiunge la generazione di documenti Word coerenti con l'identità
visiva Tielogic, in parallelo al render PDF già esistente. Il flusso
completo è ora `bullet input → Markdown formattato → PDF e/o DOCX`
in una singola chiamata MCP.
- docx_renderer.py: subprocess Pandoc che legge il Markdown da stdin,
emette il binario .docx su stdout. Strippa il YAML frontmatter e i
blocchi `<style>` (presenti per il PDF, irrilevanti in DOCX) prima
della conversione.
- mcp_tools.py: nuovo tool `document_to_docx(markdown)` che ritorna
`{docx_b64, size_bytes}`; `document_generate` esteso con
`output_format ∈ {md, pdf, docx, all}`. La firma di
`build_mcp_server` accetta ora `docx_reference_path` opzionale.
- config.py: `Settings.docx_reference_path` (default
/app/themes/tielogic-reference.docx).
- main.py: passa la nuova setting a `build_mcp_server`.
- mcp-docugen.Dockerfile: installazione di pandoc accanto alle libs
Chromium.
- themes/tielogic-reference.docx: reference Word (10 KB) con stili
Tielogic — heading colors blu/dark, font Inter, dimensioni allineate
al CSS web. Generato da `scripts/build-reference-docx.py` che parte
dal reference.docx di default di Pandoc e riscrive `word/styles.xml`
con regex sui blocchi `<w:style>`. Pandoc lo applica in automatico
agli output DOCX prodotti dal servizio.
- 9 nuovi test unit per docx_renderer (strip frontmatter/style,
preprocess combinato, error empty input, smoke skippato in
ambienti senza Pandoc): 92 test totali.
Smoke E2E via MCP: una sola chiamata `document_generate` con
`output_format=all` produce MD (14 KB), PDF (137 KB, 4 pagine A4) e
DOCX (12.7 KB) coerenti tra loro.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Problema: i template puntavano a un path host hardcoded
(stylesheet: /home/adriano/.../themes/tielogic.css), quindi il file .md
generato non era portabile — su un'altra macchina md-to-pdf non trovava
il CSS e produceva PDF senza stile.
Soluzione: il Renderer legge il CSS da Settings.inline_stylesheet_path
(default /app/themes/tielogic.css nel container) e lo inietta come
blocco <style>...</style> subito dopo il frontmatter YAML del Markdown
restituito dall'LLM. Il file .md risultante è autocontenuto e portabile.
- renderer.py: nuovo arg inline_stylesheet_path + funzione
_inject_inline_stylesheet (idempotente, gestisce Markdown senza
frontmatter, no-op se CSS vuoto)
- config.py: Settings.inline_stylesheet_path: Path | None
- main.py: passa il path al Renderer
- mcp-docugen.Dockerfile: COPY themes ./themes nello stage builder per
trasportare /app/themes/tielogic.css nell'immagine runtime
- templates_seed/{offerta,report-analisi}/template.md: rimossa la riga
`stylesheet:` dal frontmatter di output + regola tassativa che vieta
all'LLM di emettere blocchi <style> di sua iniziativa (evita
conflitti di cascade visti in test)
- 4 nuovi test unit (76 totali): iniezione dopo frontmatter, prepend
quando frontmatter assente, no-op CSS vuoto, integrazione full E2E
via Renderer.generate
scripts/bundle-css.py: utility per fixare file .md legacy che
referenziavano stylesheet: come path host (sostituisce la riga con
<style> inline pescando il CSS dal repo)
README aggiornato con rationale e workflow.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- templates_seed/{offerta,report-analisi}/template.md: template Tielogic
ufficiali versionati come sorgente di verità nel repo
- template_seed.py: copia idempotente seed→volume al boot, mai
sovrascrive template esistenti (preserva edit fatti via MCP runtime)
- config.py: nuova Settings.templates_seed_dir
(default /app/services/mcp-docugen/templates_seed)
- main.py: chiamata seed_templates() in build_app dopo TemplateStore init
- 4 nuovi test unit (idempotenza, skip se seed_dir mancante,
no-op su entry non valide). 72 test verde totali
Workflow: edit del template nel repo → rebuild image → al primo boot
il volume vuoto riceve i template; se il template esiste già nel
volume (es. modificato dall'utente via tool MCP) viene preservato.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>