From 34320376767ca9131183216a01cf106ca6405500 Mon Sep 17 00:00:00 2001 From: Claudomator Agent Date: Sat, 14 Mar 2026 17:07:29 +0000 Subject: feat: expose changestats in API responses - Add parseChangestatFromOutput/File helpers in internal/api/changestats.go to parse git diff --stat summary lines from execution stdout logs - Wire parser in processResult: after each execution completes, scan the stdout log for git diff stats and persist via UpdateExecutionChangestats - Tests: TestGetTask_IncludesChangestats (verifies processResult wiring), TestListExecutions_IncludesChangestats (verifies storage round-trip) Co-Authored-By: Claude Sonnet 4.6 --- internal/api/changestats.go | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 internal/api/changestats.go (limited to 'internal/api/changestats.go') diff --git a/internal/api/changestats.go b/internal/api/changestats.go new file mode 100644 index 0000000..0b70105 --- /dev/null +++ b/internal/api/changestats.go @@ -0,0 +1,49 @@ +package api + +import ( + "bufio" + "os" + "regexp" + "strconv" + "strings" + + "github.com/thepeterstone/claudomator/internal/task" +) + +// gitDiffStatRe matches git diff --stat summary lines, e.g.: +// +// "3 files changed, 50 insertions(+), 10 deletions(-)" +// "1 file changed, 5 insertions(+)" +// "1 file changed, 3 deletions(-)" +var gitDiffStatRe = regexp.MustCompile(`(\d+) files? changed(?:, (\d+) insertions?\(\+\))?(?:, (\d+) deletions?\(-\))?`) + +// parseChangestatFromOutput scans text for git diff --stat summary lines and +// returns the first match as a Changestats value. Returns nil if no match found. +func parseChangestatFromOutput(output string) *task.Changestats { + scanner := bufio.NewScanner(strings.NewReader(output)) + for scanner.Scan() { + line := scanner.Text() + if m := gitDiffStatRe.FindStringSubmatch(line); m != nil { + cs := &task.Changestats{} + cs.FilesChanged, _ = strconv.Atoi(m[1]) + if m[2] != "" { + cs.LinesAdded, _ = strconv.Atoi(m[2]) + } + if m[3] != "" { + cs.LinesRemoved, _ = strconv.Atoi(m[3]) + } + return cs + } + } + return nil +} + +// parseChangestatFromFile reads a log file and extracts the first git diff stat +// summary it finds. Returns nil if the file cannot be read or contains no match. +func parseChangestatFromFile(path string) *task.Changestats { + data, err := os.ReadFile(path) + if err != nil { + return nil + } + return parseChangestatFromOutput(string(data)) +} -- cgit v1.2.3