Skip to content

Add commit hashes, --touches, and blame; fix empty-message parsing - #2

Merged
AngelCodes95 merged 5 commits into
mainfrom
feat/cli-lookup
Nov 4, 2026
Merged

AngelCodes95 merged 5 commits into
mainfrom
feat/cli-lookup

Conversation

@AngelCodes95

@AngelCodes95 AngelCodes95 commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

Summary

Makes the CLI serve the use case the README leads with: looking up why a specific line exists.

  • Fix: a commit made with --allow-empty-message used to swallow the commit next to it and get reported as MISPLACED (reproduced against real git). The parser now reads a fixed number of NUL-terminated fields per commit instead of splitting on a \0\0 boundary, which empty fields could imitate.
  • Hashes: log, show, check, and parse warnings now carry hash and shortHash (git's own %h). Text output leads with the short hash. --json only gains fields.
  • log --touches <path>: matches whole path segments in both directions (src/auth matches src/auth/x.ts and src, never src/authz).
  • agent-commit blame <file> [-L <start>[,<end>]]: runs git blame and prints each responsible commit's Agent-Context with the line ranges it owns. Uses git's numeric -L syntax. Uncommitted lines are counted on stderr.
  • Tests: consolidated four copies of the record() helper into one fixture.

Stacked on #1; base retargets to main once that merges.

Test plan

  • npm test passes at every commit (126, 126, 128, 129, 138, 154)
  • Real-git integration tests for blame: ranges, whole file, uncommitted lines, out-of-range and missing-path errors, a file named -L
  • npm run sync-docs:check passes
  • agent-commit check --range main..feat/cli-lookup: all OK

Merge with Rebase and merge.

@AngelCodes95
AngelCodes95 changed the base branch from docs/stale-fixes to main November 4, 2026 17:15
check, format, merge-draft, and query tests each defined an identical
record() helper. It now lives in tests/fixtures/record.ts.

Agent-Context: {"why":"Done ahead of adding hash fields to AgentCommitRecord, which would otherwise have meant the same edit in four places, and four places to drift the next time the record shape changes.","touches":["cli/tests/fixtures/record.ts","cli/tests"]}
Records were split on a "\0\0" boundary. A commit made with
--allow-empty-message emits two adjacent empty fields, byte-identical to
that boundary, so log merged it with the next commit and reported the
remains as MISPLACED. The parser now reads a fixed count of
NUL-terminated fields per commit and throws LogFormatError on output
that isn't a whole number of records.

Agent-Context: {"why":"Reproduced against real git first: two commits in, one bogus MISPLACED record out. Considered a different multi-byte boundary, rejected because NUL is the only byte git guarantees never appears in a message, so any boundary built from it can collide with empty fields; counting fields positionally is the only scheme with no collision case. Also unblocks adding a hash field, since a leading field would have collided the same way whenever a commit has no trailer.","touches":["cli/src/parser.ts","cli/tests/parser.test.ts"]}
Records, check results, and parse warnings now carry hash and
shortHash. Text output leads each entry with the short hash, git log
--oneline style; --json carries both.

Agent-Context: {"why":"Without a hash, a log --grep match could be read but not acted on: there was no way to pass it to git show or agent-commit show, and subjects are not unique. shortHash comes from git's %h rather than slicing %H so it honors core.abbrev and stays unambiguous in large repos. Adding JSON fields is additive, so existing --json consumers keep working.","touches":["cli/src/parser.ts","cli/src/types.ts","cli/src/format.ts","cli/src/check.ts","cli/src/index.ts"]}
Matches the touches field on whole path segments, in both directions:
an entry inside the queried path or one containing it both match, a
partial segment never does.

Agent-Context: {"why":"Exact match, like --refs, would miss the common case of asking about a file when the commit listed its directory. Plain string-prefix match was rejected because src/auth would then match src/authz. Matching only entries under the query was rejected too: a commit claiming it touched src is relevant to a question about src/auth/session.ts.","touches":["cli/src/query.ts","cli/src/index.ts"]}
agent-commit blame <file> [-L <start>[,<end>]] runs git blame and
prints the Agent-Context of each commit responsible, with the line
ranges it owns. Extracts runGit from runGitLog so both share the same
error translation.

Agent-Context: {"why":"This is the lookup the README names as the main use case, and until now it took git blame plus a manual git show per hash. Mirrors git's -L syntax instead of file:line because colons are legal in filenames and appear in Windows paths; only the numeric -L forms are accepted so nothing but plain numbers reaches git. Reads the working tree like plain git blame, so uncommitted lines are counted on stderr rather than silently dropped.","touches":["cli/src/blame.ts","cli/src/index.ts","cli/src/parser.ts"]}
@AngelCodes95
AngelCodes95 merged commit 8f17d4c into main Nov 4, 2026
5 checks passed
@AngelCodes95
AngelCodes95 deleted the feat/cli-lookup branch November 4, 2026 17:16
@AngelCodes95 AngelCodes95 mentioned this pull request Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant