vibestats 1.0.3 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +54 -35
  2. package/dist/index.js +67 -0
  3. package/package.json +6 -7
package/README.md CHANGED
@@ -1,79 +1,98 @@
1
- # @wolfaidev/claude-wrapped
1
+ # vibestats
2
2
 
3
- Generate your **Claude Code Wrapped 2025** - a Spotify Wrapped-style annual summary of your Claude Code usage.
3
+ AI coding stats CLI for **Claude Code** and **OpenAI Codex**. Track your usage and generate annual "Spotify Wrapped" style summaries.
4
4
 
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- npm install -g @wolfaidev/claude-wrapped
8
+ npm install -g vibestats
9
+ # or run directly
10
+ npx vibestats
9
11
  ```
10
12
 
11
13
  ## Usage
12
14
 
13
15
  ```bash
14
- claude-wrapped
16
+ # Usage stats (default)
17
+ vibestats # Daily usage table
18
+ vibestats --monthly # Monthly aggregation
19
+ vibestats --model # Aggregate by model
20
+ vibestats --total # Show only totals
21
+
22
+ # Wrapped summary
23
+ vibestats --wrapped # Annual wrapped summary
15
24
  ```
16
25
 
17
- This reads your local Claude Code stats from `~/.claude/stats-cache.json` and displays:
26
+ ## CLI Flags
18
27
 
19
- - Total sessions, tokens, and estimated cost
20
- - Longest and current coding streaks
21
- - Peak coding hour and favorite day
22
- - Model usage breakdown
23
- - Words generated estimate
24
- - Shareable URL to view your wrapped online
28
+ ### Usage Mode (default)
25
29
 
26
- ## CLI Flags
30
+ | Flag | Description |
31
+ |------|-------------|
32
+ | `--monthly` | Aggregate by month |
33
+ | `--model` | Aggregate by model |
34
+ | `--total` | Show only totals |
35
+ | `--since YYYY-MM-DD` | Filter from date |
36
+ | `--until YYYY-MM-DD` | Filter to date |
37
+ | `--compact`, `-c` | Compact table (hide cache columns) |
38
+ | `--json` | Output raw JSON |
39
+
40
+ ### Wrapped Mode
27
41
 
28
42
  | Flag | Description |
29
43
  |------|-------------|
44
+ | `--wrapped` | Generate wrapped summary |
30
45
  | `--json` | Output raw JSON stats |
31
46
  | `--quiet`, `-q` | Only output the shareable URL |
32
- | `--url <url>` | Custom base URL for the wrapped page |
33
- | `--init` | Create a default config file |
34
- | `--config` | Show current config location and values |
47
+ | `--no-short` | Disable shortlink generation |
35
48
 
36
- ## Config File
49
+ ### Data Source
37
50
 
38
- Create a config file to set persistent defaults:
51
+ | Flag | Description |
52
+ |------|-------------|
53
+ | `--codex` | OpenAI Codex only |
54
+ | `--combined` | Claude + Codex combined |
55
+
56
+ ### Config
57
+
58
+ | Flag | Description |
59
+ |------|-------------|
60
+ | `--init` | Create config file |
61
+ | `--config` | Show current config |
62
+ | `--url <url>` | Custom base URL |
63
+
64
+ ## Config File
39
65
 
40
66
  ```bash
41
- claude-wrapped --init
67
+ vibestats --init
42
68
  ```
43
69
 
44
- This creates `~/.claude-wrapped.json`:
70
+ Creates `~/.vibestats.json`:
45
71
 
46
72
  ```json
47
73
  {
48
- "baseUrl": "https://wrapped.wolfai.dev",
74
+ "baseUrl": "https://vibestats.wolfai.dev",
49
75
  "outputFormat": "normal",
50
- "theme": {
51
- "enabled": true
52
- },
76
+ "theme": { "enabled": true },
53
77
  "hideCost": false
54
78
  }
55
79
  ```
56
80
 
57
- ### Config Options
58
-
59
- | Option | Type | Default | Description |
60
- |--------|------|---------|-------------|
61
- | `baseUrl` | string | `https://wrapped.wolfai.dev` | Base URL for shareable links |
62
- | `outputFormat` | `"normal"` \| `"json"` \| `"quiet"` | `"normal"` | Default output format |
63
- | `theme.enabled` | boolean | `true` | Enable terminal colors |
64
- | `statsCachePath` | string | `~/.claude/stats-cache.json` | Custom stats file path |
65
- | `hideCost` | boolean | `false` | Hide cost from output |
81
+ ## Data Sources
66
82
 
67
- CLI flags always override config file values.
83
+ | Source | Location |
84
+ |--------|----------|
85
+ | Claude Code | `~/.claude/projects/**/*.jsonl` |
86
+ | OpenAI Codex | `~/.codex/sessions/*.jsonl` |
68
87
 
69
88
  ## Requirements
70
89
 
71
90
  - Node.js 18+
72
- - Claude Code must have been used at least once (to generate stats)
91
+ - Claude Code or OpenAI Codex CLI usage data
73
92
 
74
93
  ## View Online
75
94
 
