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: &[FlagSpec {
287 long: "--json",
288 short: None,
289 description: "JSON output",
290 takes_value: false,
291 value_kind: None,
292 }],
293 positional: None,
294 hidden: false,
295 },
296 CommandNode {
297 name: "spend",
298 aliases: &["billing", "finops", "roi"],
299 description: "Show cost report",
300 subcommands: &[],
301 flags: &[FlagSpec {
302 long: "--json",
303 short: None,
304 description: "JSON output",
305 takes_value: false,
306 value_kind: None,
307 }],
308 positional: None,
309 hidden: false,
310 },
311 CommandNode {
312 name: "index",
313 aliases: &[],
314 description: "Build or rebuild search index",
315 subcommands: &[],
316 flags: &[FlagSpec {
317 long: "--force",
318 short: Some('f'),
319 description: "Force rebuild",
320 takes_value: false,
321 value_kind: None,
322 }],
323 positional: None,
324 hidden: false,
325 },
326 CommandNode {
327 name: "explore",
328 aliases: &["repomap", "repo-map"],
329 description: "Explore repository structure",
330 subcommands: &[],
331 flags: &[
332 FlagSpec {
333 long: "--depth",
334 short: Some('d'),
335 description: "Max depth",
336 takes_value: true,
337 value_kind: None,
338 },
339 FlagSpec {
340 long: "--json",
341 short: None,
342 description: "JSON output",
343 takes_value: false,
344 value_kind: None,
345 },
346 ],
347 positional: None,
348 hidden: false,
349 },
350 CommandNode {
351 name: "compress",
352 aliases: &["compact"],
353 description: "Compress input",
354 subcommands: &[],
355 flags: &[],
356 positional: None,
357 hidden: false,
358 },
359 CommandNode {
360 name: "update",
361 aliases: &["upgrade"],
362 description: "Update lean-ctx",
363 subcommands: &[],
364 flags: &[FlagSpec {
365 long: "--check",
366 short: None,
367 description: "Check only, don't install",
368 takes_value: false,
369 value_kind: None,
370 }],
371 positional: None,
372 hidden: false,
373 },
374 CommandNode {
375 name: "stop",
376 aliases: &[],
377 description: "Stop all lean-ctx processes",
378 subcommands: &[],
379 flags: &[],
380 positional: None,
381 hidden: false,
382 },
383 CommandNode {
384 name: "restart",
385 aliases: &[],
386 description: "Restart lean-ctx",
387 subcommands: &[],
388 flags: &[],
389 positional: None,
390 hidden: false,
391 },
392 CommandNode {
393 name: "dev-install",
394 aliases: &[],
395 description: "Development install (stop+build+install+restart)",
396 subcommands: &[],
397 flags: &[],
398 positional: None,
399 hidden: false,
400 },
401 CommandNode {
402 name: "wrap",
403 aliases: &[],
404 description: "One-command setup for an agent",
405 subcommands: &[],
406 flags: &[],
407 positional: Some(DynamicKind::Agents),
408 hidden: false,
409 },
410 CommandNode {
411 name: "unwrap",
412 aliases: &[],
413 description: "Undo wrap, restore pre-wrap config",
414 subcommands: &[],
415 flags: &[],
416 positional: Some(DynamicKind::Agents),
417 hidden: false,
418 },
419 CommandNode {
420 name: "doctor",
421 aliases: &[],
422 description: "Diagnose installation issues",
423 subcommands: &[],
424 flags: &[],
425 positional: None,
426 hidden: false,
427 },
428 CommandNode {
429 name: "selftest",
430 aliases: &["health"],
431 description: "Run self-test",
432 subcommands: &[],
433 flags: &[],
434 positional: None,
435 hidden: false,
436 },
437 CommandNode {
438 name: "rules",
439 aliases: &[],
440 description: "Manage rules",
441 subcommands: &[],
442 flags: &[],
443 positional: None,
444 hidden: false,
445 },
446 CommandNode {
447 name: "export-rules",
448 aliases: &[],
449 description: "Export rules to file",
450 subcommands: &[],
451 flags: &[],
452 positional: None,
453 hidden: false,
454 },
455 CommandNode {
456 name: "harden",
457 aliases: &["security", "lockdown"],
458 description: "Harden security settings",
459 subcommands: &[],
460 flags: &[],
461 positional: None,
462 hidden: false,
463 },
464 CommandNode {
465 name: "completions",
466 aliases: &[],
467 description: "Generate shell completion script",
468 subcommands: &[],
469 flags: &[],
470 positional: Some(DynamicKind::Shells),
471 hidden: false,
472 },
473 CommandNode {
474 name: "gotchas",
475 aliases: &["bugs"],
476 description: "Show known gotchas",
477 subcommands: &[],
478 flags: &[],
479 positional: None,
480 hidden: false,
481 },
482 CommandNode {
483 name: "learn",
484 aliases: &[],
485 description: "Interactive learning",
486 subcommands: &[],
487 flags: &[],
488 positional: None,
489 hidden: false,
490 },
491 CommandNode {
492 name: "cloud",
493 aliases: &[],
494 description: "Cloud features",
495 subcommands: &[],
496 flags: &[],
497 positional: None,
498 hidden: false,
499 },
500 CommandNode {
501 name: "help",
502 aliases: &[],
503 description: "Show help",
504 subcommands: &[],
505 flags: &[],
506 positional: None,
507 hidden: false,
508 },
509 CommandNode {
510 name: "eval",
511 aliases: &[],
512 description: "Evaluate compression quality",
513 subcommands: &[],
514 flags: &[],
515 positional: None,
516 hidden: false,
517 },
518 CommandNode {
519 name: "audit",
520 aliases: &["compliance"],
521 description: "Run compliance audit",
522 subcommands: &[],
523 flags: &[],
524 positional: None,
525 hidden: false,
526 },
527 CommandNode {
528 name: "agent",
529 aliases: &[],
530 description: "Manage agent integrations",
531 subcommands: &[],
532 flags: &[FlagSpec {
533 long: "--agent",
534 short: Some('a'),
535 description: "Agent name",
536 takes_value: true,
537 value_kind: Some(DynamicKind::Agents),
538 }],
539 positional: None,
540 hidden: false,
541 },
542 CommandNode {
543 name: "session",
544 aliases: &["sessions"],
545 description: "Manage sessions",
546 subcommands: &[],
547 flags: &[],
548 positional: None,
549 hidden: false,
550 },
551 CommandNode {
552 name: "knowledge",
553 aliases: &[],
554 description: "Manage knowledge base",
555 subcommands: &[],
556 flags: &[],
557 positional: None,
558 hidden: false,
559 },
560 CommandNode {
561 name: "stats",
562 aliases: &["introspect"],
563 description: "Show statistics",
564 subcommands: &[],
565 flags: &[FlagSpec {
566 long: "--json",
567 short: None,
568 description: "JSON output",
569 takes_value: false,
570 value_kind: None,
571 }],
572 positional: None,
573 hidden: false,
574 },
575 CommandNode {
576 name: "cheatsheet",
577 aliases: &[],
578 description: "Show cheatsheet",
579 subcommands: &[],
580 flags: &[],
581 positional: None,
582 hidden: false,
583 },
584 CommandNode {
585 name: "mcp",
586 aliases: &[],
587 description: "MCP server management",
588 subcommands: &[],
589 flags: &[],
590 positional: None,
591 hidden: false,
592 },
593 CommandNode {
594 name: "wrapped",
595 aliases: &[],
596 description: "Show wrapped summary",
597 subcommands: &[],
598 flags: &[],
599 positional: None,
600 hidden: false,
601 },
602 CommandNode {
603 name: "addon",
604 aliases: &["addons", "plugin", "plugins"],
605 description: "Manage addons",
606 subcommands: &[
607 CommandNode {
608 name: "list",
609 aliases: &[],
610 description: "List addons",
611 subcommands: &[],
612 flags: &[],
613 positional: None,
614 hidden: false,
615 },
616 CommandNode {
617 name: "install",
618 aliases: &[],
619 description: "Install addon",
620 subcommands: &[],
621 flags: &[],
622 positional: None,
623 hidden: false,
624 },
625 CommandNode {
626 name: "remove",
627 aliases: &[],
628 description: "Remove addon",
629 subcommands: &[],
630 flags: &[],
631 positional: None,
632 hidden: false,
633 },
634 CommandNode {
635 name: "info",
636 aliases: &[],
637 description: "Addon info",
638 subcommands: &[],
639 flags: &[],
640 positional: None,
641 hidden: false,
642 },
643 ],
644 flags: &[],
645 positional: None,
646 hidden: false,
647 },
648 CommandNode {
649 name: "verify",
650 aliases: &["proof"],
651 description: "Verify cache integrity",
652 subcommands: &[],
653 flags: &[],
654 positional: None,
655 hidden: false,
656 },
657 CommandNode {
658 name: "verify-cache",
659 aliases: &["cache-selftest"],
660 description: "Verify cache consistency",
661 subcommands: &[],
662 flags: &[],
663 positional: None,
664 hidden: false,
665 },
666 CommandNode {
667 name: "visualize",
668 aliases: &[],
669 description: "Visualize context graph",
670 subcommands: &[],
671 flags: &[],
672 positional: None,
673 hidden: false,
674 },
675 CommandNode {
676 name: "instructions",
677 aliases: &[],
678 description: "Show agent instructions",
679 subcommands: &[],
680 flags: &[],
681 positional: None,
682 hidden: false,
683 },
684 CommandNode {
685 name: "semantic-search",
686 aliases: &["search-code"],
687 description: "Semantic code search",
688 subcommands: &[],
689 flags: &[],
690 positional: None,
691 hidden: false,
692 },
693 CommandNode {
694 name: "read",
695 aliases: &[],
696 description: "Read and compress a file",
697 subcommands: &[],
698 flags: &[],
699 positional: None,
700 hidden: false,
701 },
702 CommandNode {
703 name: "call",
704 aliases: &[],
705 description: "Call an MCP tool",
706 subcommands: &[],
707 flags: &[],
708 positional: None,
709 hidden: false,
710 },
711 CommandNode {
712 name: "diff",
713 aliases: &[],
714 description: "Compressed diff",
715 subcommands: &[],
716 flags: &[],
717 positional: None,
718 hidden: false,
719 },
720 CommandNode {
721 name: "grep",
722 aliases: &["find"],
723 description: "Search with compression",
724 subcommands: &[],
725 flags: &[],
726 positional: None,
727 hidden: false,
728 },
729 CommandNode {
730 name: "glob",
731 aliases: &[],
732 description: "Glob file search",
733 subcommands: &[],
734 flags: &[],
735 positional: None,
736 hidden: false,
737 },
738 CommandNode {
739 name: "ls",
740 aliases: &[],
741 description: "List directory contents",
742 subcommands: &[],
743 flags: &[],
744 positional: None,
745 hidden: false,
746 },
747 CommandNode {
748 name: "deps",
749 aliases: &[],
750 description: "Show dependencies",
751 subcommands: &[],
752 flags: &[],
753 positional: None,
754 hidden: false,
755 },
756 CommandNode {
757 name: "discover",
758 aliases: &[],
759 description: "Discover project structure",
760 subcommands: &[],
761 flags: &[],
762 positional: None,
763 hidden: false,
764 },
765 CommandNode {
766 name: "ghost",
767 aliases: &[],
768 description: "Ghost context injection",
769 subcommands: &[],
770 flags: &[],
771 positional: None,
772 hidden: false,
773 },
774 CommandNode {
775 name: "filter",
776 aliases: &[],
777 description: "Filter context",
778 subcommands: &[],
779 flags: &[],
780 positional: None,
781 hidden: false,
782 },
783 CommandNode {
784 name: "heatmap",
785 aliases: &[],
786 description: "Show file heatmap",
787 subcommands: &[],
788 flags: &[],
789 positional: None,
790 hidden: false,
791 },
792 CommandNode {
793 name: "graph",
794 aliases: &[],
795 description: "Show dependency graph",
796 subcommands: &[],
797 flags: &[],
798 positional: None,
799 hidden: false,
800 },
801 CommandNode {
802 name: "smells",
803 aliases: &[],
804 description: "Detect code smells",
805 subcommands: &[],
806 flags: &[],
807 positional: None,
808 hidden: false,
809 },
810 CommandNode {
811 name: "ledger",
812 aliases: &[],
813 description: "Token usage ledger",
814 subcommands: &[],
815 flags: &[],
816 positional: None,
817 hidden: false,
818 },
819 CommandNode {
820 name: "control",
821 aliases: &[],
822 description: "Runtime control",
823 subcommands: &[],
824 flags: &[],
825 positional: None,
826 hidden: false,
827 },
828 CommandNode {
829 name: "plan",
830 aliases: &[],
831 description: "Plan context strategy",
832 subcommands: &[],
833 flags: &[],
834 positional: None,
835 hidden: false,
836 },
837 CommandNode {
838 name: "compile",
839 aliases: &[],
840 description: "Compile context",
841 subcommands: &[],
842 flags: &[],
843 positional: None,
844 hidden: false,
845 },
846 CommandNode {
847 name: "skillify",
848 aliases: &[],
849 description: "Generate skill from code",
850 subcommands: &[],
851 flags: &[],
852 positional: None,
853 hidden: false,
854 },
855 CommandNode {
856 name: "summary",
857 aliases: &["overview"],
858 description: "Show project summary",
859 subcommands: &[],
860 flags: &[],
861 positional: None,
862 hidden: false,
863 },
864 CommandNode {
865 name: "benchmark",
866 aliases: &[],
867 description: "Run compression benchmarks",
868 subcommands: &[],
869 flags: &[],
870 positional: None,
871 hidden: false,
872 },
873 CommandNode {
874 name: "tools",
875 aliases: &[],
876 description: "List available MCP tools",
877 subcommands: &[],
878 flags: &[],
879 positional: None,
880 hidden: false,
881 },
882 CommandNode {
883 name: "allow",
884 aliases: &["trust"],
885 description: "Allow a command/path",
886 subcommands: &[],
887 flags: &[],
888 positional: None,
889 hidden: false,
890 },
891 CommandNode {
892 name: "untrust",
893 aliases: &[],
894 description: "Untrust a command/path",
895 subcommands: &[],
896 flags: &[],
897 positional: None,
898 hidden: false,
899 },
900 CommandNode {
901 name: "theme",
902 aliases: &[],
903 description: "Set dashboard theme",
904 subcommands: &[],
905 flags: &[],
906 positional: None,
907 hidden: false,
908 },
909 CommandNode {
910 name: "tee",
911 aliases: &[],
912 description: "Tee output to file",
913 subcommands: &[],
914 flags: &[],
915 positional: None,
916 hidden: false,
917 },
918 CommandNode {
919 name: "codesign-setup",
920 aliases: &[],
921 description: "Setup code signing",
922 subcommands: &[],
923 flags: &[],
924 positional: None,
925 hidden: false,
926 },
927 CommandNode {
928 name: "buddy",
929 aliases: &[],
930 description: "AI buddy assistant",
931 subcommands: &[],
932 flags: &[],
933 positional: None,
934 hidden: false,
935 },
936 CommandNode {
937 name: "learning",
938 aliases: &["conformance"],
939 description: "Show learning progress",
940 subcommands: &[],
941 flags: &[],
942 positional: None,
943 hidden: false,
944 },
945 CommandNode {
946 name: "token-report",
947 aliases: &["report-tokens"],
948 description: "Token usage report",
949 subcommands: &[],
950 flags: &[],
951 positional: None,
952 hidden: false,
953 },
954 CommandNode {
955 name: "pack",
956 aliases: &[],
957 description: "Pack context for export",
958 subcommands: &[],
959 flags: &[],
960 positional: None,
961 hidden: false,
962 },
963 CommandNode {
964 name: "policy",
965 aliases: &[],
966 description: "Manage security policies",
967 subcommands: &[],
968 flags: &[],
969 positional: None,
970 hidden: false,
971 },
972 CommandNode {
973 name: "cep",
974 aliases: &[],
975 description: "Context engineering pipeline",
976 subcommands: &[],
977 flags: &[],
978 positional: None,
979 hidden: false,
980 },
981 CommandNode {
982 name: "team",
983 aliases: &[],
984 description: "Team management",
985 subcommands: &[],
986 flags: &[],
987 positional: None,
988 hidden: false,
989 },
990 CommandNode {
991 name: "provider",
992 aliases: &[],
993 description: "Manage LLM providers",
994 subcommands: &[],
995 flags: &[],
996 positional: None,
997 hidden: false,
998 },
999 CommandNode {
1000 name: "watch",
1001 aliases: &[],
1002 description: "Watch for file changes",
1003 subcommands: &[],
1004 flags: &[],
1005 positional: None,
1006 hidden: false,
1007 },
1008 CommandNode {
1009 name: "yolo",
1010 aliases: &["secure"],
1011 description: "Toggle security mode",
1012 subcommands: &[],
1013 flags: &[],
1014 positional: None,
1015 hidden: false,
1016 },
1017 CommandNode {
1019 name: "__complete",
1020 aliases: &[],
1021 description: "Dynamic completion (internal)",
1022 subcommands: &[],
1023 flags: &[],
1024 positional: None,
1025 hidden: true,
1026 },
1027 CommandNode {
1028 name: "daemon",
1029 aliases: &[],
1030 description: "Start daemon (internal)",
1031 subcommands: &[],
1032 flags: &[],
1033 positional: None,
1034 hidden: true,
1035 },
1036];
1037
1038#[cfg(test)]
1039mod tests {
1040 use super::*;
1041
1042 #[test]
1043 fn no_duplicate_names_at_top_level() {
1044 let mut seen = std::collections::HashSet::new();
1045 for node in COMMAND_TREE {
1046 assert!(seen.insert(node.name), "duplicate: {}", node.name);
1047 }
1048 }
1049
1050 #[test]
1051 fn visible_count_exceeds_50() {
1052 let visible = COMMAND_TREE.iter().filter(|n| !n.hidden).count();
1053 assert!(
1054 visible >= 30,
1055 "expected at least 30 visible commands, got {visible}"
1056 );
1057 }
1058
1059 #[test]
1060 fn command_tree_covers_known_commands() {
1061 let known = crate::cli::dispatch::suggest::KNOWN_COMMANDS;
1062 let tree_names: std::collections::HashSet<&str> = COMMAND_TREE
1063 .iter()
1064 .flat_map(|n| std::iter::once(n.name).chain(n.aliases.iter().copied()))
1065 .collect();
1066
1067 let mut missing = Vec::new();
1068 for cmd in known {
1069 if !tree_names.contains(cmd) {
1070 missing.push(*cmd);
1071 }
1072 }
1073 assert!(
1074 missing.is_empty(),
1075 "KNOWN_COMMANDS entries missing from COMMAND_TREE: {missing:?}"
1076 );
1077 }
1078}