Changelog – Version 4.2.0 This release adds a hierarchical command tree, improves default usage formatting, and lays the groundwork for more flexible subcommand management. It remains backward-compatible with 4.1.x.
Major Changes Prefix-Tree Command Registry
Replaced the flat Map<String, Command> with a new CommandTree<T, S> data structure.
Commands and subcommands are now stored in a trie, keyed by dot-separated paths (e.g. "base.sub.subsub").
Lookup via findNode(base, rawArgs) returns the most specific matching node plus any leftover arguments.
Removal via removeCommand(label, prune) can either clear a single node or prune an entire subtree.
Introduced CommandNode<T, S> to represent each segment in the tree, with optional command payload and child-tracking (hadChildren) flags.
Refactored Default Usage Generation
Overhauled generateDefaultUsage(...) to show only one level of subcommands, then required and optional arguments.
Usage now prints:
Full command path (/parent child …)
First-level subcommand choices (<sub1|sub2>)
Required args (<arg>…) and optional args ([opt]…)
Backward-compatible: existing explicit setUsage(...) overrides still apply.
✨ New Features Improved Lookup & Autocomplete
Subcommands are no longer flat—autocomplete and invocation automatically traverse the tree.
Arguments fallback correctly when a node has no children but still accepts parameters.
Expanded Test Coverage
Added unit tests for CommandTree and CommandNode covering:
Adding and finding nested commands
Matching with extra args and partial paths
Removing nodes with both prune and “clear only” semantics
Updated existing CommandInvoker tests to work against the new tree-based lookup.
Bug Fixes & Tweaks
Fixed edge cases in removeCommand:
Pruning a branch now properly removes children and resets parent flags.
Clearing a command on a leaf node without children now unregisters that node.
Cleaned up legacy methods that referenced the old flat map.
General Improvements
Simplified the addCommand(label, command) API to accept full paths directly.
Streamlined tree traversal code with clearer branch and command-presence checks.
Minor logging enhancements when adding or removing commands from the tree.
Review any custom invocation code: switch from manager.getCommands().get(label) to manager.getCommands().findNode(base, rawArgs) in CommandInvoker.
Adjust tests or tooling that assumed a flat map of labels. All lookups now go through CommandTree.
Verify your usage messages: autogenerated usage strings now show only one subcommand level; if you relied on deeper nesting, update your custom setUsage(...) or test expectations.