fix: make plans root-consistent from any subdirectory and fail concisely outside a repo - #28
Conversation
Running the CLI from a repository subdirectory drops root-level untracked files and reports cwd-relative paths, so the plan disagrees with the same repository scanned from its root. This test pins the root-relative equality that the fix must restore.
collectGitDiff ran every git command in the invocation directory, so git diff enumerated root-relative repo-wide paths while git ls-files --others only saw the cwd subtree with cwd-relative paths, and untracked stats then resolved against the wrong file. Resolve the top level once via git rev-parse --show-toplevel and run diff, ls-files, and per-file stat commands from that single root so any subdirectory produces the same root-relative plan as the root.
Outside a git repository the CLI currently dumps git diff usage text plus a Node stack trace; pin the intended contract instead: exit 1, stdout empty, and exactly one 'atomcommit: not a git repository' stderr line.
collectGitDiff now returns null when git rev-parse --show-toplevel fails, and main() prints a single 'atomcommit: not a git repository' stderr line with exit code 1 instead of letting the raw git usage dump and Node stack trace escape through an uncaught error. --help/--version and argument validation are unchanged and still work outside a repository.
README 'What it reads' omitted -z markers and the staged numstat/stat queries and did not mention the new rev-parse root resolution; the help safety note named only diff and ls-files. Update both to match exactly what the CLI runs, including subdirectory equivalence and the concise non-repository error.
…checks The fixture plan generated from docs/ must be byte-identical to the root-generated plan, and a plan run outside any repository must exit 1 with exactly the single-line stderr, mirroring the unit regressions at the packaged-CLI level.
…error in the changelog
Automated merge noteTriage class: auto-merge Summary: Root-consistent Checks run: GitHub check "Repository hygiene" — SUCCESS (completed). Independent local verification at head SHA in an isolated worktree: Rebased / CI-repaired: No — branch clean and mergeable; BLOCKED state was review-required only (no branch protection rules on main). Verified head SHA: |
Summary
planpreviously produced different, wrong results depending on the invocation directory:git diffenumerated repo-wide root-relative paths whilegit ls-files --otherswas cwd-scoped with cwd-relative paths, so root-level untracked files were dropped and subdirectory files got wrong paths/stats (untrackedStatthen diffed the wrong file).collectGitDiffnow resolves the repository root once viagit rev-parse --show-topleveland runs every read-only git command from that root, so any subdirectory yields the identical root-relative plan (88aedc4 test, 955a337 fix).git diffusage text plus an uncaught Node stack trace:collectGitDiffreturnsnull,mainprints one stderr lineatomcommit: not a git repository, exit 1, stdout empty (50775bc test, 1c7b73a fix).rev-parse --show-toplevel,-zmarkers, and the staged--cached --numstat/--statqueries that were never listed), help safety note and CHANGELOG updated, and scripts/smoke.sh extended to assert root-vs-subdirectory plan equality and the concise non-repository error end-to-end.Commits: 7 — test(red)→fix(green) pairs for each defect, then docs/help alignment, smoke extension, changelog.
Files:
src/index.js,test/cli.test.js,README.md,CHANGELOG.md,scripts/smoke.sh.Verification
npm test23/23 pass (incl. 2 new regression tests),npm run checkpass,npm run smokepass ("subdirectory-stable, and non-repository error concise"),bash scripts/validate.shexit 0,npm run release:checkexit 0,git diff --checkclean.--versionstill works outside a repo,--bogusunchanged).Roger Chappel <miscanalysis@gmail.com>viagit log --format='%h%x09%an%x09%ae%x09%cn%x09%ce' origin/main..HEADbefore push.Risk Level
Notes: read-only planning path only; no staging/mutation, no dependency/workflow/API changes.
collectGitDiff(exported) now returnsnulloutside a repository instead of throwing a wrapped git-usage error — documented in code comment; no in-repo callers besidesmain.Rollback Plan
Human Decision Needed