command pipeline model
Currently, pop-config implements a model where plugins can "augment" a single active authoritative CLI, and there is only one CLI initialized in a POP project, specified as the cli= option in hub.pop.config.load(). However, there are other patterns that can be very useful when implementing plugins, which might require support for other models.
One of these models is one where there is a "supercommand", which then leverages a "subcommand". Yet the "subcommand" is also a stand-alone command. This can be useful in a number of situations. One is one we have discussed privately a lot, with an ego command that has a profile plugin, and we want to call it as ego profile foo, and the profile plugin simply is a stand-alone command epro that has foo defined as a sub-command, and doesn't even need to be aware that some other command is leveraging it (de-coupling the concerns of epro from those of ego.) So when leveraged directly via ego using this proposed method, epro wouldn't need to explicitly "augment" ego -- instead it can just be invoked directly by ego's code and passed all remaining arguments not parsed by the parent command.
Using this approach, you can "glom" together multiple commands in a pipeline, or incorporate a stand-alone POP command into a parent command. There are other scenarios where this pipeline approach can be useful as well.
To implement this, I propose the ability for multiple CLIs to be initialized, in a pipeline (currently, only one is initialized.) cli= would specify a list of pipelines to initialize.
When used in this fashion, cli= could be given a list, not just a string, in the following format:
cli=[first_cli, second_cli]
or
cli=[(first_cli, adapter_func), (second_cli, adapter_func)]
This functionality would leverage the remaining_args functionality (see https://stackoverflow.com/a/49351471). When a list-pipeline like above is specified, each CLI except the last would have remaining_args enabled, and any remaining arguments would be captured for passing to the next stage in the pipeline. An optional tuple can be used containing an adapter_func which could be used to adapt the remaining arguments arbitrarily before they are passed to the next stage of the pipeline.
There are potential problems with this approach. It may not be possible to support easily since POP auto-discovers plugin subsystems, not POP projects. And yet CLI is associated with a POP project. So this demands more functionality from POP that may not fit easily into the current POP dyne wire-up code.
Potentially, this solution could work as long you kept all POP projects in a single software project. But this violates the goals of allowing these projects to exist as separate entities which is a key design feature of POP so this wouldn't be hugely beneficial.
To work around these problems, we could (brainstorming) allow a CLI be attached directly to a sub, or as its own distinct discoverable entity (thus making discoverable entities themselves pluggable?,) in which case it could be discovered via a dyne name, and leveraged from another software project dynamically.
More thought needs to be given to this idea. For now I'm just recording the idea here so we have an official record of the concept.