Skip to content

feat: weekly usage digest CLI command - #82

Open
kannupriyakalra wants to merge 4 commits into
mainfrom
feat/weekly-digest
Open

feat: weekly usage digest CLI command#82
kannupriyakalra wants to merge 4 commits into
mainfrom
feat/weekly-digest

Conversation

@kannupriyakalra

Copy link
Copy Markdown
Collaborator

Summary

Implements the copilot-lens digest command from issue #70 — a Spotify Wrapped-style terminal summary of AI usage.

copilot-lens digest               # current week (default)
copilot-lens digest --last-week   # prior week
copilot-lens digest --month       # current month
copilot-lens digest --save        # also writes digest.md to cwd
copilot-lens digest --json        # machine-readable JSON

Sample output:

Week of Jun 2 – Jun 8, 2026
────────────────────────────────────
  📅  Active days       5 / 7
  💬  Sessions          34     ▲ 12% vs prior
  ⏱   Total time        6h 14m
  🔤  Tokens used       1.2M   ▲ 8% vs prior
  🏆  Most active repo  copilot-lens
  🕐  Peak hour         2 – 3 PM
  🔧  Top tool          Bash (41 calls)
  🤖  Top model         claude-sonnet-4-6

  Longest session: "copilot-lens" — 48m, 23 turns

Changes

  • src/digest.tsgetDigest(period) aggregates sessions from listSessions() filtered by date range; scans CLI event files for tool usage, accurate duration, and turn counts; pulls token totals from getTokenUsage().daily buckets filtered to the range. No new data sources.
  • src/cli-digest.tsx — Ink TUI mirroring cli-tokens.tsx style; --save writes digest.md; --json outputs raw JSON for piping.
  • src/cli.ts — wires digest subcommand and updates help text.
  • src/__tests__/cli-digest.test.ts — 8 tests covering all parseDigestArgs combinations.

Test plan

  • copilot-lens digest renders the weekly summary
  • copilot-lens digest --last-week shows prior week label
  • copilot-lens digest --month shows current month label
  • copilot-lens digest --json outputs valid JSON with all fields
  • copilot-lens digest --save writes digest.md and also renders TUI
  • copilot-lens digest --help shows usage text
  • No activity period shows "No activity found for this period."
  • All 122 unit tests pass

Closes #70

🤖 Generated with Claude Code

@kannupriyakalra

Copy link
Copy Markdown
Collaborator Author

Verification Report

Verdict: PASS (with one bug found and fixed)

Method: Cold-start via npx tsx src/cli.ts digest [flags] on feat/weekly-digest. All sessions in test env are claude-code source.


Steps

  1. copilot-lens digest --help → correct usage printed, all four flags listed

    Usage: copilot-lens digest [options]
    
      Print a weekly usage summary to the terminal (Spotify Wrapped-style).
    
      Options:
        --last-week   Show last week instead of the current week
        --month       Show the current month's digest
        --save        Also write digest.md to the current directory
        --json        Output raw JSON (pipeline-friendly)
        -h, --help    Show this help
    
  2. copilot-lens digest → TUI renders correctly after fix

    Week of Jun 8 – Jun 14, 2026
    ────────────────────────────────────
      📅  Active days       1 / 7
      💬  Sessions          8
      ⏱   Total time        9h 5m
      🔤  Tokens used       119.3M
      🏆  Most active repo  llm4s
      🕐  Peak hour         8 – 9 PM
      🤖  Top model         claude-sonnet-4-6
    
      Longest session: "modular-jingling-pike" — 2h 25m
    
  3. copilot-lens digest --last-week → shows prior week label, graceful empty state

    Week of Jun 1 – Jun 7, 2026
    No activity found for this period.
    
  4. copilot-lens digest --month → June 2026 digest with ▲ change badges

    June 2026
    ────────────────────────────────────
      📅  Active days       1 / 30
      💬  Sessions          8     ▲ 167% vs prior
      ⏱   Total time        8h 59m
      🔤  Tokens used       116.1M     ▲ 189% vs prior
      🏆  Most active repo  llm4s
      🕐  Peak hour         8 – 9 PM
      🤖  Top model         claude-sonnet-4-6
    
  5. copilot-lens digest --json → valid JSON, all 16 fields present, correct schema

  6. copilot-lens digest --save → prints Saved digest to .../digest.md to stderr, renders TUI, writes well-formed Markdown table

    # AI Usage Digest
    ## Week of Jun 8 – Jun 14, 2026
    | Metric | Value |
    |--------|-------|
    | Active days | 1 / 7 |
    | Sessions | 8 |
    ...
    **Longest session:** "modular-jingling-pike" — 2h 25m
    _Generated by copilot-lens_
  7. copilot-lens --helpdigest correctly listed alongside tokens

  8. ✅ All 122 unit tests pass (8 new parseDigestArgs tests + 114 existing)

  9. 🔍 --bogus-flag → silently ignored, runs week digest. Consistent with tokens behavior.

  10. 🔍 --json --save together → --json takes priority, TUI suppressed and --save skipped. The old digest.md is not overwritten. This may surprise users who expect both to act; worth a note in --help if that combination is intentional.


Bug fixed in this review

totalDays off-by-one (fixed in commit db94427):

digest.ts line 93 had Math.round(...) + 1. Since end is already 23:59:59.999, Math.round(6.9999...) = 7 and the extra +1 made weeks display 8 and June display 31. Removed the +1:

  • Week now shows 1 / 7
  • June now shows 1 / 30

