vibestats 1.2.0 → 1.3.0
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.
- package/README.md +6 -1
- package/dist/index.js +85 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,11 +31,16 @@ vibestats --wrapped # Annual wrapped summary
|
|
|
31
31
|
|------|-------------|
|
|
32
32
|
| `--monthly` | Aggregate by month |
|
|
33
33
|
| `--model` | Aggregate by model |
|
|
34
|
+
| `--sessions` | Aggregate by session |
|
|
34
35
|
| `--total` | Show only totals |
|
|
35
36
|
| `--since YYYY-MM-DD` | Filter from date |
|
|
36
37
|
| `--until YYYY-MM-DD` | Filter to date |
|
|
38
|
+
| `--last N` | Last N days (shorthand: `--last7`, `--last30`, etc.) |
|
|
37
39
|
| `--compact`, `-c` | Compact table (hide cache columns) |
|
|
38
40
|
| `--json` | Output raw JSON |
|
|
41
|
+
| `--quiet`, `-q` | Quiet output (totals line) |
|
|
42
|
+
| `--share`, `-s` | Generate a shareable usage URL |
|
|
43
|
+
| `--project`, `-p` | Current project only (Claude Code) |
|
|
39
44
|
|
|
40
45
|
### Wrapped Mode
|
|
41
46
|
|
|
@@ -59,7 +64,7 @@ vibestats --wrapped # Annual wrapped summary
|
|
|
59
64
|
|------|-------------|
|
|
60
65
|
| `--init` | Create config file |
|
|
61
66
|
| `--config` | Show current config |
|
|
62
|
-
| `--url <url>` | Custom base URL |
|
|
67
|
+
| `--url <url>` | Custom base URL for shareable links/pages |
|
|
63
68
|
|
|
64
69
|
## Config File
|
|
65
70
|
|
package/dist/index.js
CHANGED
|
@@ -1978,10 +1978,55 @@ function createSpinner(label = "Loading vibestats...") {
|
|
|
1978
1978
|
};
|
|
1979
1979
|
return { whilePromise, stop };
|
|
1980
1980
|
}
|
|
1981
|
+
function formatLocalDateYYYYMMDD(date) {
|
|
1982
|
+
const year = date.getFullYear();
|
|
1983
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
1984
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
1985
|
+
return `${year}-${month}-${day}`;
|
|
1986
|
+
}
|
|
1987
|
+
function parseLocalDateYYYYMMDD(dateStr) {
|
|
1988
|
+
const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(dateStr.trim());
|
|
1989
|
+
if (!m) return null;
|
|
1990
|
+
const year = Number.parseInt(m[1], 10);
|
|
1991
|
+
const month = Number.parseInt(m[2], 10);
|
|
1992
|
+
const day = Number.parseInt(m[3], 10);
|
|
1993
|
+
if (!Number.isFinite(year) || !Number.isFinite(month) || !Number.isFinite(day)) return null;
|
|
1994
|
+
if (month < 1 || month > 12) return null;
|
|
1995
|
+
if (day < 1 || day > 31) return null;
|
|
1996
|
+
const date = new Date(year, month - 1, day, 12, 0, 0, 0);
|
|
1997
|
+
if (date.getFullYear() !== year || date.getMonth() !== month - 1 || date.getDate() !== day) return null;
|
|
1998
|
+
return date;
|
|
1999
|
+
}
|
|
2000
|
+
function parseLastDaysFlag(args) {
|
|
2001
|
+
const parseDays = (value) => {
|
|
2002
|
+
if (typeof value === "number") {
|
|
2003
|
+
if (!Number.isInteger(value) || value <= 0) return null;
|
|
2004
|
+
return value;
|
|
2005
|
+
}
|
|
2006
|
+
if (typeof value === "string") {
|
|
2007
|
+
const m = /^(\d+)\s*d?$/.exec(value.trim());
|
|
2008
|
+
if (!m) return null;
|
|
2009
|
+
const days = Number.parseInt(m[1], 10);
|
|
2010
|
+
if (!Number.isFinite(days) || days <= 0) return null;
|
|
2011
|
+
return days;
|
|
2012
|
+
}
|
|
2013
|
+
return null;
|
|
2014
|
+
};
|
|
2015
|
+
const direct = parseDays(args.last);
|
|
2016
|
+
if (direct) return direct;
|
|
2017
|
+
const shorthandDays = Object.keys(args).map((k) => {
|
|
2018
|
+
const m = /^last(\d+)$/.exec(k);
|
|
2019
|
+
if (!m) return null;
|
|
2020
|
+
return Number.parseInt(m[1], 10);
|
|
2021
|
+
}).filter((n) => typeof n === "number" && Number.isFinite(n) && n > 0);
|
|
2022
|
+
if (shorthandDays.length === 0) return null;
|
|
2023
|
+
shorthandDays.sort((a, b) => a - b);
|
|
2024
|
+
return shorthandDays[0];
|
|
2025
|
+
}
|
|
1981
2026
|
var main = defineCommand({
|
|
1982
2027
|
meta: {
|
|
1983
2028
|
name: "vibestats",
|
|
1984
|
-
version: "1.
|
|
2029
|
+
version: "1.3.0",
|
|
1985
2030
|
description: "AI coding stats - usage tracking and annual wrapped for Claude Code & Codex"
|
|
1986
2031
|
},
|
|
1987
2032
|
args: {
|
|
@@ -2012,7 +2057,7 @@ var main = defineCommand({
|
|
|
2012
2057
|
quiet: {
|
|
2013
2058
|
type: "boolean",
|
|
2014
2059
|
alias: "q",
|
|
2015
|
-
description: "
|
|
2060
|
+
description: "Quiet mode (usage: totals line; wrapped: URL only)",
|
|
2016
2061
|
default: false
|
|
2017
2062
|
},
|
|
2018
2063
|
// Usage-specific options
|
|
@@ -2047,6 +2092,11 @@ var main = defineCommand({
|
|
|
2047
2092
|
type: "string",
|
|
2048
2093
|
description: "End date for filtering (YYYY-MM-DD)"
|
|
2049
2094
|
},
|
|
2095
|
+
last: {
|
|
2096
|
+
type: "string",
|
|
2097
|
+
alias: "l",
|
|
2098
|
+
description: "Show only the last N days (e.g. --last 7). Shorthand also supported: --last7, --last30, etc."
|
|
2099
|
+
},
|
|
2050
2100
|
compact: {
|
|
2051
2101
|
type: "boolean",
|
|
2052
2102
|
alias: "c",
|
|
@@ -2075,7 +2125,7 @@ var main = defineCommand({
|
|
|
2075
2125
|
// Wrapped-specific options
|
|
2076
2126
|
url: {
|
|
2077
2127
|
type: "string",
|
|
2078
|
-
description: "Custom base URL for
|
|
2128
|
+
description: "Custom base URL for shareable links/pages"
|
|
2079
2129
|
},
|
|
2080
2130
|
"no-short": {
|
|
2081
2131
|
type: "boolean",
|
|
@@ -2113,6 +2163,23 @@ var main = defineCommand({
|
|
|
2113
2163
|
}
|
|
2114
2164
|
});
|
|
2115
2165
|
async function runUsage(args, config) {
|
|
2166
|
+
const requestedSince = args.since;
|
|
2167
|
+
const requestedUntil = args.until;
|
|
2168
|
+
const requestedLastDays = parseLastDaysFlag(args);
|
|
2169
|
+
let since = requestedSince;
|
|
2170
|
+
let until = requestedUntil;
|
|
2171
|
+
if (requestedLastDays && !since) {
|
|
2172
|
+
const anchorStr = until || formatLocalDateYYYYMMDD(/* @__PURE__ */ new Date());
|
|
2173
|
+
const anchor = parseLocalDateYYYYMMDD(anchorStr);
|
|
2174
|
+
if (!anchor) {
|
|
2175
|
+
console.error(`Error: Invalid --until date "${anchorStr}". Expected YYYY-MM-DD.`);
|
|
2176
|
+
process.exit(1);
|
|
2177
|
+
}
|
|
2178
|
+
const start = new Date(anchor);
|
|
2179
|
+
start.setDate(start.getDate() - (requestedLastDays - 1));
|
|
2180
|
+
since = formatLocalDateYYYYMMDD(start);
|
|
2181
|
+
if (!until) until = anchorStr;
|
|
2182
|
+
}
|
|
2116
2183
|
let aggregation = "daily";
|
|
2117
2184
|
if (args.sessions) aggregation = "session";
|
|
2118
2185
|
else if (args.monthly) aggregation = "monthly";
|
|
@@ -2122,14 +2189,27 @@ async function runUsage(args, config) {
|
|
|
2122
2189
|
const stats = await spinner.whilePromise(
|
|
2123
2190
|
loadUsageStats({
|
|
2124
2191
|
aggregation,
|
|
2125
|
-
since
|
|
2126
|
-
until
|
|
2192
|
+
since,
|
|
2193
|
+
until,
|
|
2127
2194
|
codexOnly: args.codex,
|
|
2128
2195
|
combined: args.combined,
|
|
2129
2196
|
projectFilter: args.project ? process.cwd() : void 0
|
|
2130
2197
|
})
|
|
2131
2198
|
);
|
|
2132
2199
|
if (!stats) {
|
|
2200
|
+
if (requestedSince || requestedUntil || requestedLastDays) {
|
|
2201
|
+
const rangeStr = `${since || "(start)"} to ${until || "(end)"}`;
|
|
2202
|
+
console.error(`Error: No usage data found for date range ${rangeStr}.`);
|
|
2203
|
+
if (args.codex) {
|
|
2204
|
+
console.error("Checked: ~/.codex/sessions and ~/.codex/archived_sessions");
|
|
2205
|
+
} else if (args.combined) {
|
|
2206
|
+
console.error("Checked: ~/.claude/projects and ~/.codex/sessions (plus archived sessions)");
|
|
2207
|
+
} else {
|
|
2208
|
+
console.error("Checked: ~/.claude/projects");
|
|
2209
|
+
}
|
|
2210
|
+
console.error("Try widening the range or removing the date filter.");
|
|
2211
|
+
process.exit(1);
|
|
2212
|
+
}
|
|
2133
2213
|
if (args.codex) {
|
|
2134
2214
|
console.error("Error: OpenAI Codex data not found at ~/.codex");
|
|
2135
2215
|
console.error("Make sure you have used the Codex CLI at least once.");
|