89 lines
2.7 KiB
Python
89 lines
2.7 KiB
Python
# aider-watch-client parsers | 2026-04-20 @ Asia/Taipei
|
|
"""從 aider stdout / chat_history.md / git diff 抽事件資訊。"""
|
|
from __future__ import annotations
|
|
import re
|
|
import subprocess
|
|
from pathlib import Path
|
|
|
|
_BANNER_MODEL = re.compile(r"^\s*Model:\s*(\S+)", re.MULTILINE)
|
|
_BANNER_VER = re.compile(r"^\s*Aider v([\d\.]+)", re.MULTILINE)
|
|
_TOKENS_LINE = re.compile(
|
|
r"Tokens:\s+([\d\.]+)([km]?)\s+sent,\s+([\d\.]+)([km]?)\s+received",
|
|
re.IGNORECASE,
|
|
)
|
|
|
|
|
|
def _parse_num(n: str, suffix: str) -> int:
|
|
v = float(n)
|
|
if suffix.lower() == "k":
|
|
v *= 1000
|
|
elif suffix.lower() == "m":
|
|
v *= 1_000_000
|
|
return int(v)
|
|
|
|
|
|
def parse_stdout_banner(stdout: str) -> dict:
|
|
m_model = _BANNER_MODEL.search(stdout)
|
|
m_ver = _BANNER_VER.search(stdout)
|
|
return {
|
|
"model": m_model.group(1) if m_model else None,
|
|
"cli_version": m_ver.group(1) if m_ver else None,
|
|
}
|
|
|
|
|
|
def parse_chat_history(md: str) -> dict:
|
|
total_sent = 0
|
|
total_recv = 0
|
|
for m in _TOKENS_LINE.finditer(md):
|
|
total_sent += _parse_num(m.group(1), m.group(2))
|
|
total_recv += _parse_num(m.group(3), m.group(4))
|
|
return {"tokens_sent": total_sent, "tokens_received": total_recv,
|
|
"file_edits": []}
|
|
|
|
|
|
def parse_git_diff_stat(diff_stat: str) -> list[dict]:
|
|
out = []
|
|
for line in diff_stat.strip().splitlines():
|
|
parts = line.split("\t")
|
|
if len(parts) != 3:
|
|
continue
|
|
add, dele, path = parts
|
|
try:
|
|
a = int(add) if add != "-" else 0
|
|
d = int(dele) if dele != "-" else 0
|
|
except ValueError:
|
|
continue
|
|
out.append({"path": path, "lines_added": a, "lines_deleted": d,
|
|
"is_new_file": d == 0 and a > 0})
|
|
return out
|
|
|
|
|
|
def git_numstat(cwd: Path, pre_sha: str, post_sha: str = "HEAD") -> list[dict]:
|
|
try:
|
|
r = subprocess.run(
|
|
["git", "-C", str(cwd), "diff", "--numstat", pre_sha, post_sha],
|
|
capture_output=True, text=True, timeout=10)
|
|
if r.returncode != 0:
|
|
return []
|
|
return parse_git_diff_stat(r.stdout)
|
|
except Exception:
|
|
return []
|
|
|
|
|
|
def git_diff_head(cwd: Path, path: str, pre_sha: str, n: int = 3) -> list[str]:
|
|
try:
|
|
r = subprocess.run(
|
|
["git", "-C", str(cwd), "diff", "-U0", pre_sha, "--", path],
|
|
capture_output=True, text=True, timeout=5)
|
|
picks = []
|
|
for l in r.stdout.splitlines():
|
|
if l.startswith("+++") or l.startswith("---"):
|
|
continue
|
|
if l.startswith("@@") or l.startswith("+") or l.startswith("-"):
|
|
picks.append(l)
|
|
if len(picks) >= n:
|
|
break
|
|
return picks
|
|
except Exception:
|
|
return []
|