From 479c250a92ef5fb7334ddf176383b1afdba3ab1c Mon Sep 17 00:00:00 2001 From: teernisse Date: Thu, 19 Feb 2026 15:41:45 -0500 Subject: [PATCH] chore: add project tooling with Makefile, golangci-lint config, and CLAUDE.md Establish the quality infrastructure for the cburn project: - Makefile: standardized targets for build, install, lint, test, test-race, bench, and fuzz. Uses explicit Go path (/usr/local/go/bin/go) for reproducibility. Fuzz defaults to 30s with FUZZ_TIME override. - .golangci.yml (v2 format): enables gosec (security), revive (style), gocritic (bugs/perf), errcheck, nilerr, perfsprint, prealloc, and standard static analysis. Disables noisy rules (exported doc requirement, ifElseChain, deferred .Close() gosec G104). Includes gofmt + goimports formatters. - CLAUDE.md: comprehensive project guide covering architecture overview, data flow diagram, package map, build/test commands, key design decisions (byte-level parsing, mtime-based caching, async TUI loading), and configuration reference. - .gitignore: add pipeline.test to ignored test artifacts. --- .gitignore | 3 ++ .golangci.yml | 44 ++++++++++++++++++++++++++ CLAUDE.md | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 34 +++++++++++++++++++++ 4 files changed, 166 insertions(+) create mode 100644 .golangci.yml create mode 100644 CLAUDE.md create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index bf5507b..662b20d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,8 @@ cburn .idea/ .vscode/ +# Test artifacts +pipeline.test + # OS .DS_Store diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..8e83f10 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,44 @@ +version: "2" + +linters: + enable: + - gosec # security checks + - revive # style & correctness (golint successor) + - gocritic # bugs, performance, style + - unconvert # unnecessary type conversions + - unparam # unused function parameters + - misspell # typos in comments/strings + - errcheck # unchecked errors (on by default, being explicit) + - govet # suspicious constructs (on by default) + - staticcheck # deep static analysis (on by default) + - ineffassign # unused assignments (on by default) + - unused # unused code (on by default) + - nilerr # returning nil when error is non-nil + - perfsprint # faster fmt.Sprintf alternatives + - prealloc # slice pre-allocation hints + +linters-settings: + revive: + rules: + - name: exported + disabled: true # don't require doc comments on every export + gocritic: + enabled-tags: + - diagnostic + - performance + disabled-checks: + - ifElseChain # sometimes clearer than switch + gosec: + excludes: + - G104 # don't flag deferred .Close() unchecked errors + funlen: + lines: 80 + +formatters: + enable: + - gofmt + - goimports + +output: + sort-order: + - file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..dab2ccd --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,85 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What This Is + +cburn is a CLI + TUI dashboard for analyzing Claude Code usage metrics. It parses JSONL session logs from `~/.claude/projects/`, computes token usage, costs, cache efficiency, and activity patterns, then presents results as CLI tables or an interactive Bubble Tea dashboard. + +## Build & Run + +A `Makefile` wraps all common commands. Go is at `/usr/local/go/bin/go`. + +```bash +make build # build ./cburn binary +make install # install to ~/go/bin + +cburn # default: summary command +cburn tui # interactive dashboard +cburn costs # cost breakdown +cburn --no-cache # skip SQLite cache, full reparse +``` + +## Quality Pipeline + +```bash +make lint # golangci-lint (config: .golangci.yml) +make test # unit tests +make test-race # tests with race detector +make bench # pipeline benchmarks (uses live ~/.claude data) +make fuzz # fuzz the JSONL parser (default 30s, override: FUZZ_TIME=2m) +``` + +Lint + test should pass before committing. The linter catches security issues (gosec), unchecked errors (errcheck), performance hints (perfsprint, prealloc), and style (revive). + +Tests live alongside the code they test (`*_test.go`). The parser has both unit tests and a fuzz test in `internal/source/parser_test.go`. + +## Architecture + +### Data Flow + +``` +~/.claude/projects/**/*.jsonl + -> source.ScanDir() + source.ParseFile() (parallel, GOMAXPROCS workers) + -> store.Cache (SQLite, mtime-based incremental) + -> pipeline.Aggregate*() functions + -> CLI renderers (cmd/) or TUI tabs (internal/tui/) +``` + +### Package Map + +| Package | Role | +|---------|------| +| `cmd/` | Cobra CLI commands. Each file = one subcommand. `root.go` has shared data loading + filtering. | +| `internal/source` | File discovery (`ScanDir`) and JSONL parsing (`ParseFile`). Deduplicates by message ID. | +| `internal/pipeline` | ETL orchestration: parallel loading, cache-aware incremental loading, aggregation functions (`Aggregate`, `AggregateDays`, `AggregateHourly`, `AggregateModels`, `AggregateProjects`). | +| `internal/store` | SQLite cache layer. Tracks file mtime/size, caches parsed `SessionStats`. | +| `internal/model` | Domain types: `SessionStats`, `APICall`, `SummaryStats`, `DailyStats`, etc. | +| `internal/config` | TOML config (`~/.config/cburn/config.toml`), model pricing tables, cost calculation. | +| `internal/cli` | Terminal formatting: numbers, tokens, costs, tables, horizontal bars. | +| `internal/claudeai` | claude.ai API client for subscription/usage data. | +| `internal/tui` | Bubble Tea app. `app.go` is the root model with async data loading. Tab renderers in `tab_*.go`. | +| `internal/tui/components` | Reusable TUI components: cards, bar charts, sparklines, progress bars, tab bar. | +| `internal/tui/theme` | Color schemes (flexoki-dark, catppuccin-mocha, tokyo-night, terminal). | + +### Key Design Decisions + +- **Parsing strategy**: User/system entries use byte-level extraction for speed; only assistant entries get full JSON parse (they carry token/cost data). +- **Deduplication**: Messages are keyed by message ID; the final state wins (handles edits/retries). +- **Cache**: SQLite at `~/.cache/cburn/sessions.db`. Mtime+size diffing means unchanged files aren't reparsed. +- **TUI async loading**: Data loads via goroutines posting `tea.Msg`; the UI remains responsive during parse. +- **Pricing**: Hardcoded in `internal/config/pricing.go` with user overrides in config TOML. Model names are normalized (date suffixes stripped). + +## Configuration + +Config file: `~/.config/cburn/config.toml` + +Env var fallbacks: `ANTHROPIC_ADMIN_KEY`, `CLAUDE_SESSION_KEY` + +Run `cburn setup` for interactive configuration. + +## TUI Layout Conventions + +- `components.CardInnerWidth(w)` computes usable width inside a card border. +- `components.LayoutRow(w, n)` splits width into n columns accounting for gaps. +- When rendering inline bars (like Activity panel), dynamically compute column widths from actual data to prevent line wrapping. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..65739a8 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +GO := /usr/local/go/bin/go +BIN := cburn + +.PHONY: build install lint test test-race bench fuzz clean + +## Build & install +build: + $(GO) build -o $(BIN) . + +install: + $(GO) install . + +## Quality +lint: + golangci-lint run ./... + +test: + $(GO) test ./... + +test-race: + $(GO) test -race ./... + +bench: + $(GO) test -bench=. -benchmem ./internal/pipeline/ + +## Fuzz (run for 30s by default, override with FUZZ_TIME=2m) +FUZZ_TIME ?= 30s +fuzz: + $(GO) test -fuzz=Fuzz -fuzztime=$(FUZZ_TIME) ./internal/source/ + +## Housekeeping +clean: + rm -f $(BIN) + $(GO) clean -testcache