feat: publication IA (magazine/brief/essay) + fixes critique
Some checks failed
CI / Lint, Unit Tests & Build (push) Failing after 1m22s
CI / Deploy production (on server) (push) Has been skipped

Publication IA:
- 4 templates (magazine, brief, essay, simple) avec CSS riche
- Rewrite IA (article/exercises/tutorial/reference/mixed)
- Modération avec timeout 12s + fallback safe
- Quotas publish_enhance par tier (basic=2, pro=15, business=100)
- Détection contenu stale (hash)
- Migration DB publishedContent/publishedTemplate/publishedSourceHash

Fixes:
- cheerio v1.2: Element -> AnyNode (domhandler), decodeEntities cast
- _isShared ajouté au type Note (champ virtuel serveur)
- callout colors PDF export: extraction fonction pure testable
- admin/published: guard note.userId null
- Cmd+S fonctionne en mode dialog (pas seulement fullPage)

i18n:
- 23 clés publish* traduites dans les 15 locales
- Extension Web Clipper: 13 locales mise à jour

Tests:
- callout-colors.test.ts (6 tests)
- note-visible-in-view.test.ts (5 tests)
- entitlements.test.ts + byok-entitlements.test.ts: mock usageLog + unstubAllEnvs
- 199/199 tests passent

Tracker: user-stories.md sync avec sprint-status.yaml
This commit is contained in:
Antigravity
2026-06-28 07:32:57 +00:00
parent 902fe95a69
commit 96e7902f01
169 changed files with 5382 additions and 1527 deletions

View File

@@ -66,13 +66,14 @@ Chaque jour doit avoir 1-4 notes à réviser avec une activité descriptive.`
const provider = getChatProvider(config)
const raw = await provider.generateText(prompt)
return this.parseResponse(raw, notes, daysUntilExam)
return this.parseResponse(raw, notes, daysUntilExam, language)
}
private parseResponse(
raw: string,
notes: Array<{ id: string; title: string }>,
totalDays: number
totalDays: number,
language?: string
): StudyPlan {
const jsonMatch = raw.match(/```json\s*([\s\S]+?)\s*```/)
let jsonStr = jsonMatch ? jsonMatch[1] : raw
@@ -101,6 +102,9 @@ Chaque jour doit avoir 1-4 notes à réviser avec une activité descriptive.`
}
} catch {
// Fallback: simple distribution
const lang = language || 'fr'
const firstReadLabel = lang === 'fa' ? 'اولین مطالعه' : lang === 'ar' ? 'القراءة الأولى' : lang === 'de' ? 'Erste Lektüre' : lang === 'es' ? 'Primera lectura' : lang === 'it' ? 'Prima lettura' : lang === 'pt' ? 'Primeira leitura' : lang === 'ru' ? 'Первое чтение' : lang === 'zh' ? '第一次阅读' : lang === 'ja' ? '最初の読み' : lang === 'ko' ? '첫 번째 읽기' : lang === 'nl' ? 'Eerste lezing' : lang === 'pl' ? 'Pierwsze czytanie' : lang === 'hi' ? 'पहली पढ़ाई' : lang === 'fr' ? 'Première lecture' : 'First reading'
const reviewLabel = (n: number) => lang === 'fa' ? `مرور ${n} یادداشت` : lang === 'ar' ? `مراجعة ${n} ملاحظات` : lang === 'de' ? `${n} Notizen wiederholen` : lang === 'es' ? `Repasar ${n} notas` : lang === 'it' ? `Ripassa ${n} note` : lang === 'pt' ? `Rever ${n} notas` : lang === 'ru' ? `Повторить ${n} заметок` : lang === 'zh' ? `复习 ${n} 条笔记` : lang === 'ja' ? `${n}件のノートを復習` : lang === 'ko' ? `${n}개 노트 복습` : lang === 'nl' ? `${n} notities herzien` : lang === 'pl' ? `Powtórz ${n} notatek` : lang === 'hi' ? `${n} नोट्स दोहराएं` : lang === 'fr' ? `Revoir ${n} notes` : `Review ${n} notes`
const days: StudyDay[] = []
const today = new Date()
const notesPerDay = Math.max(1, Math.ceil(notes.length / Math.min(totalDays, 14)))
@@ -113,7 +117,7 @@ Chaque jour doit avoir 1-4 notes à réviser avec une activité descriptive.`
date: date.toISOString().slice(0, 10),
noteIds: dayNotes.map(n => n.id),
noteTitles: dayNotes.map(n => n.title),
activity: i === 0 ? 'Première lecture' : `Revoir ${dayNotes.length} notes`,
activity: i === 0 ? firstReadLabel : reviewLabel(dayNotes.length),
})
}