WORK-083
ID:WORK-083Status:done

Create Shared Git Timestamp Utility

Priority:highComplexity:moderateMilestone:v1.0.0Source:SPEC-029

Criteria completion

Criteria completion: 10 of 10 (100%) checked; history from Mar 30 to Apr 30%25%50%75%100%Mar 30Apr 3
Branches 3
History 6
  1. e900a90
    Created (done)by bjornolofandersson
  2. f262d7b
    Content editedby Claude
  3. f0a845a
    • ☑ New module in `packages/content/` exports a function (e.g. `getGitTimestamps`) that returns `Map<string, { created: string; modified: string }>` for all files under a given directory
    • ☑ Uses batch `git log` commands (not per-file) for both created and modified timestamps
    • ☑ Modified timestamp derived from `git log --format="%at" --name-only --diff-filter=ACMR HEAD`
    • ☑ Created timestamp derived from `git log --format="%at" --name-only --diff-filter=A --reverse HEAD`
    • ☑ Timestamps normalized to ISO 8601 date strings (`YYYY-MM-DD`)
    • ☑ Falls back to `fs.stat()` (`birthtimeMs` / `mtimeMs`) when git data is unavailable for a file
    • ☑ Detects shallow clones via `git rev-parse --is-shallow-repository` and omits or marks `created` as unreliable
    • ☑ Handles non-git directories gracefully (falls back entirely to fs.stat)
    • ☑ Results cached in memory for the duration of a single `loadContent()` call (no cross-build caching needed)
    • ☑ Unit tests covering: normal git repo, shallow clone detection, non-git fallback, date formatting
    by Claude
  4. f87ae8d
    statusreadydone
    by Claude
  5. 2a05e00
    Content editedby Claude
  6. 43cadfe
    Created (ready)by Claude
    plan: break down SPEC-029 into work items WORK-083 through WORK-087

Summary

Create a shared utility in packages/content/ that batch-collects git timestamps (created and modified) for all files in a content directory. This replaces the per-package approach used by runes/plan/src/scanner.ts:getGitMtimes() with a general-purpose solution available to the entire content pipeline.

Acceptance Criteria

  • New module in packages/content/ exports a function (e.g. getGitTimestamps) that returns Map<string, { created: string; modified: string }> for all files under a given directory
  • Uses batch git log commands (not per-file) for both created and modified timestamps
  • Modified timestamp derived from git log --format="%at" --name-only --diff-filter=ACMR HEAD
  • Created timestamp derived from git log --format="%at" --name-only --diff-filter=A --reverse HEAD
  • Timestamps normalized to ISO 8601 date strings (YYYY-MM-DD)
  • Falls back to fs.stat() (birthtimeMs / mtimeMs) when git data is unavailable for a file
  • Detects shallow clones via git rev-parse --is-shallow-repository and omits or marks created as unreliable
  • Handles non-git directories gracefully (falls back entirely to fs.stat)
  • Results cached in memory for the duration of a single loadContent() call (no cross-build caching needed)
  • Unit tests covering: normal git repo, shallow clone detection, non-git fallback, date formatting

Approach

  1. Create packages/content/src/timestamps.ts with the batch git timestamp collection logic
  2. Reuse the proven pattern from runes/plan/src/scanner.ts:getGitMtimes(), extended to also capture creation times
  3. Parse git log output into a Map<string, { created: number; modified: number }> keyed by relative file path
  4. Add fs.stat fallback for files missing from git history
  5. Export a high-level function that returns formatted ISO date strings

References

  • SPEC-029 (Phase 1 — Git Timestamp Utility)
  • runes/plan/src/scanner.ts — existing getGitMtimes() implementation to draw from