From 7e8967decbc8221694953abf1435fda8aaf18824 Mon Sep 17 00:00:00 2001 From: Peter Stone Date: Thu, 19 Mar 2026 23:03:56 +0000 Subject: feat: agent status dashboard with availability timeline and Gemini quota detection - Detect Gemini TerminalQuotaError (daily quota) as BUDGET_EXCEEDED, not generic FAILED - Surface container stderr tail in error so quota/rate-limit classifiers can match it - Add agent_events table to persist rate-limit start/recovery events across restarts - Add GET /api/agents/status endpoint returning live agent state + 24h event history - Stats dashboard: agent status cards, 24h availability timeline, per-run execution table Co-Authored-By: Claude Sonnet 4.6 --- internal/executor/helpers.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'internal/executor/helpers.go') diff --git a/internal/executor/helpers.go b/internal/executor/helpers.go index 9e4530b..aee7da0 100644 --- a/internal/executor/helpers.go +++ b/internal/executor/helpers.go @@ -143,6 +143,30 @@ func tailFile(path string, n int) string { return strings.Join(lines, "\n") } +// readFileTail returns the last maxBytes bytes of the file at path as a string, +// or empty string if the file cannot be read. Used to surface agent stderr on failure. +func readFileTail(path string, maxBytes int64) string { + f, err := os.Open(path) + if err != nil { + return "" + } + defer f.Close() + fi, err := f.Stat() + if err != nil { + return "" + } + offset := fi.Size() - maxBytes + if offset < 0 { + offset = 0 + } + buf := make([]byte, fi.Size()-offset) + n, err := f.ReadAt(buf, offset) + if err != nil && n == 0 { + return "" + } + return strings.TrimSpace(string(buf[:n])) +} + func gitSafe(args ...string) []string { return append([]string{"-c", "safe.directory=*"}, args...) } -- cgit v1.2.3