jan/feature/20260818-lib-app-cmd-build-command-tree-lazily into master The discovery re-parse re-parses the full command line at each level against the subparsers registered so far. A level's subcommand parsers are not registered until the re-parse descends into them, so the tokens after the subcommand name are parsed against the current level's options. An option meant for a deeper level can then collide with a same-named option of a shallower level, or fail on a missing value. Replace the re-parse with a single argv walk. The subcommand names at each level are known once the commands are materialized, so the invoked path is found by matching tokens against those names and skipping the options (and the values they consume) that precede them. Walking the tokens never parses the tail against a half-built parser, so the collision cannot occur. Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.84.2 Signed-off-by: Jan Lindemann <jan@janware.com>
App() construction builds the entire command tree: every load_subcommands() call in a command's __init__() constructs its whole subtree eagerly, so running a single leaf command pays to instantiate every unrelated command object as well (jw-pkg builds about 50 command objects for any invocation). Defer the construction instead. load_subcommands() now records only the module search path and name filter, and the subcommands are materialized on first access to the children or child_classes property. The parser reads children only down the invoked branch on the non-help path, so a simple run instantiates just that path (jw-pkg builds 5-7 objects), while the help and completion path expands every node and leaves rendered help unchanged. Assisted-by: unsloth/Qwen3.8-27B-GGUF:Q4_K_M with pi.dev v0.84.2 Signed-off-by: Jan Lindemann <jan@janware.com>