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

@@ -327,7 +327,7 @@ export const AgentsView: React.FC<AgentsViewProps> = ({
'Connexion SSH sans mot de passe à devSandbox',
'Gateway token (blank to generate)',
'Procédure d\'accès à openclaw',
'Derniers commits du repo Momento'
'Derniers commits du repo Memento'
].map((note, i) => (
<label key={i} className="flex items-center gap-4 px-6 py-4 cursor-pointer hover:bg-white/50 transition-colors group">
<div className={`w-5 h-5 rounded border transition-all flex items-center justify-center

View File

@@ -44,7 +44,7 @@ export const AuthPage: React.FC<AuthPageProps> = ({ onAuthComplete, onBack, init
<div className="w-8 h-8 bg-ink text-white rounded-xl flex items-center justify-center shadow-lg">
<span className="font-serif font-bold text-xl">M</span>
</div>
<span className="font-serif text-xl font-medium tracking-tight text-ink">Momento</span>
<span className="font-serif text-xl font-medium tracking-tight text-ink">Memento</span>
</div>
<div className="w-24" /> {/* Spacer */}
@@ -191,7 +191,7 @@ export const AuthPage: React.FC<AuthPageProps> = ({ onAuthComplete, onBack, init
</AnimatePresence>
<p className="text-center mt-8 text-[9px] text-concrete font-bold uppercase tracking-[0.3em] opacity-40">
© 2024 Momento Labs Privacy Terms
© 2024 Memento Labs Privacy Terms
</p>
</div>
</main>

View File

@@ -124,7 +124,7 @@ export const ClipperSimulator: React.FC<ClipperSimulatorProps> = ({
try {
// Occasional simulated error for retry demonstration
if (Math.random() < 0.15) {
throw new Error("Connexion réseau interrompue. L'extension n'a pas pu joindre les serveurs Momento.");
throw new Error("Connexion réseau interrompue. L'extension n'a pas pu joindre les serveurs Memento.");
}
const dateStr = new Date().toLocaleDateString('fr-FR', {
@@ -175,10 +175,10 @@ export const ClipperSimulator: React.FC<ClipperSimulatorProps> = ({
setLastCreatedNoteId(newNoteId);
setClipperState('success');
// Add note to Momento Database
// Add note to Memento Database
onAddNote(newNote);
// Fire real-time notification toast in Momento!
// Fire real-time notification toast in Memento!
onTriggerToast(clipTitle, newNoteId);
} catch (err: any) {
@@ -260,7 +260,7 @@ export const ClipperSimulator: React.FC<ClipperSimulatorProps> = ({
{/* Web Extension active badge */}
<button
className="p-1.5 bg-accent/10 border border-accent/20 rounded-lg text-accent animate-pulse relative group"
title="Momento Web Clipper is active"
title="Memento Web Clipper is active"
>
<Scissors size={14} className="-rotate-90" />
<span className="absolute bottom-full right-0 mb-2 whitespace-nowrap hidden group-hover:block bg-ink text-paper text-[10px] py-1 px-2 rounded-md shadow-lg">
@@ -356,12 +356,12 @@ export const ClipperSimulator: React.FC<ClipperSimulatorProps> = ({
{/* Extension Hub Header */}
<header className="px-5 py-4 border-b border-neutral-100 dark:border-neutral-800 bg-neutral-50 dark:bg-neutral-900/40 flex items-center justify-between">
<div className="flex items-center gap-2">
{/* Momento Logo with Clipper Branding */}
{/* Memento Logo with Clipper Branding */}
<div className="w-7 h-7 bg-ink text-paper rounded-lg flex items-center justify-center font-serif font-black text-sm">
M
</div>
<div className="leading-tight">
<span className="text-xs font-bold font-serif text-ink dark:text-dark-ink tracking-tight">Momento</span>
<span className="text-xs font-bold font-serif text-ink dark:text-dark-ink tracking-tight">Memento</span>
<span className="text-[10px] text-accent block font-mono font-medium tracking-widest uppercase">Web Clipper</span>
</div>
</div>
@@ -561,7 +561,7 @@ export const ClipperSimulator: React.FC<ClipperSimulatorProps> = ({
}}
className="w-full py-3.5 bg-ink text-paper rounded-xl text-xs font-bold uppercase tracking-widest flex items-center justify-center gap-2 hover:opacity-95 transition-opacity"
>
Voir dans Momento
Voir dans Memento
<ArrowUpRight size={14} />
</button>
@@ -608,7 +608,7 @@ export const ClipperSimulator: React.FC<ClipperSimulatorProps> = ({
{/* Simulated context details */}
<footer className="px-5 py-3 border-t border-neutral-100 dark:border-neutral-800 bg-neutral-50/50 dark:bg-neutral-900/40 text-[9px] text-concrete text-center">
Momento Companion v2.1.2 Sécurisé HTTPS TLS 1.3
Memento Companion v2.1.2 Sécurisé HTTPS TLS 1.3
</footer>
</div>
</div>

View File

@@ -37,7 +37,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
<div className="w-10 h-10 bg-ink flex items-center justify-center rounded-xl shadow-lg rotate-3 group hover:rotate-0 transition-transform cursor-pointer">
<span className="text-paper font-serif text-2xl font-bold">M</span>
</div>
<span className="font-serif text-2xl font-medium tracking-tight">Momento</span>
<span className="font-serif text-2xl font-medium tracking-tight">Memento</span>
</div>
<div className="hidden md:flex items-center gap-10">
@@ -86,7 +86,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
<span className="italic">enfin amplifié.</span>
</h1>
<p className="max-w-2xl mx-auto text-lg md:text-xl text-concrete font-light leading-relaxed mb-12">
Momento n'est pas qu'une simple application de notes. C'est un écosystème intelligent qui connecte, analyse et développe vos idées en temps réel grâce à 6 types d'agents IA et une recherche sémantique de pointe.
Memento n'est pas qu'une simple application de notes. C'est un écosystème intelligent qui connecte, analyse et développe vos idées en temps réel grâce à 6 types d'agents IA et une recherche sémantique de pointe.
</p>
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
@@ -155,7 +155,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
<h2 className="text-4xl md:text-5xl font-serif tracking-tight text-ink">Une intelligence fluide, <br />intégrée à chaque mot.</h2>
</div>
<div className="text-concrete font-light">
Momento orchestres vos idées grâce à une architecture multi-fournisseurs.
Memento orchestres vos idées grâce à une architecture multi-fournisseurs.
</div>
</div>
@@ -352,7 +352,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
{
name: "Basic",
price: "Gratuit",
desc: "Pour découvrir la magie de Momento.",
desc: "Pour découvrir la magie de Memento.",
features: ["100 Notes max", "3 Carnets", "50 crédits IA (Lifetime)", "Recherche sémantique", "Historique 7 jours"],
cta: "Commencer",
popular: false
@@ -433,7 +433,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
</div>
<h3 className="text-3xl font-serif font-medium mb-4">La stratégie BYOK</h3>
<p className="text-concrete font-light leading-relaxed mb-6">
Vous possédez déjà des clés API OpenAI, Anthropic ou Google ? Connectez-les directement à Momento.
Vous possédez déjà des clés API OpenAI, Anthropic ou Google ? Connectez-les directement à Memento.
Utilisez l'IA sans limites de crédits imposées, en payant uniquement ce que vous consommez chez votre fournisseur favori.
</p>
<div className="grid grid-cols-2 gap-4">
@@ -472,12 +472,12 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
<section className="py-40 px-8 text-center bg-paper relative overflow-hidden">
<div className="max-w-3xl mx-auto relative z-10">
<h2 className="text-5xl md:text-7xl font-serif tracking-tight mb-8 leading-tight">Prêt à libérer votre <br /><span className="italic">plein potentiel ?</span></h2>
<p className="text-lg text-concrete font-light mb-12">Rejoignez des milliers de chercheurs, designers et penseurs qui utilisent déjà Momento pour construire leur futur.</p>
<p className="text-lg text-concrete font-light mb-12">Rejoignez des milliers de chercheurs, designers et penseurs qui utilisent déjà Memento pour construire leur futur.</p>
<button
onClick={onEnter}
className="px-16 py-6 bg-ink text-paper rounded-[32px] text-lg font-bold uppercase tracking-[0.2em] hover:scale-105 transition-all shadow-[0_30px_60px_-15px_rgba(0,0,0,0.3)]"
>
Lancer Momento
Lancer Memento
</button>
</div>
</section>
@@ -489,7 +489,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
<div className="flex-1 space-y-8">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-accent/10 text-accent text-[9px] font-bold uppercase tracking-widest">
<Globe size={12} />
Écosystème Momento
Écosystème Memento
</div>
<h3 className="text-4xl font-serif font-medium leading-tight text-ink">
Traduisez vos documents.<br />
@@ -558,7 +558,7 @@ export const LandingPage: React.FC<LandingPageProps> = ({ onEnter, onLogin, onRe
<div className="w-8 h-8 bg-ink flex items-center justify-center rounded-lg">
<span className="text-paper font-serif text-lg font-bold">M</span>
</div>
<span className="font-serif text-xl medium tracking-tight">Momento</span>
<span className="font-serif text-xl medium tracking-tight">Memento</span>
</div>
<p className="text-sm text-concrete font-light max-w-xs">Le second cerveau amplifié par l'IA. Pensé pour les esprits créatifs.</p>
</div>

View File

@@ -602,7 +602,7 @@ export const SearchModal: React.FC<SearchModalProps> = ({
<div className="flex items-center gap-1.5 text-[9px] font-bold uppercase tracking-wider text-concrete/60">
<Command size={10} />
<span>Momento Search OS v2.3</span>
<span>Memento Search OS v2.3</span>
</div>
</div>
</motion.div>

View File

@@ -9,7 +9,7 @@ export const BillingTab: React.FC = () => {
name: 'Plan Basic',
price: 'Gratuit',
period: '',
description: 'Pour découvrir la magie de Momento.',
description: 'Pour découvrir la magie de Memento.',
features: [
'100 Notes max',
'3 Carnets',
@@ -119,7 +119,7 @@ export const BillingTab: React.FC = () => {
</div>
<div className="space-y-2">
<p className="text-xs text-concrete font-light">Votre plan gratuit n'expire jamais. Passez à la vitesse supérieure pour débloquer toute la puissance de Momento.</p>
<p className="text-xs text-concrete font-light">Votre plan gratuit n'expire jamais. Passez à la vitesse supérieure pour débloquer toute la puissance de Memento.</p>
<div className="pt-4 flex items-center justify-between border-t border-border/40 mt-4">
<span className="text-[11px] font-bold text-ink uppercase tracking-widest">Plan Actuel</span>
<span className="text-[11px] font-bold text-accent uppercase tracking-widest">GRATUIT</span>