Skip to main content

mnemo/
cli.rs

1use clap::{Parser, Subcommand, ValueEnum};
2use clap_complete::Shell;
3use std::path::PathBuf;
4
5use crate::export::ExportFormat;
6
7#[derive(Parser, Debug)]
8#[command(
9    name = "mnemo",
10    version,
11    about = "Navigation et recherche dans l'historique Bash",
12    long_about = None,
13)]
14pub struct Cli {
15    #[command(subcommand)]
16    pub command: Command,
17}
18
19#[derive(Subcommand, Debug)]
20pub enum Command {
21    /// Initialise la configuration et la base de données.
22    Init {
23        /// Lance l'assistant d'onboarding interactif (intégration Bash, import,
24        /// diagnostic). Toutes les actions proposées sont non destructives.
25        #[arg(long)]
26        wizard: bool,
27        /// En mode `--wizard` non interactif, accepte les choix sûrs par défaut
28        /// sans rien supprimer ni purger.
29        #[arg(long)]
30        yes: bool,
31    },
32
33    /// Génère un script de complétion shell sur stdout (bash, zsh, fish).
34    ///
35    /// mnemo n'écrit jamais dans vos fichiers shell : redirigez la sortie vers
36    /// l'emplacement adéquat (voir `docs/UX_ONBOARDING.md`).
37    Completions {
38        /// Shell cible.
39        #[arg(value_enum)]
40        shell: CompletionShell,
41    },
42
43    /// Importe l'historique Bash (~/.bash_history par défaut) dans la base.
44    Import {
45        /// Fichier d'historique à importer.
46        #[arg(long)]
47        file: Option<PathBuf>,
48    },
49
50    /// Ajoute une commande dans la base.
51    Add {
52        /// Commande à enregistrer.
53        #[arg(long)]
54        cmd: String,
55        /// Répertoire de travail (défaut : répertoire courant).
56        #[arg(long)]
57        cwd: Option<String>,
58        /// Code de sortie de la commande.
59        #[arg(long = "exit-code", default_value_t = 0)]
60        exit_code: i64,
61    },
62
63    /// Ouvre l'interface TUI interactive de recherche.
64    Search {
65        /// Requête initiale (positionnelle, optionnelle).
66        query: Option<String>,
67        /// Requête explicite (équivalent à l'argument positionnel).
68        #[arg(long = "query", value_name = "TEXTE", conflicts_with = "query")]
69        query_opt: Option<String>,
70        /// Mode non interactif : imprime les résultats sur stdout sans TUI.
71        #[arg(long)]
72        print: bool,
73        /// Nombre maximal de résultats affichés en mode --print.
74        #[arg(long, default_value_t = 20)]
75        limit: usize,
76        /// Filtre sur un projet Git (nom du dossier racine ou chemin git_root).
77        #[arg(long, value_name = "NOM")]
78        project: Option<String>,
79        /// Filtre sur une branche Git.
80        #[arg(long, value_name = "BRANCHE")]
81        branch: Option<String>,
82        /// Filtre sur un code de sortie exact (ex : 0, 1, 127).
83        #[arg(long = "exit-code", value_name = "CODE")]
84        exit_code: Option<i64>,
85        /// N'affiche que les commandes en échec (exit_code ≠ 0).
86        #[arg(long, conflicts_with = "exit_code")]
87        failed: bool,
88        /// Limite l'âge des résultats (durée `24h`/`7d`/`2w`/`3m`/`1y` ou date `AAAA-MM-JJ`).
89        #[arg(long, value_name = "DURÉE|DATE")]
90        since: Option<String>,
91        /// N'affiche que les commandes antérieures à une date (`AAAA-MM-JJ`).
92        /// Alias : `--until`.
93        #[arg(long, visible_alias = "until", value_name = "DATE")]
94        before: Option<String>,
95        /// Filtre sur un répertoire de travail exact.
96        #[arg(long, value_name = "CHEMIN")]
97        cwd: Option<String>,
98        /// Filtre sur un shell exact (ex : bash, zsh).
99        #[arg(long, value_name = "SHELL")]
100        shell: Option<String>,
101        /// Produit une sortie JSON stable (implique le mode non interactif).
102        #[arg(long)]
103        json: bool,
104        /// N'affiche que les identifiants, un par ligne (implique le mode non
105        /// interactif). Pratique pour chaîner avec `mnemo show`/`mnemo print`.
106        #[arg(long = "id-only", conflicts_with = "json")]
107        id_only: bool,
108    },
109
110    /// Ouvre la TUI avancée (interface interactive principale).
111    Tui {
112        /// Requête initiale (positionnelle, optionnelle).
113        query: Option<String>,
114        /// Filtre initial sur un projet Git (nom du dossier racine).
115        #[arg(long, value_name = "NOM")]
116        project: Option<String>,
117        /// Filtre initial sur une branche Git.
118        #[arg(long, value_name = "BRANCHE")]
119        branch: Option<String>,
120        /// Filtre initial sur un répertoire de travail.
121        #[arg(long, value_name = "CHEMIN")]
122        cwd: Option<String>,
123        /// N'affiche que les commandes en échec (exit_code ≠ 0).
124        #[arg(long)]
125        failed: bool,
126    },
127
128    /// Affiche le snippet d'intégration Bash à ajouter dans ~/.bashrc.
129    Bashrc,
130
131    /// Gère l'intégration shell installée dans ~/.bashrc.
132    Shell {
133        #[command(subcommand)]
134        action: ShellCommand,
135    },
136
137    /// Applique les migrations de schéma SQLite en attente.
138    Migrate,
139
140    /// Affiche des statistiques d'usage (texte simple).
141    Stats {
142        /// Filtre sur un projet Git (nom du dossier racine, chemin git_root, ou `current`).
143        #[arg(long, value_name = "NOM")]
144        project: Option<String>,
145        /// Filtre sur une branche Git.
146        #[arg(long, value_name = "BRANCHE")]
147        branch: Option<String>,
148        /// Limite la fenêtre d'analyse (durée `24h`/`7d`/`2w`/`3m`/`1y` ou date `AAAA-MM-JJ`).
149        #[arg(long, value_name = "DURÉE|DATE")]
150        since: Option<String>,
151        /// Produit une sortie JSON exploitable.
152        #[arg(long)]
153        json: bool,
154    },
155
156    /// Diagnostique l'installation locale de mnemo.
157    Doctor {
158        /// Répare les éléments manquants (config, base, bloc .bashrc).
159        #[arg(long)]
160        fix: bool,
161        /// Produit une sortie JSON exploitable.
162        #[arg(long)]
163        json: bool,
164    },
165
166    /// Gère la configuration locale de mnemo.
167    Config {
168        #[command(subcommand)]
169        action: ConfigCommand,
170    },
171
172    /// Crée une sauvegarde locale complète (archive .tar.gz).
173    Backup {
174        /// Dossier de destination (défaut : ~/.local/share/mnemo/backups/).
175        #[arg(long, value_name = "DOSSIER")]
176        output: Option<PathBuf>,
177        /// Produit une sortie JSON exploitable.
178        #[arg(long)]
179        json: bool,
180    },
181
182    /// Restaure une sauvegarde (.tar.gz) après vérification.
183    Restore {
184        /// Chemin de l'archive de sauvegarde.
185        archive: PathBuf,
186        /// Montre ce qui serait fait sans rien modifier.
187        #[arg(long = "dry-run")]
188        dry_run: bool,
189        /// Confirme la restauration sans question interactive.
190        #[arg(long)]
191        yes: bool,
192    },
193
194    /// Exporte les commandes en JSON ou CSV.
195    Export {
196        /// Format de sortie.
197        #[arg(long, value_enum)]
198        format: ExportFormat,
199        /// Filtre sur un projet Git (nom du dossier racine ou chemin git_root).
200        #[arg(long, value_name = "NOM")]
201        project: Option<String>,
202        /// Filtre sur une branche Git.
203        #[arg(long, value_name = "BRANCHE")]
204        branch: Option<String>,
205        /// Fichier de sortie (défaut : stdout).
206        #[arg(long, value_name = "FICHIER")]
207        output: Option<PathBuf>,
208        /// Compresse la sortie en gzip (`.json.gz` / `.csv.gz`).
209        #[arg(long)]
210        gzip: bool,
211    },
212
213    /// Affiche les dernières commandes avec leurs IDs.
214    List {
215        /// Nombre de commandes affichées (défaut : 20).
216        #[arg(long)]
217        limit: Option<usize>,
218        /// Filtre sur un projet Git (nom du dossier racine ou chemin git_root).
219        #[arg(long, value_name = "NOM")]
220        project: Option<String>,
221        /// Filtre sur une branche Git.
222        #[arg(long, value_name = "BRANCHE")]
223        branch: Option<String>,
224        /// Produit une sortie JSON exploitable.
225        #[arg(long)]
226        json: bool,
227    },
228
229    /// Affiche le détail complet d'une commande par son ID, sans l'exécuter.
230    ///
231    /// mnemo n'exécute jamais une commande de l'historique : `show` se contente
232    /// de lire la base. Si la commande a déjà été redactée, sa forme redactée
233    /// stockée est affichée telle quelle.
234    Show {
235        /// Identifiant de la commande (voir `mnemo list` ou `mnemo search`).
236        id: i64,
237    },
238
239    /// Imprime uniquement la commande brute sur stdout, sans décor ni exécution.
240    ///
241    /// Aucun label, aucune couleur : la sortie peut être copiée ou redirigée.
242    /// mnemo n'exécute jamais la commande ; l'utilisateur reste responsable de
243    /// ce qu'il fait de la sortie.
244    Print {
245        /// Identifiant de la commande (voir `mnemo list` ou `mnemo search`).
246        id: i64,
247    },
248
249    /// Supprime une commande par son ID (après confirmation).
250    Delete {
251        /// Identifiant de la commande à supprimer.
252        id: i64,
253        /// Montre la commande ciblée sans la supprimer.
254        #[arg(long = "dry-run")]
255        dry_run: bool,
256        /// Confirme la suppression sans question interactive.
257        #[arg(long)]
258        yes: bool,
259    },
260
261    /// Nettoie les commandes plus anciennes qu'une durée donnée.
262    Prune {
263        /// Durée d'ancienneté (ex : 30d, 12w, 6m, 1y).
264        #[arg(long = "older-than", value_name = "DURÉE")]
265        older_than: String,
266        /// Filtre sur un projet Git (nom du dossier racine ou chemin git_root).
267        #[arg(long, value_name = "NOM")]
268        project: Option<String>,
269        /// Filtre sur une branche Git.
270        #[arg(long, value_name = "BRANCHE")]
271        branch: Option<String>,
272        /// Montre ce qui serait supprimé sans rien modifier.
273        #[arg(long = "dry-run")]
274        dry_run: bool,
275        /// Confirme le nettoyage sans question interactive.
276        #[arg(long)]
277        yes: bool,
278    },
279
280    /// Affiche des informations détaillées de version et de build.
281    Version,
282
283    /// Vérifie si une nouvelle version est disponible (sans rien installer).
284    ///
285    /// En terminal interactif, si une mise à jour existe, propose de lancer
286    /// `mnemo upgrade` immédiatement (réponse par défaut : non). En mode non
287    /// interactif (CI, script, cron, pipe), reste une simple vérification.
288    /// `--upgrade` enchaîne directement l'installation quand une mise à jour est
289    /// disponible ; combiné à `--yes`, il permet un upgrade automatisé.
290    /// `--require-signature` rend la vérification Sigstore (cosign) obligatoire
291    /// lors de l'upgrade enchaîné.
292    Update {
293        /// Sortie au format JSON (vérification seule, sans proposition).
294        #[arg(long)]
295        json: bool,
296        /// Si une mise à jour est disponible, lance directement `mnemo upgrade`.
297        #[arg(long)]
298        upgrade: bool,
299        /// Avec `--upgrade`, installe sans confirmation interactive.
300        #[arg(long)]
301        yes: bool,
302        /// Avec `--upgrade`, exige une signature Sigstore valide (cosign).
303        #[arg(long = "require-signature")]
304        require_signature: bool,
305    },
306
307    /// Télécharge et installe la dernière version stable (remplace le binaire).
308    Upgrade {
309        /// Montre ce qui serait fait sans rien télécharger ni remplacer.
310        #[arg(long = "dry-run")]
311        dry_run: bool,
312        /// Confirme l'installation sans question interactive.
313        #[arg(long)]
314        yes: bool,
315        /// Force une version précise (ex : v0.5.0) au lieu de la dernière.
316        #[arg(long, value_name = "VERSION")]
317        version: Option<String>,
318        /// Force un triplet cible (ex : aarch64-unknown-linux-musl).
319        #[arg(long, value_name = "CIBLE")]
320        target: Option<String>,
321        /// Exige une signature Sigstore valide (cosign requis) avant d'installer.
322        #[arg(long = "require-signature")]
323        require_signature: bool,
324    },
325
326    /// Désinstalle mnemo : binaire + intégration shell. Conserve les données.
327    Uninstall {
328        /// Montre ce qui serait supprimé sans rien modifier.
329        #[arg(long = "dry-run")]
330        dry_run: bool,
331        /// Confirme la désinstallation sans question interactive.
332        #[arg(long)]
333        yes: bool,
334        /// Supprime AUSSI la configuration, la base et les sauvegardes.
335        #[arg(long)]
336        purge: bool,
337    },
338
339    /// Inspecte le projet courant et les projets connus de l'historique.
340    Project {
341        #[command(subcommand)]
342        action: ProjectCommand,
343    },
344
345    /// Maintenance de l'historique (nettoyage automatique configurable).
346    Maintenance {
347        #[command(subcommand)]
348        action: MaintenanceCommand,
349    },
350
351    /// Navigue, consulte et exporte des sessions de travail.
352    ///
353    /// Une session regroupe les commandes partageant un même `session_id`,
354    /// capturé par l'intégration shell (`MNEMO_SESSION_ID`). Les commandes
355    /// importées ou enregistrées sans cet identifiant ne sont pas rattachées à
356    /// une session.
357    Session {
358        #[command(subcommand)]
359        action: SessionCommand,
360    },
361
362    /// Analyse et redacte les secrets présents dans l'historique déjà stocké.
363    ///
364    /// `scan` repère les commandes potentiellement sensibles et les affiche
365    /// toujours sous forme redactée. `redact` les nettoie en place (dry-run par
366    /// défaut, sauvegarde obligatoire avant toute écriture). Aucun secret n'est
367    /// jamais affiché en clair.
368    Secrets {
369        #[command(subcommand)]
370        action: SecretsCommand,
371    },
372
373    /// Génère un runbook Markdown réutilisable à partir d'une session ou d'un
374    /// projet Git.
375    ///
376    /// Chaque commande est présentée dans une section Markdown numérotée avec
377    /// son répertoire de travail, triée par ordre chronologique (le plus ancien
378    /// en premier). Les commandes vides sont exclues. Le résultat peut être
379    /// écrit sur stdout (défaut) ou dans un fichier (`--output`).
380    ///
381    /// Exactement un des drapeaux `--last`, `--session` ou `--project` est
382    /// requis. Si aucun n'est fourni, une erreur claire est affichée.
383    Runbook {
384        /// Cible la dernière session (incompatible avec `--session` et
385        /// `--project`).
386        #[arg(long, conflicts_with_all = ["session", "project"])]
387        last: bool,
388        /// Identifiant de session explicite (incompatible avec `--last` et
389        /// `--project`).
390        #[arg(long, value_name = "ID", conflicts_with_all = ["last", "project"])]
391        session: Option<String>,
392        /// Nom court ou chemin `git_root` d'un projet (incompatible avec
393        /// `--last` et `--session`).
394        #[arg(long, value_name = "NOM|CHEMIN", conflicts_with_all = ["last", "session"])]
395        project: Option<String>,
396        /// Fichier de sortie (défaut : stdout).
397        #[arg(long, value_name = "FICHIER")]
398        output: Option<PathBuf>,
399        /// Autorise l'écrasement du fichier de sortie si déjà existant.
400        #[arg(long)]
401        force: bool,
402        /// Nombre maximal de commandes incluses dans le runbook.
403        #[arg(long, value_name = "N")]
404        limit: Option<u32>,
405        /// Titre personnalisé du runbook (défaut : identifiant de session ou
406        /// nom de projet).
407        #[arg(long, value_name = "TITRE")]
408        title: Option<String>,
409    },
410}
411
412/// Regroupe les options de `mnemo search` pour éviter une fonction à trop
413/// d'arguments (filtres combinables passés en un bloc).
414#[derive(Debug, Default)]
415pub struct SearchArgs {
416    pub query: Option<String>,
417    pub print: bool,
418    pub limit: usize,
419    pub project: Option<String>,
420    pub branch: Option<String>,
421    pub exit_code: Option<i64>,
422    pub failed: bool,
423    pub since: Option<String>,
424    pub before: Option<String>,
425    pub cwd: Option<String>,
426    pub shell: Option<String>,
427    pub json: bool,
428    pub id_only: bool,
429}
430
431/// Shells supportés par `mnemo completions`. Limité volontairement à bash, zsh
432/// et fish (un shell inconnu produit une erreur claire de clap). L'enregistrement
433/// automatique du hook reste, lui, Bash-first.
434#[derive(Clone, Copy, Debug, ValueEnum)]
435pub enum CompletionShell {
436    Bash,
437    Zsh,
438    Fish,
439}
440
441impl CompletionShell {
442    /// Convertit vers le générateur `clap_complete` correspondant.
443    pub fn generator(self) -> Shell {
444        match self {
445            CompletionShell::Bash => Shell::Bash,
446            CompletionShell::Zsh => Shell::Zsh,
447            CompletionShell::Fish => Shell::Fish,
448        }
449    }
450}
451
452#[derive(Subcommand, Debug)]
453pub enum ConfigCommand {
454    /// Affiche la configuration effective (valeurs par défaut incluses).
455    Show,
456    /// Affiche le chemin du fichier de configuration.
457    Path,
458    /// Ouvre la configuration dans l'éditeur ($EDITOR, sinon nano/vi).
459    Edit,
460    /// Vérifie la validité du fichier de configuration.
461    Validate,
462    /// Gère la liste des commandes ignorées dans `mnemo stats`.
463    StatsIgnore {
464        #[command(subcommand)]
465        action: StatsIgnoreCommand,
466    },
467}
468
469#[derive(Subcommand, Debug)]
470pub enum ProjectCommand {
471    /// Affiche le projet détecté pour le répertoire courant.
472    Current,
473    /// Liste les projets connus de l'historique.
474    List {
475        /// Nombre maximal de projets affichés.
476        #[arg(long, value_name = "N")]
477        limit: Option<usize>,
478        /// Sortie JSON.
479        #[arg(long)]
480        json: bool,
481    },
482    /// Affiche le détail d'un projet : activité, branches, derniers échecs.
483    Show {
484        /// Racine ou nom court du projet (incompatible avec `--current`).
485        #[arg(value_name = "PROJET", conflicts_with = "current")]
486        project: Option<String>,
487        /// Cible le projet du répertoire courant.
488        #[arg(long)]
489        current: bool,
490        /// Nombre maximal de commandes récentes affichées.
491        #[arg(long, value_name = "N")]
492        limit: Option<usize>,
493        /// Sortie JSON.
494        #[arg(long)]
495        json: bool,
496    },
497    /// Génère un rapport d'activité réutilisable (Markdown par défaut, ou JSON).
498    Report {
499        /// Racine ou nom court du projet (incompatible avec `--current`).
500        #[arg(value_name = "PROJET", conflicts_with = "current")]
501        project: Option<String>,
502        /// Cible le projet du répertoire courant.
503        #[arg(long)]
504        current: bool,
505        /// Borne inférieure (`24h`, `7d`, `2w`, `3m`, `1y` ou `AAAA-MM-JJ`).
506        #[arg(long, value_name = "DURÉE|DATE")]
507        since: Option<String>,
508        /// Borne supérieure (`AAAA-MM-JJ` exclue, ou durée).
509        #[arg(long, value_name = "DURÉE|DATE")]
510        until: Option<String>,
511        /// Format de sortie (`markdown` par défaut).
512        #[arg(long, value_enum, default_value = "markdown")]
513        format: SessionFormat,
514        /// Fichier de sortie (défaut : stdout).
515        #[arg(long, value_name = "FICHIER")]
516        output: Option<PathBuf>,
517        /// Autorise l'écrasement d'un fichier de sortie existant.
518        #[arg(long)]
519        force: bool,
520        /// Nombre maximal de commandes détaillées dans le rapport.
521        #[arg(long, value_name = "N")]
522        limit: Option<usize>,
523    },
524}
525
526#[derive(Subcommand, Debug)]
527pub enum MaintenanceCommand {
528    /// Affiche l'état de la maintenance et ce qui serait nettoyé.
529    Status,
530    /// Exécute le nettoyage configuré.
531    Run {
532        /// Montre ce qui serait supprimé sans rien modifier.
533        #[arg(long = "dry-run")]
534        dry_run: bool,
535        /// Confirme le nettoyage sans question interactive.
536        #[arg(long)]
537        yes: bool,
538    },
539}
540
541#[derive(Subcommand, Debug)]
542pub enum StatsIgnoreCommand {
543    /// Ajoute une commande à la liste ignorée du Top commandes.
544    Add {
545        /// Nom de commande (ex: `create_dir`).
546        name: String,
547    },
548    /// Retire une commande de la liste ignorée.
549    Remove {
550        /// Nom de commande (ex: `create_dir`).
551        name: String,
552    },
553    /// Affiche les commandes actuellement ignorées.
554    List,
555}
556
557#[derive(Subcommand, Debug)]
558pub enum ShellCommand {
559    /// Met à niveau l'intégration Bash installée dans ~/.bashrc.
560    ///
561    /// Remplace un bloc obsolète par la version courante (capture de
562    /// `MNEMO_SESSION_ID` pour `mnemo session`), après sauvegarde et sans
563    /// toucher au reste du fichier. Sans bloc installé, propose `mnemo init`.
564    Upgrade,
565}
566
567/// Format d'export d'une session (`mnemo session export`).
568#[derive(Clone, Copy, Debug, PartialEq, Eq, ValueEnum)]
569pub enum SessionFormat {
570    Markdown,
571    Json,
572}
573
574#[derive(Subcommand, Debug)]
575pub enum SessionCommand {
576    /// Liste les sessions connues, de la plus récente à la plus ancienne.
577    List {
578        /// Nombre maximal de sessions affichées.
579        #[arg(long, value_name = "N")]
580        limit: Option<usize>,
581    },
582    /// Affiche les commandes d'une session, dans l'ordre chronologique.
583    Show {
584        /// Identifiant de session (voir `mnemo session list`).
585        session_id: String,
586        /// Nombre maximal de commandes affichées.
587        #[arg(long, value_name = "N")]
588        limit: Option<usize>,
589    },
590    /// Exporte une session en Markdown (défaut) ou JSON.
591    Export {
592        /// Identifiant de session à exporter (incompatible avec `--last`).
593        #[arg(value_name = "SESSION_ID", conflicts_with = "last")]
594        session_id: Option<String>,
595        /// Cible la session la plus récente au lieu d'un identifiant explicite.
596        #[arg(long)]
597        last: bool,
598        /// Format de sortie (`markdown` par défaut).
599        #[arg(long, value_enum, default_value = "markdown")]
600        format: SessionFormat,
601        /// Fichier de sortie (défaut : stdout).
602        #[arg(long, value_name = "FICHIER")]
603        output: Option<PathBuf>,
604        /// Autorise l'écrasement d'un fichier de sortie existant.
605        #[arg(long)]
606        force: bool,
607    },
608}
609
610#[derive(Subcommand, Debug)]
611pub enum SecretsCommand {
612    /// Repère les commandes potentiellement sensibles (lecture seule).
613    ///
614    /// Les commandes sont toujours affichées sous forme redactée ; aucun secret
615    /// n'apparaît en clair. N'effectue aucune modification.
616    Scan {
617        /// Nombre maximal de résultats affichés.
618        #[arg(long, value_name = "N")]
619        limit: Option<usize>,
620        /// Sortie JSON (sans valeurs sensibles).
621        #[arg(long)]
622        json: bool,
623    },
624    /// Redacte en place les commandes sensibles déjà stockées.
625    ///
626    /// Dry-run par défaut : sans `--apply`, rien n'est modifié. Avec `--apply`,
627    /// une sauvegarde est créée avant toute écriture et seule la colonne
628    /// `command` est mise à jour.
629    Redact {
630        /// Montre ce qui serait redacté sans rien modifier (comportement par
631        /// défaut, accepté explicitement).
632        #[arg(long = "dry-run")]
633        dry_run: bool,
634        /// Applique réellement la redaction (sinon dry-run).
635        #[arg(long)]
636        apply: bool,
637        /// Confirme la redaction sans question interactive.
638        #[arg(long)]
639        yes: bool,
640        /// Force une sauvegarde avant redaction (toujours effectuée avec
641        /// `--apply`, ce drapeau le rend explicite).
642        #[arg(long)]
643        backup: bool,
644    },
645}