1#[derive(Clone, Copy)]
8pub enum DynamicKind {
9 Agents,
10 Shells,
11 Modes,
12 ConfigKeys,
13 Profiles,
14 TerseLevel,
15}
16
17pub 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
26pub 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 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: "daemon",
1052 aliases: &[],
1053 description: "Start daemon (internal)",
1054 subcommands: &[],
1055 flags: &[],
1056 positional: None,
1057 hidden: true,
1058 },
1059];
1060
1061#[cfg(test)]
1062mod tests {
1063 use super::*;
1064
1065 #[test]
1066 fn no_duplicate_names_at_top_level() {
1067 let mut seen = std::collections::HashSet::new();
1068 for node in COMMAND_TREE {
1069 assert!(seen.insert(node.name), "duplicate: {}", node.name);
1070 }
1071 }
1072
1073 #[test]
1074 fn visible_count_exceeds_50() {
1075 let visible = COMMAND_TREE.iter().filter(|n| !n.hidden).count();
1076 assert!(
1077 visible >= 30,
1078 "expected at least 30 visible commands, got {visible}"
1079 );
1080 }
1081
1082 #[test]
1083 fn command_tree_covers_known_commands() {
1084 let known = crate::cli::dispatch::suggest::KNOWN_COMMANDS;
1085 let tree_names: std::collections::HashSet<&str> = COMMAND_TREE
1086 .iter()
1087 .flat_map(|n| std::iter::once(n.name).chain(n.aliases.iter().copied()))
1088 .collect();
1089
1090 let mut missing = Vec::new();
1091 for cmd in known {
1092 if !tree_names.contains(cmd) {
1093 missing.push(*cmd);
1094 }
1095 }
1096 assert!(
1097 missing.is_empty(),
1098 "KNOWN_COMMANDS entries missing from COMMAND_TREE: {missing:?}"
1099 );
1100 }
1101}