cmdStats implements `flow stats` — usage & ROI analytics derived from flow.db, session transcripts, and on-disk auto-runs/owner/kb dirs.
(args []string)
| 15 | // cmdStats implements `flow stats` — usage & ROI analytics derived from |
| 16 | // flow.db, session transcripts, and on-disk auto-runs/owner/kb dirs. |
| 17 | func cmdStats(args []string) int { |
| 18 | fs := flagSet("stats") |
| 19 | since := fs.String("since", "all", "window: all | <N>d | RFC3339") |
| 20 | project := fs.String("project", "", "limit to one project slug") |
| 21 | card := fs.Bool("card", false, "render a shareable HTML card instead of the terminal report") |
| 22 | png := fs.Bool("png", false, "render a shareable PNG card (no browser needed)") |
| 23 | out := fs.String("out", "", "output path for --card/--png; default <flow-root>/stats-card.{html,png}") |
| 24 | if err := fs.Parse(args); err != nil { |
| 25 | return 2 |
| 26 | } |
| 27 | |
| 28 | root, err := flowRoot() |
| 29 | if err != nil { |
| 30 | fmt.Fprintf(os.Stderr, "error: %v\n", err) |
| 31 | return 1 |
| 32 | } |
| 33 | dbPath, err := flowDBPath() |
| 34 | if err != nil { |
| 35 | fmt.Fprintf(os.Stderr, "error: %v\n", err) |
| 36 | return 1 |
| 37 | } |
| 38 | db, err := flowdb.OpenDB(dbPath) |
| 39 | if err != nil { |
| 40 | fmt.Fprintf(os.Stderr, "error: open db: %v\n", err) |
| 41 | return 1 |
| 42 | } |
| 43 | defer db.Close() |
| 44 | |
| 45 | sinceTime, err := stats.ParseSince(*since, time.Now()) |
| 46 | if err != nil { |
| 47 | fmt.Fprintf(os.Stderr, "error: %v\n", err) |
| 48 | return 2 |
| 49 | } |
| 50 | |
| 51 | home, err := os.UserHomeDir() |
| 52 | if err != nil { |
| 53 | fmt.Fprintf(os.Stderr, "error: no home dir: %v\n", err) |
| 54 | return 1 |
| 55 | } |
| 56 | cachePath := filepath.Join(root, "stats-cache.json") |
| 57 | cache := stats.LoadCache(cachePath) |
| 58 | consts := stats.LoadConstants(filepath.Join(root, "stats.json")) |
| 59 | |
| 60 | s, err := stats.BuildStats(stats.BuildOpts{ |
| 61 | Root: root, |
| 62 | ClaudeProjects: filepath.Join(home, ".claude", "projects"), |
| 63 | DB: db, |
| 64 | Cache: cache, |
| 65 | Constants: consts, |
| 66 | Since: sinceTime, |
| 67 | Project: *project, |
| 68 | }) |
| 69 | if err != nil { |
| 70 | fmt.Fprintf(os.Stderr, "error: build stats: %v\n", err) |
| 71 | return 1 |
| 72 | } |
| 73 | if saveErr := cache.Save(cachePath); saveErr != nil { |
| 74 | fmt.Fprintf(os.Stderr, "warning: could not write stats cache: %v\n", saveErr) |