Refactor, test everything, DRY
This MR moves all CLI functionality into testable library code, leaving each binary file with a single line of code.
It refactors out a bunch of utilities that were repeated and unstandardised before, and tests them.
Finally, it adds basic tests for the CLI tools. These can be expanded on later, but combined with the good test coverage of src
, should provide much higher confidence than we've had before that passing tests will result in a working CLI suite.