feat(stats): add GET /stats endpoint with per-agent/repo/day aggregates #127

Merged
charles merged 1 commit from dev/123 into main 2026-04-20 11:08:57 +00:00
Collaborator

Closes #123.

Dev pushed this branch at 12:34; container died at exit 137 before it could open the PR (same silent-disappearance pattern as before). Opening on its behalf so the review loop can run normally.

Summary

  • SQLite-backed task history (src/task-store.ts) persists finalized tasks from onFinish + handleCancel, growing beyond the 50-task in-memory cap.
  • New GET /stats endpoint aggregating cost, turns, success-rate per agent / repo / day over a configurable window.
  • Docs updated (README, CLAUDE.md).

Files

  • src/task-store.ts (new, 347 loc)
  • src/stats.test.ts (new, 522 loc)
  • src/main.ts (+55 loc)
  • README / CLAUDE.md

Test plan

  • bun test — dev ran its own local test pass before push
  • Reviewer pass
  • Manual smoke against live service: curl /stats returns aggregates
Closes #123. Dev pushed this branch at 12:34; container died at exit 137 before it could open the PR (same silent-disappearance pattern as before). Opening on its behalf so the review loop can run normally. ## Summary - SQLite-backed task history (`src/task-store.ts`) persists finalized tasks from `onFinish` + `handleCancel`, growing beyond the 50-task in-memory cap. - New `GET /stats` endpoint aggregating cost, turns, success-rate per agent / repo / day over a configurable window. - Docs updated (README, CLAUDE.md). ## Files - `src/task-store.ts` (new, 347 loc) - `src/stats.test.ts` (new, 522 loc) - `src/main.ts` (+55 loc) - README / CLAUDE.md ## Test plan - [x] `bun test` — dev ran its own local test pass before push - [ ] Reviewer pass - [ ] Manual smoke against live service: `curl /stats` returns aggregates
feat(stats): add GET /stats endpoint with per-agent/repo/day aggregates
All checks were successful
qa / qa (pull_request) Successful in 2m58s
qa / dockerfile (pull_request) Successful in 9s
709364bef7
Adds persistent task history (SQLite tasks.db) and a /stats endpoint
that serves cost/turn/success-rate aggregates over a configurable time
window. Finalized tasks are persisted from onFinish and handleCancel in
main.ts so the store grows beyond the 50-task in-memory cap.

Closes #123

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
claude-desktop left a comment

Note: PR was opened by me (claude-desktop) on dev's behalf after the 137 crash, so I can't self-approve — posting my review as a comment instead.

Reviewed against #123 AC line-by-line:

Endpoint + response shape — matches the spec exactly. window/agent/repo params wired; unknown window falls back to 30d; success_rate excludes cancelled from the denominator (denominator-zero returns 0, not NaN) and documented in the endpoint docstring.

SQLite schema — indexes on finished_at, agent, repo keep the 30d aggregation bounded. INSERT OR REPLACE makes persistTask idempotent for re-entry. Parametrised queries throughout. agent_type column added beyond the AC's listed columns — needed for by_agent.type, correct call.

WiringpersistTask fires from both onFinish and handleCancel, so success/failure/cancelled all land in the table. In-memory 50-task cap preserved for SSE.

Tests — 19 tests pass, covering every edge case the AC enumerated (empty window, all-cancelled → 0, single-task, non-existent-agent filter, invalid window param, 7d/30d/all windows, by_day ordering).

Docs — README /stats section with query-param table + response example; CLAUDE.md module table split storage.ts / task-store.ts with accurate one-liners.

Pre-existing repo issues, not blockers for this PR

  • bunx tsc --noEmit fails on src/dashboard-browser.test.ts (cannot find happy-dom types). Reproduces on main before this branch lands — shipped with PR #121. Worth a follow-up ticket but not a blocker.

Nits (non-blocking)

  • task-store.ts reads CLAUDE_HOOKS_STATE_DIR directly rather than reusing db.ts's resolver. Equivalent behaviour, one-line duplication.

LGTM from my side — would approve if I could. Leaving the PR open for the reviewer agent for a formal verdict.

Note: PR was opened by me (claude-desktop) on dev's behalf after the 137 crash, so I can't self-approve — posting my review as a comment instead. Reviewed against #123 AC line-by-line: **Endpoint + response shape** — matches the spec exactly. `window`/`agent`/`repo` params wired; unknown `window` falls back to `30d`; `success_rate` excludes cancelled from the denominator (denominator-zero returns 0, not NaN) and documented in the endpoint docstring. **SQLite schema** — indexes on `finished_at`, `agent`, `repo` keep the 30d aggregation bounded. `INSERT OR REPLACE` makes `persistTask` idempotent for re-entry. Parametrised queries throughout. `agent_type` column added beyond the AC's listed columns — needed for `by_agent.type`, correct call. **Wiring** — `persistTask` fires from both `onFinish` and `handleCancel`, so success/failure/cancelled all land in the table. In-memory 50-task cap preserved for SSE. **Tests** — 19 tests pass, covering every edge case the AC enumerated (empty window, all-cancelled → 0, single-task, non-existent-agent filter, invalid window param, 7d/30d/all windows, by_day ordering). **Docs** — README `/stats` section with query-param table + response example; CLAUDE.md module table split `storage.ts` / `task-store.ts` with accurate one-liners. **Pre-existing repo issues, not blockers for this PR** - `bunx tsc --noEmit` fails on `src/dashboard-browser.test.ts` (cannot find `happy-dom` types). Reproduces on `main` before this branch lands — shipped with PR #121. Worth a follow-up ticket but not a blocker. **Nits (non-blocking)** - `task-store.ts` reads `CLAUDE_HOOKS_STATE_DIR` directly rather than reusing `db.ts`'s resolver. Equivalent behaviour, one-line duplication. LGTM from my side — would approve if I could. Leaving the PR open for the `reviewer` agent for a formal verdict.
charles force-pushed dev/123 from 709364bef7
All checks were successful
qa / qa (pull_request) Successful in 2m58s
qa / dockerfile (pull_request) Successful in 9s
to 38bac0926a
All checks were successful
qa / qa (pull_request) Successful in 3m4s
qa / dockerfile (pull_request) Successful in 8s
2026-04-20 11:04:16 +00:00
Compare
charles deleted branch dev/123 2026-04-20 11:08:57 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!127
No description provided.