cli
cli — audit issues
Audited 2026-06-20. Repo: software/cli. Criteria: completeness · tests · separation of concerns · verb-named functions · file size (<1000 lines) · organization.
Health summary
A small, clean, well-factored CLI: four subcommands (check, convert, pack, unpack) across 436 lines of source split sensibly into arg-parsing (main.cpp), a format/codec layer (Convert), and bundle I/O (Pack). It builds with no warnings and test.sh passes all 25 smoke assertions. The main defects are documentation/usage-string format-name drift (a --from/--to value the usage advertises is actually rejected), gaps in test coverage for convert argument-parsing and several pack/unpack error paths, and a stale-binary/no-real-help polish layer. Nothing is a stub or unimplemented; severity is concentrated in MEDIUM and LOW.
Issues
[MEDIUM] completeness — usage string advertises an invalid format name (kinogaki)
- Where:
src/main.cpp:44 - Problem: The usage text lists
fmt = prisma | kinogaki | json | markdown | html | svg | text | blob, butformatByName(src/Convert.cpp:76) accepts the binary native format only under the nameprism, neverkinogaki. Soconvert in out --from kinogaki(copied straight from the tool's own help) fails with a bare usage error, while the genuinely-valid nameprismis never advertised. The help is self-contradicting and misleads the user away from the working flag value. - Fix: Change the usage line to
fmt = prisma | prism | json | markdown | html | svg | text | blob, matchingformatByName/formatName. Same fix applies to the README (see organization issue below).
[MEDIUM] tests — convert argument parsing and --from/--to are untested
- Where:
test.sh(whole file); parser atsrc/main.cpp:128-145 - Problem: Every
converttest relies on extension/content inference; the explicit--from <fmt>/--to <fmt>flags andformatByNameare never exercised, nor is any malformed-args path (unknown flag,--fromwith a bad/missing value, too many/too few positionals, bogus subcommand). The format-name bug above survived precisely because no test passes a--fromvalue. There is also no assertion that a forced format overrides inference. - Fix: Add cases:
convert --from json data.txt out.prisma(force input fmt against a misleading extension);--to prismforcing output;--from bogus→ exit 2;convert a b c(extra positional) → exit 2; unknown--flag→ exit 2; bad subcommand → exit 2. These are one-lineexpect "$rc" "2" ...additions.
[MEDIUM] tests — pack/unpack error paths and .prisma-text bundles untested
- Where:
test.sh:76-89; error paths insrc/Pack.cpp:87,95,102,105,106,77 - Problem: Only the happy path (pack a dir →
.prism→ unpack) is covered. Untested:packon a non-directory (Pack.cpp:87→ exit 1),unpackon a non-bundle / unparseable input (Pack.cpp:105-106→ exit 1, verified working by hand but unguarded by tests), packing to/unpacking the editable.prismatext form (Pack.cpp:94chooses text vs compressed binary by suffix — a whole branch with zero coverage), and an empty / dotfile-only directory. A regression in any of these would pass CI. - Fix: Add a
pack site site.prismaround-trip assertion plus negative cases:packa regular file → exit 1;unpackagood.prismanon-bundle → exit 1; pack a dir containing only a dotfile and confirm it is skipped.
[LOW] organization — README is stale: duplicate format name, missing pack/unpack sections, wrong dependency claim
- Where:
README.md:9andREADME.md:1-67 - Problem: Line 9's fmt list reads
fmt = kinogaki | kinogaki | json | ...— "kinogaki" appears twice and neither is a real format name (should beprisma | prism). The README's intro (lines 3-4) says the tool only "validate[s] … and convert[s] between formats" and "links KinogakiCore (no other dependencies)", but the tool also haspack/unpackand depends on KinogakiCodecs too (build.sh:7,CMakeLists.txt:19-24). There is no README section documentingpack/unpackbeyond the one-line synopsis, unlike the dedicatedcheck/convertsections. - Fix: Fix line 9 to
prisma | prism | json | markdown | html | svg | text | blob; update the intro to mention bundling and the KinogakiCodecs dependency; add a## pack / unpacksection mirroring the existing examples.
[LOW] organization — stale renamed binaries left in build/
- Where:
build/prism,build/prisma(alongsidebuild/kinogaki) - Problem:
build/(gitignored, so not committed — good) still holds two binaries from the pre-rename era (prism,prisma) next to the currentkinogaki. They are dead local artifacts that can confuse./build/<tab>completion and PATH usage after the project's rename tokinogaki. - Fix: Have
build.shstart withrm -rf "$OUT"(or clean only its own product) beforemkdir -p "$OUT", so the output dir reflects only the current build. Delete the stale binaries now.
[LOW] completeness — no real --help; usage goes to stderr with exit 2 for any unrecognized command
- Where:
src/main.cpp:39-48,112-146 - Problem: README line 64 documents
kinogaki --help, but there is no help handling:--help(and-h, no args, or any bad subcommand) all fall through tousage(), which prints to stderr and returns 2. A user explicitly asking for help gets help text on the error stream and a failure exit code — conventionally--helpprints to stdout and exits 0. Bad-input → stderr+2 is correct; an explicit help request being treated as an error is not. - Fix: Special-case
--help/-h/helpinmainto print the same text to stdout andreturn 0; keepusage()(stderr, exit 2) for the error path.
[LOW] completeness — readFile/writeFile duplicated across translation units
- Where:
src/main.cpp:27-37andsrc/Pack.cpp:25-35 - Problem: Near-identical
readFile/writeFilehelpers are defined privately in bothmain.cppandPack.cpp(the only divergence iswriteFile's path type:std::stringvsfs::path). Minor duplication; a future fix (e.g. better error reporting on partial writes) must be made in two places. - Fix: Hoist a small
io.h/io.cpp(or extendConvert) with sharedreadFile/writeFile; not urgent given the tiny size.
[LOW] separation — clean
- Argument parsing lives in
main.cpp(subcommand dispatch +convertflag loop,main.cpp:112-146); format/codec policy is isolated behind theConvertlayer (Convert.h/.cpp) with a single codec registry (Convert.cpp:29-45); bundle filesystem I/O is inPack. No business logic leaks intomain; the command bodies (cmdCheck,cmdConvert,cmdPack,cmdUnpack) are thin and each owns one job. Good layering for a tool this size.
[LOW] naming — clean
- All functions read as verbs:
readFile,writeFile,usage,cmdCheck/cmdConvert/cmdPack/cmdUnpack,importToStage,exportFromStage,formatForPath,formatByName,looksNative,looksBinary,packInto,unpackInto,sortedEntries,endsWith,lowerExt.formatName(f)andforeignCodec(f)are noun-named but are conventional getters/lookups, not actions — acceptable. No misleading or ambiguous names found.
[LOW] filesize — clean
- Largest source file is
src/main.cppat 147 lines. All files are well under the 800/1000-line thresholds (Convert.cpp118,Pack.cpp112,Convert.h46,Pack.h13). No file flagged.