Files
zed_time_tracker/log_commit.py
T
fegger bfff093dc6 Add Zed Hours Tracker tooling
Introduces a local-first time tracker for Zed editor sessions, including
background activity tracking, automatic git commit logging, and markdown
report generation. Includes install script, systemd service template,
and setup instructions in README.
2026-09-11 10:27:56 +02:00

102 lines
2.9 KiB
Python

#!/usr/bin/env python3
"""Log a git commit event to .zed-hours/commits.jsonl.
This script is normally called by the git post-commit hook.
It can also be run manually for testing.
"""
import json
import os
import subprocess
from datetime import datetime, timezone
from pathlib import Path
def get_project_root() -> Path:
try:
root = subprocess.check_output(
["git", "rev-parse", "--show-toplevel"],
cwd=os.environ.get("GIT_DIR", "."),
text=True,
stderr=subprocess.DEVNULL,
).strip()
return Path(root).resolve()
except (subprocess.CalledProcessError, FileNotFoundError):
pass
# Fallback 1: script location (<project>/tools/time_tracking/)
script_project = Path(__file__).resolve().parents[2]
if (script_project / ".git").exists() or (script_project / ".zed-hours").exists():
return script_project
# Fallback 2: current directory
return Path.cwd().resolve()
def get_last_commit_info(project_root: Path) -> dict:
try:
log_format = "%H|%an|%ae|%s|%D"
out = subprocess.check_output(
["git", "log", "-1", f"--format={log_format}"],
cwd=project_root,
text=True,
stderr=subprocess.DEVNULL,
).strip()
sha, author, email, subject, refs = out.split("|", 4)
# Try to extract current branch
branch = "unknown"
try:
branch = subprocess.check_output(
["git", "rev-parse", "--abbrev-ref", "HEAD"],
cwd=project_root,
text=True,
stderr=subprocess.DEVNULL,
).strip()
except subprocess.CalledProcessError:
pass
return {
"sha": sha,
"author": author,
"email": email,
"subject": subject,
"branch": branch,
}
except subprocess.CalledProcessError as e:
return {
"sha": "unknown",
"author": "unknown",
"email": "unknown",
"subject": f"error: {e}",
"branch": "unknown",
}
def log_commit(project_root: Path | None = None) -> Path | None:
if project_root is None:
project_root = get_project_root()
log_dir = project_root / ".zed-hours"
log_dir.mkdir(parents=True, exist_ok=True)
commit_info = get_last_commit_info(project_root)
record = {
"type": "commit",
"timestamp": datetime.now(timezone.utc).astimezone().isoformat(timespec="seconds"),
"repo": str(project_root),
**commit_info,
}
log_file = log_dir / "commits.jsonl"
with log_file.open("a", encoding="utf-8") as f:
f.write(json.dumps(record, ensure_ascii=False) + "\n")
return log_file
def main() -> None:
log_file = log_commit()
if log_file:
print(f"Logged commit to {log_file}")
if __name__ == "__main__":
main()