Polish monopam CLI: unified output, distinct exit codes, bug fixes
Kill the ghost `monopam sync` vocabulary across help text, error hints,
the generated CLAUDE.md template, and .mli docs. Commands now speak the
shipped verbs only: pull, push, status.
Unify the user-facing contract for every command:
- Common.print_success emits `✓ message (0.1s)` plus a one-line Next: hint.
- Ctx.err ?hint + Common.fail_ctx route every CLI error through one
formatter so add/init/deps/publish produce the same Error/Hint shape
as pull/push/status.
- Ctx.exit_code maps errors to shell exit codes (2 user, 3 network,
4 push conflict, 5 external service) so scripts can react correctly.
Heuristics match git stderr to separate non-fast-forward from
unreachable-host failures. Unit-tested per category in test_ctx.ml.
- Config.load returns a typed load_error (Not_found | Invalid |
Io_error) so Common.with_config can print a tailored recovery hint
instead of the generic "run monopam init" for every failure.
Align the shipped commands with the README:
- monopam add <name>: Import.resolve_name tries the local opam-repo
overlay first, falls back to `opam show <name> --field dev-repo`.
- monopam init --root: removed the silent jump to git toplevel; uses
CWD unless --root is explicit, and always prints the resolved root.
- monopam diff: accepts multiple package names like pull/push.
- verse cherrypick -> cherry-pick (old name removed).
- Push lists each repo with its actual URL so users see exactly where
each commit landed.
- "upstream" -> "your remotes" / "configured remote" in help text, to
match the README's design principle #1.
Fix two real spec bugs uncovered while writing the Quick Start cram test:
- Import.run committed sources.toml via add_to_index which reads the
stale pre-Subtree.add index, dropping the subtree files from HEAD's
tree. Switched to add_all so the commit reflects the working tree.
Without this fix, every monopam push after monopam add failed with
"Subtree prefix does not exist".
- Git.Subtree.split built a fresh root commit instead of reusing the
original upstream commit when processing a subtree-add merge. First
push after add would then fail with non-fast-forward.
process_split_commit now detects parents whose whole tree equals
the current sub_hash and caches them as their own split
representative, so the chain fast-forwards to upstream.
Remove lib/doctor.ml (1054 LOC, no CLI entry, dead weight). Drop the
dirty-checkout guard from push.ml with a comment explaining why
(checkouts are a derived cache; pull still guards).
Tests:
- monopam/test/quickstart.t: end-to-end init -> add -> edit -> commit
-> push against a local bare upstream that already has one commit.
Asserts the upstream receives both the imported history and the
new edit as a fast-forward with no --force. Also asserts HEAD
contains the subtree after add.
- push.t: adds a regression case for push-over-dirty-checkout and a
Next: hint assertion.
- test_ctx.ml, test_config.ml, test_import.ml: unit coverage for
Ctx.exit_code, Config.pp_load_error, Import.looks_like_url.