gcusage 0.1.0 → 0.1.2

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.
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isPeriodProvided = isPeriodProvided;
4
+ exports.resolveRange = resolveRange;
5
+ exports.applyUntilClamp = applyUntilClamp;
6
+ const time_1 = require("./utils/time");
7
+ function isPeriodProvided(args) {
8
+ return args.some((arg) => arg === "--period" || arg.startsWith("--period="));
9
+ }
10
+ function resolveRange(period, periodWasProvided, sinceMs, untilMs) {
11
+ const now = new Date();
12
+ if (period === "session") {
13
+ const start = (0, time_1.startOfDay)(now).getTime();
14
+ const end = (0, time_1.endOfDay)(now).getTime();
15
+ return applyUntilClamp({ sinceMs: start, untilMs: end }, untilMs);
16
+ }
17
+ if (!periodWasProvided && sinceMs === null && untilMs === null) {
18
+ const end = (0, time_1.endOfDay)(now).getTime();
19
+ const startDate = new Date(now.getTime());
20
+ startDate.setDate(startDate.getDate() - 5);
21
+ const start = (0, time_1.startOfDay)(startDate).getTime();
22
+ return { sinceMs: start, untilMs: end };
23
+ }
24
+ if (period === "day") {
25
+ if (sinceMs === null && untilMs === null) {
26
+ const start = (0, time_1.startOfDay)(now).getTime();
27
+ const end = (0, time_1.endOfDay)(now).getTime();
28
+ return { sinceMs: start, untilMs: end };
29
+ }
30
+ return { sinceMs, untilMs };
31
+ }
32
+ if (period === "week") {
33
+ if (sinceMs !== null) {
34
+ const start = (0, time_1.startOfDay)(new Date(sinceMs)).getTime();
35
+ const end = (0, time_1.endOfDay)(new Date(start + 6 * 86400000)).getTime();
36
+ return applyUntilClamp({ sinceMs: start, untilMs: end }, untilMs);
37
+ }
38
+ const start = (0, time_1.startOfWeekMonday)(now).getTime();
39
+ const end = (0, time_1.endOfDay)(new Date(start + 6 * 86400000)).getTime();
40
+ return applyUntilClamp({ sinceMs: start, untilMs: end }, untilMs);
41
+ }
42
+ if (period === "month") {
43
+ const base = sinceMs !== null ? new Date(sinceMs) : now;
44
+ const start = new Date(base.getFullYear(), base.getMonth(), 1);
45
+ const end = new Date(base.getFullYear(), base.getMonth() + 1, 0);
46
+ return applyUntilClamp({ sinceMs: (0, time_1.startOfDay)(start).getTime(), untilMs: (0, time_1.endOfDay)(end).getTime() }, untilMs);
47
+ }
48
+ return { sinceMs, untilMs };
49
+ }
50
+ function applyUntilClamp(range, untilMs) {
51
+ if (untilMs === null)
52
+ return range;
53
+ if (range.untilMs === null || untilMs < range.untilMs) {
54
+ return { sinceMs: range.sinceMs, untilMs };
55
+ }
56
+ return range;
57
+ }
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderTable = renderTable;
4
+ exports.renderDailyTable = renderDailyTable;
5
+ exports.renderSessionTable = renderSessionTable;
6
+ exports.colorize = colorize;
7
+ exports.colorizeLines = colorizeLines;
8
+ exports.applyColor = applyColor;
9
+ exports.renderTitleBlock = renderTitleBlock;
10
+ exports.buildRangeText = buildRangeText;
11
+ exports.resolveDateRange = resolveDateRange;
12
+ const messages_1 = require("../../messages");
13
+ const format_1 = require("../utils/format");
14
+ const aggregate_1 = require("../aggregate");
15
+ const time_1 = require("../utils/time");
16
+ function renderTable(result, period) {
17
+ if (result.table.length === 0) {
18
+ console.log(messages_1.MESSAGES.NO_MATCHING);
19
+ return;
20
+ }
21
+ if (period === "session") {
22
+ const rows = result.table;
23
+ renderSessionTable(rows, result.range);
24
+ return;
25
+ }
26
+ const rows = result.table;
27
+ renderDailyTable(rows, result.range);
28
+ }
29
+ function renderDailyTable(rows, range) {
30
+ const headers = [
31
+ messages_1.MESSAGES.HEADER_DATE,
32
+ messages_1.MESSAGES.HEADER_MODELS,
33
+ messages_1.MESSAGES.HEADER_INPUT,
34
+ messages_1.MESSAGES.HEADER_OUTPUT,
35
+ messages_1.MESSAGES.HEADER_THOUGHT,
36
+ messages_1.MESSAGES.HEADER_CACHE,
37
+ messages_1.MESSAGES.HEADER_TOOL,
38
+ messages_1.MESSAGES.HEADER_TOTAL_TOKENS
39
+ ];
40
+ const widths = headers.map((h) => h.length);
41
+ const totals = { input: 0, output: 0, thought: 0, cache: 0, tool: 0 };
42
+ for (const row of rows) {
43
+ const modelsText = Array.from(row.models);
44
+ widths[0] = Math.max(widths[0], row.date.length);
45
+ widths[1] = Math.max(widths[1], (0, format_1.maxLineWidth)(modelsText));
46
+ widths[2] = Math.max(widths[2], (0, format_1.formatNumber)(row.input).length);
47
+ widths[3] = Math.max(widths[3], (0, format_1.formatNumber)(row.output).length);
48
+ widths[4] = Math.max(widths[4], (0, format_1.formatNumber)(row.thought).length);
49
+ widths[5] = Math.max(widths[5], (0, format_1.formatNumber)(row.cache).length);
50
+ widths[6] = Math.max(widths[6], (0, format_1.formatNumber)(row.tool).length);
51
+ widths[7] = Math.max(widths[7], (0, format_1.formatNumber)((0, aggregate_1.sumAll)(row)).length);
52
+ totals.input += row.input;
53
+ totals.output += row.output;
54
+ totals.thought += row.thought;
55
+ totals.cache += row.cache;
56
+ totals.tool += row.tool;
57
+ }
58
+ const lines = [];
59
+ lines.push(...renderTitleBlock(rows, range));
60
+ lines.push(colorize(headers, "header", widths));
61
+ lines.push("");
62
+ for (const row of rows) {
63
+ const modelLines = Array.from(row.models);
64
+ lines.push(...(0, format_1.formatRowMulti)([
65
+ [row.date],
66
+ modelLines.length > 0 ? modelLines : [""],
67
+ [(0, format_1.formatNumber)(row.input)],
68
+ [(0, format_1.formatNumber)(row.output)],
69
+ [(0, format_1.formatNumber)(row.thought)],
70
+ [(0, format_1.formatNumber)(row.cache)],
71
+ [(0, format_1.formatNumber)(row.tool)],
72
+ [(0, format_1.formatNumber)((0, aggregate_1.sumAll)(row))]
73
+ ], widths, [false, false, true, true, true, true, true, true]));
74
+ lines.push("");
75
+ }
76
+ const totalCells = [
77
+ [messages_1.MESSAGES.TOTAL_LABEL],
78
+ [""],
79
+ [(0, format_1.formatCompact)(totals.input)],
80
+ [(0, format_1.formatCompact)(totals.output)],
81
+ [(0, format_1.formatCompact)(totals.thought)],
82
+ [(0, format_1.formatCompact)(totals.cache)],
83
+ [(0, format_1.formatCompact)(totals.tool)],
84
+ [(0, format_1.formatCompact)((0, aggregate_1.sumTotals)(totals))]
85
+ ];
86
+ const totalLines = (0, format_1.formatRowMulti)(totalCells, widths, [false, false, true, true, true, true, true, true]);
87
+ lines.push(colorizeLines(totalLines, "total"));
88
+ lines.push("");
89
+ console.log(lines.join("\n"));
90
+ }
91
+ function renderSessionTable(rows, range) {
92
+ const headers = [
93
+ messages_1.MESSAGES.HEADER_DATE,
94
+ messages_1.MESSAGES.HEADER_SESSION,
95
+ messages_1.MESSAGES.HEADER_MODELS,
96
+ messages_1.MESSAGES.HEADER_INPUT,
97
+ messages_1.MESSAGES.HEADER_OUTPUT,
98
+ messages_1.MESSAGES.HEADER_THOUGHT,
99
+ messages_1.MESSAGES.HEADER_CACHE,
100
+ messages_1.MESSAGES.HEADER_TOOL,
101
+ messages_1.MESSAGES.HEADER_TOTAL_TOKENS
102
+ ];
103
+ const widths = headers.map((h) => h.length);
104
+ const totals = { input: 0, output: 0, thought: 0, cache: 0, tool: 0 };
105
+ for (const row of rows) {
106
+ const modelsText = Array.from(row.models);
107
+ widths[0] = Math.max(widths[0], row.date.length);
108
+ widths[1] = Math.max(widths[1], row.sessionId.length);
109
+ widths[2] = Math.max(widths[2], (0, format_1.maxLineWidth)(modelsText));
110
+ widths[3] = Math.max(widths[3], (0, format_1.formatNumber)(row.input).length);
111
+ widths[4] = Math.max(widths[4], (0, format_1.formatNumber)(row.output).length);
112
+ widths[5] = Math.max(widths[5], (0, format_1.formatNumber)(row.thought).length);
113
+ widths[6] = Math.max(widths[6], (0, format_1.formatNumber)(row.cache).length);
114
+ widths[7] = Math.max(widths[7], (0, format_1.formatNumber)(row.tool).length);
115
+ widths[8] = Math.max(widths[8], (0, format_1.formatNumber)((0, aggregate_1.sumAll)(row)).length);
116
+ totals.input += row.input;
117
+ totals.output += row.output;
118
+ totals.thought += row.thought;
119
+ totals.cache += row.cache;
120
+ totals.tool += row.tool;
121
+ }
122
+ const lines = [];
123
+ lines.push(...renderTitleBlock(rows, range));
124
+ lines.push(colorize(headers, "header", widths));
125
+ lines.push("");
126
+ for (const row of rows) {
127
+ const modelLines = Array.from(row.models);
128
+ lines.push(...(0, format_1.formatRowMulti)([
129
+ [row.date],
130
+ [row.sessionId],
131
+ modelLines.length > 0 ? modelLines : [""],
132
+ [(0, format_1.formatNumber)(row.input)],
133
+ [(0, format_1.formatNumber)(row.output)],
134
+ [(0, format_1.formatNumber)(row.thought)],
135
+ [(0, format_1.formatNumber)(row.cache)],
136
+ [(0, format_1.formatNumber)(row.tool)],
137
+ [(0, format_1.formatNumber)((0, aggregate_1.sumAll)(row))]
138
+ ], widths, [false, false, false, true, true, true, true, true, true]));
139
+ lines.push("");
140
+ }
141
+ const totalCells = [
142
+ [messages_1.MESSAGES.TOTAL_LABEL],
143
+ [""],
144
+ [""],
145
+ [(0, format_1.formatCompact)(totals.input)],
146
+ [(0, format_1.formatCompact)(totals.output)],
147
+ [(0, format_1.formatCompact)(totals.thought)],
148
+ [(0, format_1.formatCompact)(totals.cache)],
149
+ [(0, format_1.formatCompact)(totals.tool)],
150
+ [(0, format_1.formatCompact)((0, aggregate_1.sumTotals)(totals))]
151
+ ];
152
+ const totalLines = (0, format_1.formatRowMulti)(totalCells, widths, [false, false, false, true, true, true, true, true, true]);
153
+ lines.push(colorizeLines(totalLines, "total"));
154
+ lines.push("");
155
+ console.log(lines.join("\n"));
156
+ }
157
+ function colorize(headers, kind, widths) {
158
+ const raw = (0, format_1.formatRow)(headers, widths);
159
+ return applyColor(raw, kind);
160
+ }
161
+ function colorizeLines(lines, kind) {
162
+ return applyColor(lines.join("\n"), kind);
163
+ }
164
+ function applyColor(text, kind) {
165
+ const code = kind === "header" ? "\u001b[36m" : "\u001b[33m";
166
+ const reset = "\u001b[0m";
167
+ return `${code}${text}${reset}`;
168
+ }
169
+ function renderTitleBlock(rows, range) {
170
+ const rangeText = buildRangeText(rows, range);
171
+ const title = rangeText ? `${messages_1.MESSAGES.REPORT_TITLE} - ${rangeText}` : messages_1.MESSAGES.REPORT_TITLE;
172
+ const border = `+${"-".repeat(title.length + 2)}+`;
173
+ const line = `| ${title} |`;
174
+ return ["", applyColor(border, "header"), applyColor(line, "header"), applyColor(border, "header"), ""];
175
+ }
176
+ function buildRangeText(rows, range) {
177
+ const [start, end] = resolveDateRange(rows, range);
178
+ if (!start || !end)
179
+ return "";
180
+ return start === end ? start : `${start}${messages_1.MESSAGES.RANGE_SEP}${end}`;
181
+ }
182
+ function resolveDateRange(rows, range) {
183
+ if (range.sinceMs !== null && range.untilMs !== null) {
184
+ const start = (0, time_1.toDateKey)(range.sinceMs);
185
+ const end = (0, time_1.toDateKey)(range.untilMs);
186
+ return [start, end];
187
+ }
188
+ const dates = rows.map((r) => r.date).sort();
189
+ if (dates.length === 0)
190
+ return [null, null];
191
+ return [dates[0], dates[dates.length - 1]];
192
+ }
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.run = run;
7
+ const os_1 = __importDefault(require("os"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const messages_1 = require("../messages");
10
+ const aggregate_1 = require("./aggregate");
11
+ const logs_1 = require("./logs");
12
+ const range_1 = require("./range");
13
+ async function run(activePeriod, periodWasProvided, rawSince, rawUntil, modelFilter, typeFilter) {
14
+ const logFiles = await (0, logs_1.findLogFiles)();
15
+ if (logFiles.length === 0) {
16
+ const logPath = path_1.default.join(os_1.default.homedir(), ".gemini", "telemetry.log");
17
+ console.error(`${messages_1.MESSAGES.NO_LOG_FOUND}${logPath}`);
18
+ return { json: [], table: [], range: { sinceMs: null, untilMs: null } };
19
+ }
20
+ const points = [];
21
+ for (const file of logFiles) {
22
+ const filePoints = await (0, logs_1.parseLogFile)(file);
23
+ points.push(...filePoints);
24
+ }
25
+ const range = (0, range_1.resolveRange)(activePeriod, periodWasProvided, rawSince, rawUntil);
26
+ const filteredByType = points.filter((p) => {
27
+ if (modelFilter && p.model !== modelFilter)
28
+ return false;
29
+ if (typeFilter && p.type !== typeFilter)
30
+ return false;
31
+ return true;
32
+ });
33
+ const summaries = (0, aggregate_1.buildSessionSummaries)(filteredByType).filter((s) => {
34
+ if (range.sinceMs !== null && s.sessionStartMs < range.sinceMs)
35
+ return false;
36
+ if (range.untilMs !== null && s.sessionStartMs > range.untilMs)
37
+ return false;
38
+ return true;
39
+ });
40
+ if (activePeriod === "session") {
41
+ const table = summaries.map((s) => (0, aggregate_1.toSessionTotals)(s));
42
+ const json = table.map((row) => ({
43
+ date: row.date,
44
+ session: row.sessionId,
45
+ models: Array.from(row.models),
46
+ input: Math.round(row.input),
47
+ output: Math.round(row.output),
48
+ thought: Math.round(row.thought),
49
+ cache: Math.round(row.cache),
50
+ tool: Math.round(row.tool)
51
+ }));
52
+ return { json, table, range };
53
+ }
54
+ const table = (0, aggregate_1.aggregateSessionsToDay)(summaries);
55
+ const json = table.map((row) => ({
56
+ date: row.date,
57
+ models: Array.from(row.models),
58
+ input: Math.round(row.input),
59
+ output: Math.round(row.output),
60
+ thought: Math.round(row.thought),
61
+ cache: Math.round(row.cache),
62
+ tool: Math.round(row.tool)
63
+ }));
64
+ return { json, table, range };
65
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatRow = formatRow;
4
+ exports.formatRowMulti = formatRowMulti;
5
+ exports.maxLineWidth = maxLineWidth;
6
+ exports.formatNumber = formatNumber;
7
+ exports.formatCompact = formatCompact;
8
+ function formatRow(cells, widths, align) {
9
+ return cells
10
+ .map((cell, i) => {
11
+ const width = widths[i];
12
+ if (align && align[i]) {
13
+ return cell.padStart(width);
14
+ }
15
+ return cell.padEnd(width);
16
+ })
17
+ .join(" ");
18
+ }
19
+ function formatRowMulti(cells, widths, align) {
20
+ const height = cells.reduce((max, col) => Math.max(max, col.length), 1);
21
+ const lines = [];
22
+ for (let rowIndex = 0; rowIndex < height; rowIndex += 1) {
23
+ const rowCells = cells.map((col) => (rowIndex < col.length ? col[rowIndex] : ""));
24
+ lines.push(formatRow(rowCells, widths, align));
25
+ }
26
+ return lines;
27
+ }
28
+ function maxLineWidth(lines) {
29
+ if (lines.length === 0)
30
+ return 0;
31
+ return lines.reduce((max, line) => Math.max(max, line.length), 0);
32
+ }
33
+ function formatNumber(value) {
34
+ return Math.round(value).toLocaleString("en-US");
35
+ }
36
+ function formatCompact(value) {
37
+ const abs = Math.abs(value);
38
+ if (abs >= 1e9)
39
+ return `${(value / 1e9).toFixed(2)}B`;
40
+ if (abs >= 1e6)
41
+ return `${(value / 1e6).toFixed(2)}M`;
42
+ if (abs >= 1e3)
43
+ return `${(value / 1e3).toFixed(2)}k`;
44
+ return formatNumber(value);
45
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizePeriod = normalizePeriod;
4
+ function normalizePeriod(value) {
5
+ if (value === "day" || value === "week" || value === "month" || value === "session")
6
+ return value;
7
+ return null;
8
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTimeSpec = parseTimeSpec;
4
+ exports.startOfDay = startOfDay;
5
+ exports.endOfDay = endOfDay;
6
+ exports.toDateKey = toDateKey;
7
+ exports.pad2 = pad2;
8
+ exports.startOfWeekMonday = startOfWeekMonday;
9
+ const messages_1 = require("../../messages");
10
+ function parseTimeSpec(input, kind) {
11
+ if (typeof input !== "string")
12
+ return null;
13
+ const raw = input.trim().toLowerCase();
14
+ if (!raw)
15
+ return null;
16
+ const now = new Date();
17
+ if (raw === "today") {
18
+ return kind === "since" ? startOfDay(now).getTime() : endOfDay(now).getTime();
19
+ }
20
+ if (raw === "yesterday") {
21
+ const d = new Date(now.getTime() - 86400000);
22
+ return kind === "since" ? startOfDay(d).getTime() : endOfDay(d).getTime();
23
+ }
24
+ const relMatch = raw.match(/^(\d+)([dh])$/);
25
+ if (relMatch) {
26
+ const amount = Number(relMatch[1]);
27
+ const unit = relMatch[2];
28
+ if (!Number.isNaN(amount)) {
29
+ const delta = unit === "d" ? amount * 86400000 : amount * 3600000;
30
+ return now.getTime() - delta;
31
+ }
32
+ }
33
+ const parsed = new Date(raw);
34
+ if (!Number.isNaN(parsed.getTime())) {
35
+ if (/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
36
+ return kind === "since" ? startOfDay(parsed).getTime() : endOfDay(parsed).getTime();
37
+ }
38
+ return parsed.getTime();
39
+ }
40
+ console.error((0, messages_1.buildInvalidTimeMessage)(input));
41
+ process.exit(1);
42
+ }
43
+ function startOfDay(d) {
44
+ const tmp = new Date(d.getTime());
45
+ tmp.setHours(0, 0, 0, 0);
46
+ return tmp;
47
+ }
48
+ function endOfDay(d) {
49
+ const tmp = new Date(d.getTime());
50
+ tmp.setHours(23, 59, 59, 999);
51
+ return tmp;
52
+ }
53
+ function toDateKey(timestampMs) {
54
+ const date = new Date(timestampMs);
55
+ const year = date.getFullYear();
56
+ const month = pad2(date.getMonth() + 1);
57
+ const day = pad2(date.getDate());
58
+ return `${year}-${month}-${day}`;
59
+ }
60
+ function pad2(n) {
61
+ return n < 10 ? `0${n}` : String(n);
62
+ }
63
+ function startOfWeekMonday(date) {
64
+ const d = new Date(date.getTime());
65
+ const day = (d.getDay() + 6) % 7;
66
+ d.setDate(d.getDate() - day);
67
+ d.setHours(0, 0, 0, 0);
68
+ return d;
69
+ }