Observations for maintainer

  • topTool is always null for pure Claude Code setups — tool scanning only runs for cli-source sessions. On a machine with no Copilot CLI sessions (like this test), the 🔧 Top tool row never appears. The issue mockup shows it as a key metric. Consider pulling tool data from getClaudeCodeAnalytics() (it's already computed in sessions.ts) when cli sessions are absent.

  • Longest-session title shows session slug — Claude Code sessions use slugs (e.g. "modular-jingling-pike") as titles since there's no user-defined name. This is fine as a fallback, but for cli sessions the cwd basename is used which is more readable. No action needed; just worth knowing.

  • Tokens fluctuate slightly between invocations — The getTokenUsage 30 s cache means rapid sequential calls within the window return the same value; longer waits pick up in-progress session writes. Normal behavior, but explains why token counts in this report vary slightly between steps.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new copilot-lens digest CLI subcommand that produces a “Wrapped-style” usage summary for a selected period (week by default, with --last-week / --month) with optional JSON output and Markdown export.

Changes:

  • Introduces getDigest(period) to aggregate session counts, active days, durations, tool usage, token totals, and “prior period” comparisons.
  • Adds an Ink-based TUI (cli-digest.tsx) plus --save (writes digest.md) and --json modes.
  • Wires the new digest subcommand into the main CLI and adds argument-parsing tests.
Show a summary per file
File Description
src/digest.ts New digest aggregation logic over sessions + token usage + CLI event scanning.
src/cli-digest.tsx New Ink TUI and CLI entrypoint for copilot-lens digest, including --save and --json.
src/cli.ts Adds digest subcommand routing and updates top-level help text.
src/tests/cli-digest.test.ts Adds unit tests for parseDigestArgs.

Copilot's findings

  • Files reviewed: 4/4 changed files
  • Comments generated: 7

Comment thread src/digest.ts
Comment thread src/digest.ts Outdated
Comment thread src/cli-digest.tsx Outdated
Comment on lines +205 to +206
fs.writeFileSync(outPath, md, "utf-8");
process.stderr.write(`Saved digest to ${outPath}\n`);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — wrapped writeFileSync in a try/catch. On error it now prints a clear message to stderr and sets process.exitCode = 1, while the TUI still renders.

Comment thread src/cli-digest.tsx
Comment on lines +201 to +203
if (opts.save) {
const data = getDigest(opts.period);
const md = toMarkdown(data);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — DigestApp now accepts an optional precomputed prop. In --save mode the result from the first getDigest() call is passed directly as precomputed, so the TUI skips the second computation entirely.

Comment thread src/digest.ts
Comment on lines +79 to +81
export function getDigest(period: DigestPeriod = "week"): DigestData {
const { cur, prior } = getBounds(period);
const allSessions = listSessions();

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added 7 Vitest tests in src/__tests__/cli-digest.test.ts covering: required fields, totalDays for week/month periods, rangeLabel format, priorTokens shape, longestSession shape, and ISO date string validity.

Comment thread src/cli.ts Outdated
Commands:
(default) Start the web dashboard
tokens Show token usage in the terminal (Ink TUI)
digest Show a weekly usage summary in the terminal

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — updated the help description in src/cli.ts from "weekly" to "period-based" to accurately reflect that --last-week and --month are also supported.

Comment thread src/cli-digest.tsx Outdated
const HELP = `
Usage: copilot-lens digest [options]

Print a weekly usage summary to the terminal (Spotify Wrapped-style).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — updated the HELP string in src/cli-digest.tsx to say "period-based" instead of "weekly" so it matches the actual supported options.

@kannupriyakalra

Copy link
Copy Markdown
Collaborator Author

Hey @pavanvamsi3 — all 7 Copilot reviewer comments have been addressed. Could you take another look when you get a chance? Thanks!

kannupriyakalra and others added 4 commits June 19, 2026 00:48
Adds `copilot-lens digest` — a Spotify Wrapped-style terminal summary
of AI usage for the current week, last week, or current month.

- src/digest.ts: date-range aggregation over sessions and token data
- src/cli-digest.tsx: Ink TUI showing active days, sessions, time,
  tokens (with ▲/▼ % vs prior period), top repo/hour/tool/model,
  and longest session; --save writes digest.md; --json for scripting
- Wire into cli.ts under the `digest` subcommand
- Tests for parseDigestArgs covering all flags and edge cases

Closes #70

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
end is already set to 23:59:59.999, so Math.round(6.999...) already
gives 7; adding 1 made week show 8, June show 31.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Read events.jsonl from end of file so large sessions reflect the
  most recent activity for tool counts and duration
- Remove all-time topModel fallback — only show model from the
  selected period's token data to avoid stale/misleading values
- Wrap fs.writeFileSync in try/catch; print clear error and set
  non-zero exitCode on failure without blocking TUI render
- Pass pre-computed DigestData to DigestApp when --save is used to
  avoid calling getDigest() twice
- Fix help text: "weekly" → "period-based" in cli.ts and cli-digest.tsx
- Add 7 getDigest() tests covering all three periods, field shapes,
  date string format, and boundary invariants

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kannupriyakalra

Copy link
Copy Markdown
Collaborator Author

Merge conflicts resolved — rebased onto latest main. The branch is now clean and ready for re-review.

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.

feat: weekly usage digest — CLI report and optional Markdown export

2 participants