Skip to content

feat(cli): add shareable stats command - #43653

Merged
nexxeln merged 10 commits into
v2from
stats-cli
Aug 24, 2026
Merged

nexxeln merged 10 commits into
v2from
stats-cli

Conversation

@nexxeln

@nexxeln nexxeln commented Aug 20, 2026 •

Copy link
Copy Markdown
Contributor

summary

  • add a shareable, terminal-native opencode stats activity card with focused model, tool, and cost table modes
  • aggregate stats through bounded monthly SQLite scalar queries instead of loading complete message payloads into JS
  • exclude copied pre-fork history while retaining genuine post-fork activity
  • improve scope clarity, narrow-terminal layouts, range rendering, empty states, color fallback, and cross-platform output

benchmark

  • live 19.27 GB V2 database with 75,923 messages and 1.07 GB of current-year message JSON
  • 30-day SQL queries: 9 ms activity, 111 ms overview, 286 ms models, 220 ms tools
  • all-time SQL queries: 1.08 s overview, 3.16 s models, 2.28 s tools
  • existing time index used; no database schema or index changes

testing

  • bun typecheck in schema, core, protocol, server, client, and cli
  • bun test test/session-stats.test.ts in core
  • bun test test/stats.test.ts in cli
  • targeted oxlint on changed source and tests
  • in-memory standalone smoke tests and invalid-flag validation
  • pre-push full workspace typecheck

@Enough1122

Copy link
Copy Markdown

AI code review — automated review for reference; please use your judgment.

  1. packages/core/src/session/stats.ts:150 — total tokens/cost are summed from both assistant-message payloads and every UsageRecorded event regardless of its source — if usage events are also emitted per assistant step (not just auxiliary sources like title as in the test), totals double-count while the per-model table stays correct, producing numbers that don't add up — either filter events by source, dedupe by message id, or document the invariant and add a regression test with a step-sourced event.

  2. packages/core/src/session/stats.ts:33 — the aggregation loads all user+assistant rows in range including their full data JSON into memory (--all has no lower bound), plus per-tool duration arrays kept only for a median — on a long-lived server this can be hundreds of MB and slow — consider SQL-side aggregation, projecting only required fields, or chunked iteration; at minimum document the expected scale.

  3. packages/cli/src/commands/handlers/stats.ts:27 — client.session.stats(...) and client.location.get(...) are wrapped in Effect.promise with no error mapping or timeout — a refused connection or slow server surfaces as an unhandled defect/stack trace instead of a clean CLI error — use Effect.try and print "could not reach server at " with a non-zero exit code.

  4. packages/core/src/session/stats.ts:88 — decodeUnknownOption silently drops rows that fail to decode — corrupt or legacy-schema messages quietly disappear from stats with no signal, which will look like "my numbers are wrong" reports later — count/log skipped rows at debug level (or expose a skipped field).

  5. packages/core/src/session/stats.ts:96 vs :117 — range filtering uses SessionMessageTable.time_created, but activity/steps bucket by message.time.created and events by EventTable.created — near range boundaries the same step can be included in one view and excluded from another — pick one timestamp source per entity or widen the SQL window slightly and re-filter after decoding.

  6. Nit — packages/cli/src/commands/handlers/stats.ts:214 — truncate/padEnd use .length, so CJK/wide model or tool names misalign the tables; consider string-width-aware padding.

Overall: nice feature — the privacy default (shareable card hides tool names, models, and cost; asserted by tests) is exactly right, timezone handling and streak logic are solid, and batching the event query in groups of 500 shows care. Item 1 is the one I'd verify before merge. Thanks!

@Enough1122

Copy link
Copy Markdown

AI code review - automated review for reference; please use your judgment.

  • packages/cli/src/commands/handlers/stats.ts:~150 - stats.models.slice(0, limit) truncates silently; add a "+N more" footer so users know the table is clipped (toolUsage table has the same issue).
  • packages/cli/src/commands/handlers/stats.ts:~110-125 - activity heatmap math is solid (Monday-aligned, 52-week clamp), but weekStarts length uses (dateOrdinal(end) - dateOrdinal(start)) / 7 which can produce one extra column at exact week boundaries; harmless visually, worth a glance if alignment ever looks off.
  • Good privacy posture: default card omits cost and tool names, verified by tests asserting absence of private_tool/cost in default output.
  • Flag validation (mutual exclusion of --days/--year/--all, --limit >= 1, year bounds) is thorough.

@nexxeln
nexxeln merged commit 2e1d7c8 into v2 Aug 24, 2026
7 checks passed
@nexxeln
nexxeln deleted the stats-cli branch August 24, 2026 11:17
jinhuang712 pushed a commit to jinhuang712/opencode that referenced this pull request Sep 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants