kiro-proxy 0.1.15
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 +90 -0
- package/logger.js +82 -0
- package/package.json +28 -0
- package/q-client.js +501 -0
- package/server.js +377 -0
- package/token-counter.js +33 -0
- package/token-reader.js +246 -0
- package/usage-tracker.js +112 -0
package/usage-tracker.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
|
|
5
|
+
const USAGE_DIR = path.join(os.homedir(), '.kiro-proxy', 'usage');
|
|
6
|
+
|
|
7
|
+
function dateStr(d) {
|
|
8
|
+
const y = d.getFullYear();
|
|
9
|
+
const m = String(d.getMonth() + 1).padStart(2, '0');
|
|
10
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
11
|
+
return { y, m, day };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function filePath(date) {
|
|
15
|
+
const { y, m, day } = dateStr(date);
|
|
16
|
+
return path.join(USAGE_DIR, String(y), m, `${day}.jsonl`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function ensureDir(filePath) {
|
|
20
|
+
const dir = path.dirname(filePath);
|
|
21
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function recordUsage(credits, model) {
|
|
25
|
+
const fp = filePath(new Date());
|
|
26
|
+
ensureDir(fp);
|
|
27
|
+
const entry = JSON.stringify({ ts: Date.now(), credits, model }) + '\n';
|
|
28
|
+
fs.appendFileSync(fp, entry);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function readFile(fp) {
|
|
32
|
+
if (!fs.existsSync(fp)) return [];
|
|
33
|
+
const lines = fs.readFileSync(fp, 'utf8').split('\n').filter(Boolean);
|
|
34
|
+
const entries = [];
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
try { entries.push(JSON.parse(line)); } catch {}
|
|
37
|
+
}
|
|
38
|
+
return entries;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function daysBetween(since) {
|
|
42
|
+
const dates = [];
|
|
43
|
+
const d = new Date(since);
|
|
44
|
+
d.setHours(0, 0, 0, 0);
|
|
45
|
+
const now = new Date();
|
|
46
|
+
now.setHours(23, 59, 59, 999);
|
|
47
|
+
while (d <= now) {
|
|
48
|
+
dates.push(new Date(d));
|
|
49
|
+
d.setDate(d.getDate() + 1);
|
|
50
|
+
}
|
|
51
|
+
return dates;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function readEntries(since) {
|
|
55
|
+
const entries = [];
|
|
56
|
+
for (const d of daysBetween(since)) {
|
|
57
|
+
for (const e of readFile(filePath(d))) {
|
|
58
|
+
if (e.ts >= since) entries.push(e);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return entries;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function readAllEntries() {
|
|
65
|
+
const entries = [];
|
|
66
|
+
if (!fs.existsSync(USAGE_DIR)) return entries;
|
|
67
|
+
for (const y of fs.readdirSync(USAGE_DIR)) {
|
|
68
|
+
const yDir = path.join(USAGE_DIR, y);
|
|
69
|
+
if (!fs.statSync(yDir).isDirectory()) continue;
|
|
70
|
+
for (const m of fs.readdirSync(yDir)) {
|
|
71
|
+
const mDir = path.join(yDir, m);
|
|
72
|
+
if (!fs.statSync(mDir).isDirectory()) continue;
|
|
73
|
+
for (const f of fs.readdirSync(mDir)) {
|
|
74
|
+
if (f.endsWith('.jsonl')) entries.push(...readFile(path.join(mDir, f)));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return entries;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function summarize(entries) {
|
|
82
|
+
let total = 0;
|
|
83
|
+
const byModel = {};
|
|
84
|
+
for (const e of entries) {
|
|
85
|
+
total += e.credits || 0;
|
|
86
|
+
const m = e.model || 'unknown';
|
|
87
|
+
byModel[m] = (byModel[m] || 0) + (e.credits || 0);
|
|
88
|
+
}
|
|
89
|
+
return { requests: entries.length, credits: +total.toFixed(6), byModel };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function startOfDay() {
|
|
93
|
+
const d = new Date();
|
|
94
|
+
d.setHours(0, 0, 0, 0);
|
|
95
|
+
return d.getTime();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function queryUsage(period) {
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const ranges = {
|
|
101
|
+
today: startOfDay(),
|
|
102
|
+
'7d': now - 7 * 86400000,
|
|
103
|
+
'30d': now - 30 * 86400000,
|
|
104
|
+
};
|
|
105
|
+
if (period === 'all') return { period, ...summarize(readAllEntries()) };
|
|
106
|
+
const since = ranges[period] ?? ranges.today;
|
|
107
|
+
return { period: period || 'today', ...summarize(readEntries(since)) };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function todaySummary() {
|
|
111
|
+
return queryUsage('today');
|
|
112
|
+
}
|