Skip to main content

lean_ctx/cli/completions/
spec.rs

1//! Static command-tree specification for CLI completions.
2//!
3//! Every top-level command, its subcommands, flags and dynamic value kinds
4//! live here so the completion engine has a single source of truth.
5
6/// Describes a dynamic value set resolved at completion time.
7#[derive(Clone, Copy)]
8pub enum DynamicKind {
9    Agents,
10    Shells,
11    Modes,
12    ConfigKeys,
13    Profiles,
14    TerseLevel,
15}
16
17/// A flag/option accepted by a command.
18pub struct FlagSpec {
19    pub long: &'static str,
20    pub short: Option<char>,
21    pub description: &'static str,
22    pub takes_value: bool,
23    pub value_kind: Option<DynamicKind>,
24}
25
26/// A command or subcommand node in the tree.
27pub struct CommandNode {
28    pub name: &'static str,
29    pub aliases: &'static [&'static str],
30    pub description: &'static str,
31    pub subcommands: &'static [CommandNode],
32    pub flags: &'static [FlagSpec],
33    pub positional: Option<DynamicKind>,
34    pub hidden: bool,
35}
36
37pub static COMMAND_TREE: &[CommandNode] = &[
38    CommandNode {
39        name: "shell",
40        aliases: &[],
41        description: "Activate shell integration",
42        subcommands: &[],
43        flags: &[
44            FlagSpec {
45                long: "--agent",
46                short: Some('a'),
47                description: "Agent name",
48                takes_value: true,
49                value_kind: Some(DynamicKind::Agents),
50            },
51            FlagSpec {
52                long: "--mode",
53                short: Some('m'),
54                description: "Integration mode",
55                takes_value: true,
56                value_kind: Some(DynamicKind::Modes),
57            },
58        ],
59        positional: Some(DynamicKind::Shells),
60        hidden: false,
61    },
62    CommandNode {
63        name: "init",
64        aliases: &["setup", "onboard", "install", "bootstrap"],
65        description: "Initialize lean-ctx for an agent",
66        subcommands: &[],
67        flags: &[
68            FlagSpec {
69                long: "--agent",
70                short: Some('a'),
71                description: "Agent name",
72                takes_value: true,
73                value_kind: Some(DynamicKind::Agents),
74            },
75            FlagSpec {
76                long: "--mode",
77                short: Some('m'),
78                description: "Integration mode",
79                takes_value: true,
80                value_kind: Some(DynamicKind::Modes),
81            },
82        ],
83        positional: None,
84        hidden: false,
85    },
86    CommandNode {
87        name: "status",
88        aliases: &[],
89        description: "Show current status",
90        subcommands: &[],
91        flags: &[FlagSpec {
92            long: "--json",
93            short: None,
94            description: "JSON output",
95            takes_value: false,
96            value_kind: None,
97        }],
98        positional: None,
99        hidden: false,
100    },
101    CommandNode {
102        name: "config",
103        aliases: &[],
104        description: "Manage configuration",
105        subcommands: &[
106            CommandNode {
107                name: "get",
108                aliases: &[],
109                description: "Get a config value",
110                subcommands: &[],
111                flags: &[],
112                positional: Some(DynamicKind::ConfigKeys),
113                hidden: false,
114            },
115            CommandNode {
116                name: "set",
117                aliases: &[],
118                description: "Set a config value",
119                subcommands: &[],
120                flags: &[],
121                positional: Some(DynamicKind::ConfigKeys),
122                hidden: false,
123            },
124            CommandNode {
125                name: "edit",
126                aliases: &[],
127                description: "Open config in editor",
128                subcommands: &[],
129                flags: &[],
130                positional: None,
131                hidden: false,
132            },
133            CommandNode {
134                name: "show",
135                aliases: &[],
136                description: "Show current config",
137                subcommands: &[],
138                flags: &[FlagSpec {
139                    long: "--json",
140                    short: None,
141                    description: "JSON output",
142                    takes_value: false,
143                    value_kind: None,
144                }],
145                positional: None,
146                hidden: false,
147            },
148        ],
149        flags: &[],
150        positional: None,
151        hidden: false,
152    },
153    CommandNode {
154        name: "proxy",
155        aliases: &["serve"],
156        description: "Start the proxy server",
157        subcommands: &[
158            CommandNode {
159                name: "start",
160                aliases: &[],
161                description: "Start proxy",
162                subcommands: &[],
163                flags: &[
164                    FlagSpec {
165                        long: "--detach",
166                        short: Some('d'),
167                        description: "Run in background",
168                        takes_value: false,
169                        value_kind: None,
170                    },
171                    FlagSpec {
172                        long: "--port",
173                        short: Some('p'),
174                        description: "Port number",
175                        takes_value: true,
176                        value_kind: None,
177                    },
178                ],
179                positional: None,
180                hidden: false,
181            },
182            CommandNode {
183                name: "stop",
184                aliases: &[],
185                description: "Stop proxy",
186                subcommands: &[],
187                flags: &[],
188                positional: None,
189                hidden: false,
190            },
191        ],
192        flags: &[
193            FlagSpec {
194                long: "--port",
195                short: Some('p'),
196                description: "Port number",
197                takes_value: true,
198                value_kind: None,
199            },
200            FlagSpec {
201                long: "--detach",
202                short: Some('d'),
203                description: "Run in background",
204                takes_value: false,
205                value_kind: None,
206            },
207        ],
208        positional: None,
209        hidden: false,
210    },
211    CommandNode {
212        name: "dashboard",
213        aliases: &[],
214        description: "Open the dashboard",
215        subcommands: &[],
216        flags: &[FlagSpec {
217            long: "--port",
218            short: Some('p'),
219            description: "Port number",
220            takes_value: true,
221            value_kind: None,
222        }],
223        positional: None,
224        hidden: false,
225    },
226    CommandNode {
227        name: "cache",
228        aliases: &[],
229        description: "Manage the cache",
230        subcommands: &[
231            CommandNode {
232                name: "stats",
233                aliases: &[],
234                description: "Cache statistics",
235                subcommands: &[],
236                flags: &[],
237                positional: None,
238                hidden: false,
239            },
240            CommandNode {
241                name: "clear",
242                aliases: &[],
243                description: "Clear cache",
244                subcommands: &[],
245                flags: &[],
246                positional: None,
247                hidden: false,
248            },
249            CommandNode {
250                name: "export",
251                aliases: &[],
252                description: "Export cache",
253                subcommands: &[],
254                flags: &[],
255                positional: None,
256                hidden: false,
257            },
258        ],
259        flags: &[],
260        positional: None,
261        hidden: false,
262    },
263    CommandNode {
264        name: "terse",
265        aliases: &["compression"],
266        description: "Set compression level",
267        subcommands: &[],
268        flags: &[],
269        positional: Some(DynamicKind::TerseLevel),
270        hidden: false,
271    },
272    CommandNode {
273        name: "profile",
274        aliases: &[],
275        description: "Set tool profile",
276        subcommands: &[],
277        flags: &[],
278        positional: Some(DynamicKind::Profiles),
279        hidden: false,
280    },
281    CommandNode {
282        name: "gain",
283        aliases: &["savings", "output-savings"],
284        description: "Show token savings",
285        subcommands: &[],
286        flags: &[
287            FlagSpec {
288                long: "--json",
289                short: None,
290                description: "JSON output",
291                takes_value: false,
292                value_kind: None,
293            },
294            FlagSpec {
295                long: "--by-tool",
296                short: None,
297                description: "Per-tool savings breakdown",
298                takes_value: false,
299                value_kind: None,
300            },
301        ],
302        positional: None,
303        hidden: false,
304    },
305    CommandNode {
306        name: "spend",
307        aliases: &["billing", "finops", "roi"],
308        description: "Show cost report",
309        subcommands: &[],
310        flags: &[FlagSpec {
311            long: "--json",
312            short: None,
313            description: "JSON output",
314            takes_value: false,
315            value_kind: None,
316        }],
317        positional: None,
318        hidden: false,
319    },
320    CommandNode {
321        name: "index",
322        aliases: &[],
323        description: "Build or rebuild search index",
324        subcommands: &[],
325        flags: &[FlagSpec {
326            long: "--force",
327            short: Some('f'),
328            description: "Force rebuild",
329            takes_value: false,
330            value_kind: None,
331        }],
332        positional: None,
333        hidden: false,
334    },
335    CommandNode {
336        name: "explore",
337        aliases: &["repomap", "repo-map"],
338        description: "Explore repository structure",
339        subcommands: &[],
340        flags: &[
341            FlagSpec {
342                long: "--depth",
343                short: Some('d'),
344                description: "Max depth",
345                takes_value: true,
346                value_kind: None,
347            },
348            FlagSpec {
349                long: "--json",
350                short: None,
351                description: "JSON output",
352                takes_value: false,
353                value_kind: None,
354            },
355        ],
356        positional: None,
357        hidden: false,
358    },
359    CommandNode {
360        name: "compress",
361        aliases: &["compact"],
362        description: "Compress input",
363        subcommands: &[],
364        flags: &[],
365        positional: None,
366        hidden: false,
367    },
368    CommandNode {
369        name: "update",
370        aliases: &["upgrade"],
371        description: "Update lean-ctx",
372        subcommands: &[],
373        flags: &[FlagSpec {
374            long: "--check",
375            short: None,
376            description: "Check only, don't install",
377            takes_value: false,
378            value_kind: None,
379        }],
380        positional: None,
381        hidden: false,
382    },
383    CommandNode {
384        name: "stop",
385        aliases: &[],
386        description: "Stop all lean-ctx processes",
387        subcommands: &[],
388        flags: &[],
389        positional: None,
390        hidden: false,
391    },
392    CommandNode {
393        name: "restart",
394        aliases: &[],
395        description: "Restart lean-ctx",
396        subcommands: &[],
397        flags: &[],
398        positional: None,
399        hidden: false,
400    },
401    CommandNode {
402        name: "dev-install",
403        aliases: &[],
404        description: "Development install (stop+build+install+restart)",
405        subcommands: &[],
406        flags: &[],
407        positional: None,
408        hidden: false,
409    },
410    CommandNode {
411        name: "wrap",
412        aliases: &[],
413        description: "One-command setup for an agent",
414        subcommands: &[],
415        flags: &[],
416        positional: Some(DynamicKind::Agents),
417        hidden: false,
418    },
419    CommandNode {
420        name: "unwrap",
421        aliases: &[],
422        description: "Undo wrap, restore pre-wrap config",
423        subcommands: &[],
424        flags: &[],
425        positional: Some(DynamicKind::Agents),
426        hidden: false,
427    },
428    CommandNode {
429        name: "doctor",
430        aliases: &[],
431        description: "Diagnose installation issues",
432        subcommands: &[],
433        flags: &[],
434        positional: None,
435        hidden: false,
436    },
437    CommandNode {
438        name: "selftest",
439        aliases: &["health"],
440        description: "Run self-test",
441        subcommands: &[],
442        flags: &[],
443        positional: None,
444        hidden: false,
445    },
446    CommandNode {
447        name: "rules",
448        aliases: &[],
449        description: "Manage rules",
450        subcommands: &[],
451        flags: &[],
452        positional: None,
453        hidden: false,
454    },
455    CommandNode {
456        name: "export-rules",
457        aliases: &[],
458        description: "Export rules to file",
459        subcommands: &[],
460        flags: &[],
461        positional: None,
462        hidden: false,
463    },
464    CommandNode {
465        name: "harden",
466        aliases: &["security", "lockdown"],
467        description: "Harden security settings",
468        subcommands: &[],
469        flags: &[],
470        positional: None,
471        hidden: false,
472    },
473    CommandNode {
474        name: "completions",
475        aliases: &[],
476        description: "Generate shell completion script",
477        subcommands: &[],
478        flags: &[],
479        positional: Some(DynamicKind::Shells),
480        hidden: false,
481    },
482    CommandNode {
483        name: "gotchas",
484        aliases: &["bugs"],
485        description: "Show known gotchas",
486        subcommands: &[],
487        flags: &[],
488        positional: None,
489        hidden: false,
490    },
491    CommandNode {
492        name: "learn",
493        aliases: &[],
494        description: "Interactive learning",
495        subcommands: &[],
496        flags: &[],
497        positional: None,
498        hidden: false,
499    },
500    CommandNode {
501        name: "cloud",
502        aliases: &[],
503        description: "Cloud features",
504        subcommands: &[],
505        flags: &[],
506        positional: None,
507        hidden: false,
508    },
509    CommandNode {
510        name: "help",
511        aliases: &[],
512        description: "Show help",
513        subcommands: &[],
514        flags: &[],
515        positional: None,
516        hidden: false,
517    },
518    CommandNode {
519        name: "eval",
520        aliases: &[],
521        description: "Evaluate compression quality",
522        subcommands: &[],
523        flags: &[],
524        positional: None,
525        hidden: false,
526    },
527    CommandNode {
528        name: "audit",
529        aliases: &["compliance"],
530        description: "Run compliance audit",
531        subcommands: &[],
532        flags: &[],
533        positional: None,
534        hidden: false,
535    },
536    CommandNode {
537        name: "agent",
538        aliases: &[],
539        description: "Manage agent integrations",
540        subcommands: &[],
541        flags: &[FlagSpec {
542            long: "--agent",
543            short: Some('a'),
544            description: "Agent name",
545            takes_value: true,
546            value_kind: Some(DynamicKind::Agents),
547        }],
548        positional: None,
549        hidden: false,
550    },
551    CommandNode {
552        name: "session",
553        aliases: &["sessions"],
554        description: "Manage sessions",
555        subcommands: &[],
556        flags: &[],
557        positional: None,
558        hidden: false,
559    },
560    CommandNode {
561        name: "knowledge",
562        aliases: &[],
563        description: "Manage knowledge base",
564        subcommands: &[],
565        flags: &[],
566        positional: None,
567        hidden: false,
568    },
569    CommandNode {
570        name: "stats",
571        aliases: &["introspect"],
572        description: "Show statistics",
573        subcommands: &[],
574        flags: &[FlagSpec {
575            long: "--json",
576            short: None,
577            description: "JSON output",
578            takes_value: false,
579            value_kind: None,
580        }],
581        positional: None,
582        hidden: false,
583    },
584    CommandNode {
585        name: "cheatsheet",
586        aliases: &[],
587        description: "Show cheatsheet",
588        subcommands: &[],
589        flags: &[],
590        positional: None,
591        hidden: false,
592    },
593    CommandNode {
594        name: "mcp",
595        aliases: &[],
596        description: "MCP server management",
597        subcommands: &[],
598        flags: &[],
599        positional: None,
600        hidden: false,
601    },
602    CommandNode {
603        name: "wrapped",
604        aliases: &[],
605        description: "Show wrapped summary",
606        subcommands: &[],
607        flags: &[],
608        positional: None,
609        hidden: false,
610    },
611    CommandNode {
612        name: "addon",
613        aliases: &["addons", "plugin", "plugins"],
614        description: "Manage addons",
615        subcommands: &[
616            CommandNode {
617                name: "list",
618                aliases: &[],
619                description: "List addons",
620                subcommands: &[],
621                flags: &[],
622                positional: None,
623                hidden: false,
624            },
625            CommandNode {
626                name: "install",
627                aliases: &[],
628                description: "Install addon",
629                subcommands: &[],
630                flags: &[],
631                positional: None,
632                hidden: false,
633            },
634            CommandNode {
635                name: "remove",
636                aliases: &[],
637                description: "Remove addon",
638                subcommands: &[],
639                flags: &[],
640                positional: None,
641                hidden: false,
642            },
643            CommandNode {
644                name: "info",
645                aliases: &[],
646                description: "Addon info",
647                subcommands: &[],
648                flags: &[],
649                positional: None,
650                hidden: false,
651            },
652        ],
653        flags: &[],
654        positional: None,
655        hidden: false,
656    },
657    CommandNode {
658        name: "verify",
659        aliases: &["proof"],
660        description: "Verify cache integrity",
661        subcommands: &[],
662        flags: &[],
663        positional: None,
664        hidden: false,
665    },
666    CommandNode {
667        name: "verify-cache",
668        aliases: &["cache-selftest"],
669        description: "Verify cache consistency",
670        subcommands: &[],
671        flags: &[],
672        positional: None,
673        hidden: false,
674    },
675    CommandNode {
676        name: "visualize",
677        aliases: &[],
678        description: "Visualize context graph",
679        subcommands: &[],
680        flags: &[],
681        positional: None,
682        hidden: false,
683    },
684    CommandNode {
685        name: "instructions",
686        aliases: &[],
687        description: "Show agent instructions",
688        subcommands: &[],
689        flags: &[],
690        positional: None,
691        hidden: false,
692    },
693    CommandNode {
694        name: "semantic-search",
695        aliases: &["search-code"],
696        description: "Semantic code search",
697        subcommands: &[],
698        flags: &[],
699        positional: None,
700        hidden: false,
701    },
702    CommandNode {
703        name: "read",
704        aliases: &[],
705        description: "Read and compress a file",
706        subcommands: &[],
707        flags: &[],
708        positional: None,
709        hidden: false,
710    },
711    CommandNode {
712        name: "call",
713        aliases: &[],
714        description: "Call an MCP tool",
715        subcommands: &[],
716        flags: &[],
717        positional: None,
718        hidden: false,
719    },
720    CommandNode {
721        name: "diff",
722        aliases: &[],
723        description: "Compressed diff",
724        subcommands: &[],
725        flags: &[],
726        positional: None,
727        hidden: false,
728    },
729    CommandNode {
730        name: "grep",
731        aliases: &["find"],
732        description: "Search with compression",
733        subcommands: &[],
734        flags: &[],
735        positional: None,
736        hidden: false,
737    },
738    CommandNode {
739        name: "glob",
740        aliases: &[],
741        description: "Glob file search",
742        subcommands: &[],
743        flags: &[],
744        positional: None,
745        hidden: false,
746    },
747    CommandNode {
748        name: "ls",
749        aliases: &[],
750        description: "List directory contents",
751        subcommands: &[],
752        flags: &[],
753        positional: None,
754        hidden: false,
755    },
756    CommandNode {
757        name: "deps",
758        aliases: &[],
759        description: "Show dependencies",
760        subcommands: &[],
761        flags: &[],
762        positional: None,
763        hidden: false,
764    },
765    CommandNode {
766        name: "discover",
767        aliases: &[],
768        description: "Discover project structure",
769        subcommands: &[],
770        flags: &[],
771        positional: None,
772        hidden: false,
773    },
774    CommandNode {
775        name: "ghost",
776        aliases: &[],
777        description: "Ghost context injection",
778        subcommands: &[],
779        flags: &[],
780        positional: None,
781        hidden: false,
782    },
783    CommandNode {
784        name: "filter",
785        aliases: &[],
786        description: "Filter context",
787        subcommands: &[],
788        flags: &[],
789        positional: None,
790        hidden: false,
791    },
792    CommandNode {
793        name: "heatmap",
794        aliases: &[],
795        description: "Show file heatmap",
796        subcommands: &[],
797        flags: &[],
798        positional: None,
799        hidden: false,
800    },
801    CommandNode {
802        name: "graph",
803        aliases: &[],
804        description: "Show dependency graph",
805        subcommands: &[],
806        flags: &[],
807        positional: None,
808        hidden: false,
809    },
810    CommandNode {
811        name: "smells",
812        aliases: &[],
813        description: "Detect code smells",
814        subcommands: &[],
815        flags: &[],
816        positional: None,
817        hidden: false,
818    },
819    CommandNode {
820        name: "ledger",
821        aliases: &[],
822        description: "Token usage ledger",
823        subcommands: &[],
824        flags: &[],
825        positional: None,
826        hidden: false,
827    },
828    CommandNode {
829        name: "control",
830        aliases: &[],
831        description: "Runtime control",
832        subcommands: &[],
833        flags: &[],
834        positional: None,
835        hidden: false,
836    },
837    CommandNode {
838        name: "plan",
839        aliases: &[],
840        description: "Plan context strategy",
841        subcommands: &[],
842        flags: &[],
843        positional: None,
844        hidden: false,
845    },
846    CommandNode {
847        name: "compile",
848        aliases: &[],
849        description: "Compile context",
850        subcommands: &[],
851        flags: &[],
852        positional: None,
853        hidden: false,
854    },
855    CommandNode {
856        name: "skillify",
857        aliases: &[],
858        description: "Generate skill from code",
859        subcommands: &[],
860        flags: &[],
861        positional: None,
862        hidden: false,
863    },
864    CommandNode {
865        name: "summary",
866        aliases: &["overview"],
867        description: "Show project summary",
868        subcommands: &[],
869        flags: &[],
870        positional: None,
871        hidden: false,
872    },
873    CommandNode {
874        name: "benchmark",
875        aliases: &[],
876        description: "Run compression benchmarks",
877        subcommands: &[CommandNode {
878            name: "replay",
879            aliases: &[],
880            description: "Replay paired sessions with and without compression",
881            subcommands: &[],
882            flags: &[FlagSpec {
883                long: "--output",
884                short: None,
885                description: "Write Markdown report to a file",
886                takes_value: true,
887                value_kind: None,
888            }],
889            positional: None,
890            hidden: false,
891        }],
892        flags: &[],
893        positional: None,
894        hidden: false,
895    },
896    CommandNode {
897        name: "tools",
898        aliases: &[],
899        description: "List available MCP tools",
900        subcommands: &[],
901        flags: &[],
902        positional: None,
903        hidden: false,
904    },
905    CommandNode {
906        name: "allow",
907        aliases: &["trust"],
908        description: "Allow a command/path",
909        subcommands: &[],
910        flags: &[],
911        positional: None,
912        hidden: false,
913    },
914    CommandNode {
915        name: "untrust",
916        aliases: &[],
917        description: "Untrust a command/path",
918        subcommands: &[],
919        flags: &[],
920        positional: None,
921        hidden: false,
922    },
923    CommandNode {
924        name: "theme",
925        aliases: &[],
926        description: "Set dashboard theme",
927        subcommands: &[],
928        flags: &[],
929        positional: None,
930        hidden: false,
931    },
932    CommandNode {
933        name: "tee",
934        aliases: &[],
935        description: "Tee output to file",
936        subcommands: &[],
937        flags: &[],
938        positional: None,
939        hidden: false,
940    },
941    CommandNode {
942        name: "codesign-setup",
943        aliases: &[],
944        description: "Setup code signing",
945        subcommands: &[],
946        flags: &[],
947        positional: None,
948        hidden: false,
949    },
950    CommandNode {
951        name: "buddy",
952        aliases: &[],
953        description: "AI buddy assistant",
954        subcommands: &[],
955        flags: &[],
956        positional: None,
957        hidden: false,
958    },
959    CommandNode {
960        name: "learning",
961        aliases: &["conformance"],
962        description: "Show learning progress",
963        subcommands: &[],
964        flags: &[],
965        positional: None,
966        hidden: false,
967    },
968    CommandNode {
969        name: "token-report",
970        aliases: &["report-tokens"],
971        description: "Token usage report",
972        subcommands: &[],
973        flags: &[],
974        positional: None,
975        hidden: false,
976    },
977    CommandNode {
978        name: "pack",
979        aliases: &[],
980        description: "Pack context for export",
981        subcommands: &[],
982        flags: &[],
983        positional: None,
984        hidden: false,
985    },
986    CommandNode {
987        name: "policy",
988        aliases: &[],
989        description: "Manage security policies",
990        subcommands: &[],
991        flags: &[],
992        positional: None,
993        hidden: false,
994    },
995    CommandNode {
996        name: "cep",
997        aliases: &[],
998        description: "Context engineering pipeline",
999        subcommands: &[],
1000        flags: &[],
1001        positional: None,
1002        hidden: false,
1003    },
1004    CommandNode {
1005        name: "team",
1006        aliases: &[],
1007        description: "Team management",
1008        subcommands: &[],
1009        flags: &[],
1010        positional: None,
1011        hidden: false,
1012    },
1013    CommandNode {
1014        name: "provider",
1015        aliases: &[],
1016        description: "Manage LLM providers",
1017        subcommands: &[],
1018        flags: &[],
1019        positional: None,
1020        hidden: false,
1021    },
1022    CommandNode {
1023        name: "watch",
1024        aliases: &[],
1025        description: "Watch for file changes",
1026        subcommands: &[],
1027        flags: &[],
1028        positional: None,
1029        hidden: false,
1030    },
1031    CommandNode {
1032        name: "yolo",
1033        aliases: &["secure"],
1034        description: "Toggle security mode",
1035        subcommands: &[],
1036        flags: &[],
1037        positional: None,
1038        hidden: false,
1039    },
1040    // Hidden internal commands
1041    CommandNode {
1042        name: "__complete",
1043        aliases: &[],
1044        description: "Dynamic completion (internal)",
1045        subcommands: &[],
1046        flags: &[],
1047        positional: None,
1048        hidden: true,
1049    },
1050    CommandNode {
1051        name: "telemetry",
1052        aliases: &[],
1053        description: "Manage anonymous usage telemetry",
1054        subcommands: &[
1055            CommandNode {
1056                name: "status",
1057                aliases: &[],
1058                description: "Show current telemetry status",
1059                subcommands: &[],
1060                flags: &[],
1061                positional: None,
1062                hidden: false,
1063            },
1064            CommandNode {
1065                name: "on",
1066                aliases: &[],
1067                description: "Enable telemetry",
1068                subcommands: &[],
1069                flags: &[],
1070                positional: None,
1071                hidden: false,
1072            },
1073            CommandNode {
1074                name: "off",
1075                aliases: &[],
1076                description: "Disable telemetry",
1077                subcommands: &[],
1078                flags: &[],
1079                positional: None,
1080                hidden: false,
1081            },
1082            CommandNode {
1083                name: "show",
1084                aliases: &[],
1085                description: "Show current heartbeat payload",
1086                subcommands: &[],
1087                flags: &[],
1088                positional: None,
1089                hidden: false,
1090            },
1091            CommandNode {
1092                name: "reset-id",
1093                aliases: &[],
1094                description: "Regenerate installation ID",
1095                subcommands: &[],
1096                flags: &[],
1097                positional: None,
1098                hidden: false,
1099            },
1100            CommandNode {
1101                name: "history",
1102                aliases: &["log"],
1103                description: "Show log of sent heartbeats",
1104                subcommands: &[],
1105                flags: &[],
1106                positional: None,
1107                hidden: false,
1108            },
1109        ],
1110        flags: &[],
1111        positional: None,
1112        hidden: false,
1113    },
1114    CommandNode {
1115        name: "daemon",
1116        aliases: &[],
1117        description: "Start daemon (internal)",
1118        subcommands: &[],
1119        flags: &[],
1120        positional: None,
1121        hidden: true,
1122    },
1123];
1124
1125#[cfg(test)]
1126mod tests {
1127    use super::*;
1128
1129    #[test]
1130    fn no_duplicate_names_at_top_level() {
1131        let mut seen = std::collections::HashSet::new();
1132        for node in COMMAND_TREE {
1133            assert!(seen.insert(node.name), "duplicate: {}", node.name);
1134        }
1135    }
1136
1137    #[test]
1138    fn visible_count_exceeds_50() {
1139        let visible = COMMAND_TREE.iter().filter(|n| !n.hidden).count();
1140        assert!(
1141            visible >= 30,
1142            "expected at least 30 visible commands, got {visible}"
1143        );
1144    }
1145
1146    #[test]
1147    fn command_tree_covers_known_commands() {
1148        let known = crate::cli::dispatch::suggest::KNOWN_COMMANDS;
1149        let tree_names: std::collections::HashSet<&str> = COMMAND_TREE
1150            .iter()
1151            .flat_map(|n| std::iter::once(n.name).chain(n.aliases.iter().copied()))
1152            .collect();
1153
1154        let mut missing = Vec::new();
1155        for cmd in known {
1156            if !tree_names.contains(cmd) {
1157                missing.push(*cmd);
1158            }
1159        }
1160        assert!(
1161            missing.is_empty(),
1162            "KNOWN_COMMANDS entries missing from COMMAND_TREE: {missing:?}"
1163        );
1164    }
1165}