monopam: cram tests for init/status/pull/diff/remove/clean, fix pull worktree
Add happy-path cram coverage for six commands that previously only had
negative tests (or none at all). Each test lives in a <cmd>.t/run.t
directory so future tests can drop fixture files alongside run.t.
The new tests uncovered two real pull bugs:
- Pull updated HEAD and the git object database but never touched the
working tree. After `monopam pull`, `git log` showed the subtree
merge commit but the user's files on disk were still the pre-pull
content. `subtree_merge_or_add` now calls `Git.Repository.checkout_
prefix` after the merge.
- Pull reported "All N repositories up to date" after actually pulling
commits. `clone_repos` measured `behind_before` against the stale
`origin/<branch>` tracking ref — that ref only gets updated by a
fetch, so on the first pull after a push-only setup it was always
equal to HEAD. Replaced with a before/after HEAD snapshot around
`ensure_checkout` and `count_commits_between` for the real count.
Also: `monopam init` now writes CLAUDE.md and .gitignore directly via
a new `Init.bootstrap_files`. Before this, CLAUDE.md only appeared
after the first `monopam pull`, leaving fresh `init` workspaces with
no guidance. init.t has a regression assertion that the generated
CLAUDE.md contains `monopam pull` / `monopam push` and zero
`monopam sync` references.
Tests:
- init.t: fresh workspace, CLAUDE.md generated and idempotent.
- status.t: synced workspace summary + actionable row on local edit.
- pull.t: simulate collaborator commit on upstream, pull merges into
monorepo worktree, reports the real commit count, shows subtree
merge in git log.
- diff.t: outgoing after push --local, incoming after fetch.
- remove.t: --dry-run preview, real removal, sources.toml updated.
- clean.t: smoke test on a clean workspace.