76
- Visit [wrapped.wolfai.dev](https://wrapped.wolfai.dev) to view your wrapped in the browser.
95
+ Visit [vibestats.wolfai.dev](https://vibestats.wolfai.dev) to view your wrapped in the browser.
77
96
 
78
97
  ## License
79
98
 
package/dist/index.js CHANGED
@@ -1436,6 +1436,49 @@ function getModelAbbrevFromDisplayName(displayName) {
1436
1436
  };
1437
1437
  return map[displayName] || displayName.slice(0, 5).toLowerCase();
1438
1438
  }
1439
+ function encodeUsageToUrl(stats, baseUrl = "https://vibestats.wolfai.dev") {
1440
+ const params = new URLSearchParams();
1441
+ const aggMap = { daily: "d", monthly: "m", model: "mo", total: "t" };
1442
+ params.set("agg", aggMap[stats.aggregation] || "d");
1443
+ if (stats.source !== "claude") {
1444
+ params.set("src", stats.source);
1445
+ }
1446
+ const formatDateCompact = (d) => d.replace(/-/g, "");
1447
+ params.set("dr", `${formatDateCompact(stats.dateRange.start)}-${formatDateCompact(stats.dateRange.end)}`);
1448
+ const rows = stats.rows.slice(0, 31).map((row) => {
1449
+ let key = row.key;
1450
+ if (stats.aggregation === "daily" && row.key.length === 10) {
1451
+ key = row.key.slice(5).replace("-", "");
1452
+ }
1453
+ return [
1454
+ key,
1455
+ formatCompactNumber(row.inputTokens),
1456
+ formatCompactNumber(row.outputTokens),
1457
+ formatCompactNumber(row.cacheWriteTokens),
1458
+ formatCompactNumber(row.cacheReadTokens),
1459
+ formatCompactNumber(row.totalTokens),
1460
+ row.cost.toFixed(2)
1461
+ ].join(":");
1462
+ });
1463
+ params.set("rows", rows.join("|"));
1464
+ const t = stats.totals;
1465
+ params.set("tot", [
1466
+ formatCompactNumber(t.inputTokens),
1467
+ formatCompactNumber(t.outputTokens),
1468
+ formatCompactNumber(t.cacheWriteTokens),
1469
+ formatCompactNumber(t.cacheReadTokens),
1470
+ formatCompactNumber(t.totalTokens),
1471
+ t.cost.toFixed(2)
1472
+ ].join(":"));
1473
+ if (stats.modelBreakdown.length > 0) {
1474
+ const mb = stats.modelBreakdown.slice(0, 5).map((m) => {
1475
+ const abbr = getModelAbbrevFromDisplayName(m.model);
1476
+ return `${abbr}:${m.percentage}:${m.cost.toFixed(2)}`;
1477
+ });
1478
+ params.set("mb", mb.join(","));
1479
+ }
1480
+ return `${baseUrl}?${params.toString()}`;
1481
+ }
1439
1482
 
1440
1483
  // src/display.ts
1441
1484
  var colors2 = {
@@ -1704,6 +1747,13 @@ var main = defineCommand({
1704
1747
  description: "Use compact table format (hide cache columns)",
1705
1748
  default: false
1706
1749
  },
1750
+ // Share option for usage mode
1751
+ share: {
1752
+ type: "boolean",
1753
+ alias: "s",
1754
+ description: "Generate a shareable URL (usage mode)",
1755
+ default: false
1756
+ },
1707
1757
  // Wrapped-specific options
1708
1758
  url: {
1709
1759
  type: "string",
@@ -1769,6 +1819,19 @@ async function runUsage(args, config) {
1769
1819
  }
1770
1820
  process.exit(1);
1771
1821
  }
1822
+ const baseUrl = args.url || config.baseUrl || "https://vibestats.wolfai.dev";
1823
+ let shareUrl = null;
1824
+ if (args.share) {
1825
+ const fullUrl = encodeUsageToUrl(stats, baseUrl);
1826
+ if (!args["no-short"]) {
1827
+ shareUrl = await createShortlink(fullUrl, baseUrl);
1828
+ }
1829
+ shareUrl = shareUrl || fullUrl;
1830
+ }
1831
+ if (args.quiet && args.share && shareUrl) {
1832
+ console.log(shareUrl);
1833
+ return;
1834
+ }
1772
1835
  if (args.json) {
1773
1836
  console.log(JSON.stringify(stats, null, 2));
1774
1837
  } else if (args.quiet) {
@@ -1787,6 +1850,10 @@ async function runUsage(args, config) {
1787
1850
  showColors: config.theme?.enabled !== false
1788
1851
  });
1789
1852
  }
1853
+ if (args.share && shareUrl && !args.json) {
1854
+ console.log();
1855
+ console.log(`\u{1F517} ${shareUrl}`);
1856
+ }
1790
1857
  }
1791
1858
  async function runWrapped(args, config) {
1792
1859
  const options = resolveOptions(args, config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibestats",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "AI coding stats - usage tracking and annual wrapped for Claude Code & Codex",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,11 +18,6 @@
18
18
  "files": [
19
19
  "dist"
20
20
  ],
21
- "scripts": {
22
- "dev": "tsx src/index.ts",
23
- "build": "tsup src/index.ts --format esm --dts --clean --shims",
24
- "prepublishOnly": "pnpm build"
25
- },
26
21
  "keywords": [
27
22
  "claude",
28
23
  "claude-code",
@@ -50,5 +45,9 @@
50
45
  },
51
46
  "engines": {
52
47
  "node": ">=18.0.0"
48
+ },
49
+ "scripts": {
50
+ "dev": "tsx src/index.ts",
51
+ "build": "tsup src/index.ts --format esm --dts --clean --shims"
53
52
  }
54
- }
53
+ }