hacklab 0.0.2 → 0.3.1

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 (154) hide show
  1. package/README.md +44 -3
  2. package/bin/ddd +19 -0
  3. package/dist/commands/brag.d.ts +3 -6
  4. package/dist/commands/brag.d.ts.map +1 -1
  5. package/dist/commands/brag.js +68 -299
  6. package/dist/commands/brag.js.map +1 -1
  7. package/dist/commands/config.d.ts +2 -0
  8. package/dist/commands/config.d.ts.map +1 -0
  9. package/dist/commands/config.js +48 -0
  10. package/dist/commands/config.js.map +1 -0
  11. package/dist/commands/drop.d.ts +2 -0
  12. package/dist/commands/drop.d.ts.map +1 -0
  13. package/dist/commands/drop.js +29 -0
  14. package/dist/commands/drop.js.map +1 -0
  15. package/dist/commands/exam.d.ts +5 -0
  16. package/dist/commands/exam.d.ts.map +1 -0
  17. package/dist/commands/exam.js +224 -0
  18. package/dist/commands/exam.js.map +1 -0
  19. package/dist/commands/join.d.ts +10 -9
  20. package/dist/commands/join.d.ts.map +1 -1
  21. package/dist/commands/join.js +213 -285
  22. package/dist/commands/join.js.map +1 -1
  23. package/dist/commands/login.d.ts +1 -15
  24. package/dist/commands/login.d.ts.map +1 -1
  25. package/dist/commands/login.js +69 -133
  26. package/dist/commands/login.js.map +1 -1
  27. package/dist/commands/scan-profile.d.ts +33 -0
  28. package/dist/commands/scan-profile.d.ts.map +1 -0
  29. package/dist/commands/scan-profile.js +279 -0
  30. package/dist/commands/scan-profile.js.map +1 -0
  31. package/dist/commands/sync.d.ts +2 -0
  32. package/dist/commands/sync.d.ts.map +1 -0
  33. package/dist/commands/sync.js +55 -0
  34. package/dist/commands/sync.js.map +1 -0
  35. package/dist/commands/whoami.d.ts +1 -3
  36. package/dist/commands/whoami.d.ts.map +1 -1
  37. package/dist/commands/whoami.js +10 -37
  38. package/dist/commands/whoami.js.map +1 -1
  39. package/dist/config.d.ts +7 -0
  40. package/dist/config.d.ts.map +1 -0
  41. package/dist/config.js +18 -0
  42. package/dist/config.js.map +1 -0
  43. package/dist/dd.d.ts +3 -0
  44. package/dist/dd.d.ts.map +1 -0
  45. package/dist/dd.js +28 -0
  46. package/dist/dd.js.map +1 -0
  47. package/dist/index.js +117 -112
  48. package/dist/index.js.map +1 -1
  49. package/dist/project-brag.d.ts +58 -0
  50. package/dist/project-brag.d.ts.map +1 -0
  51. package/dist/project-brag.js +270 -0
  52. package/dist/project-brag.js.map +1 -0
  53. package/dist/scanners/index.d.ts +24 -0
  54. package/dist/scanners/index.d.ts.map +1 -0
  55. package/dist/scanners/index.js +543 -0
  56. package/dist/scanners/index.js.map +1 -0
  57. package/dist/scanners/util.d.ts +83 -0
  58. package/dist/scanners/util.d.ts.map +1 -0
  59. package/dist/scanners/util.js +129 -0
  60. package/dist/scanners/util.js.map +1 -0
  61. package/dist/session.d.ts +17 -13
  62. package/dist/session.d.ts.map +1 -1
  63. package/dist/session.js +46 -155
  64. package/dist/session.js.map +1 -1
  65. package/dist/share-card.d.ts +29 -0
  66. package/dist/share-card.d.ts.map +1 -0
  67. package/dist/share-card.js +401 -0
  68. package/dist/share-card.js.map +1 -0
  69. package/dist/sync.d.ts +64 -0
  70. package/dist/sync.d.ts.map +1 -0
  71. package/dist/sync.js +805 -0
  72. package/dist/sync.js.map +1 -0
  73. package/dist/ui.d.ts +10 -0
  74. package/dist/ui.d.ts.map +1 -0
  75. package/dist/ui.js +21 -0
  76. package/dist/ui.js.map +1 -0
  77. package/dist/utils/openBrowser.js.map +1 -1
  78. package/package.json +36 -29
  79. package/dist/api/client.d.ts +0 -150
  80. package/dist/api/client.d.ts.map +0 -1
  81. package/dist/api/client.js +0 -246
  82. package/dist/api/client.js.map +0 -1
  83. package/dist/commands/admin-waitlist.d.ts +0 -12
  84. package/dist/commands/admin-waitlist.d.ts.map +0 -1
  85. package/dist/commands/admin-waitlist.js +0 -96
  86. package/dist/commands/admin-waitlist.js.map +0 -1
  87. package/dist/commands/brag.utils.d.ts +0 -12
  88. package/dist/commands/brag.utils.d.ts.map +0 -1
  89. package/dist/commands/brag.utils.js +0 -43
  90. package/dist/commands/brag.utils.js.map +0 -1
  91. package/dist/commands/essay.d.ts +0 -18
  92. package/dist/commands/essay.d.ts.map +0 -1
  93. package/dist/commands/essay.js +0 -117
  94. package/dist/commands/essay.js.map +0 -1
  95. package/dist/commands/explore.d.ts +0 -9
  96. package/dist/commands/explore.d.ts.map +0 -1
  97. package/dist/commands/explore.js +0 -32
  98. package/dist/commands/explore.js.map +0 -1
  99. package/dist/commands/init.d.ts +0 -16
  100. package/dist/commands/init.d.ts.map +0 -1
  101. package/dist/commands/init.js +0 -237
  102. package/dist/commands/init.js.map +0 -1
  103. package/dist/commands/link.d.ts +0 -17
  104. package/dist/commands/link.d.ts.map +0 -1
  105. package/dist/commands/link.js +0 -36
  106. package/dist/commands/link.js.map +0 -1
  107. package/dist/commands/login.utils.d.ts +0 -3
  108. package/dist/commands/login.utils.d.ts.map +0 -1
  109. package/dist/commands/login.utils.js +0 -13
  110. package/dist/commands/login.utils.js.map +0 -1
  111. package/dist/commands/new.d.ts +0 -15
  112. package/dist/commands/new.d.ts.map +0 -1
  113. package/dist/commands/new.js +0 -172
  114. package/dist/commands/new.js.map +0 -1
  115. package/dist/commands/new.utils.d.ts +0 -7
  116. package/dist/commands/new.utils.d.ts.map +0 -1
  117. package/dist/commands/new.utils.js +0 -50
  118. package/dist/commands/new.utils.js.map +0 -1
  119. package/dist/commands/onboard.d.ts +0 -10
  120. package/dist/commands/onboard.d.ts.map +0 -1
  121. package/dist/commands/onboard.js +0 -93
  122. package/dist/commands/onboard.js.map +0 -1
  123. package/dist/commands/publish.d.ts +0 -8
  124. package/dist/commands/publish.d.ts.map +0 -1
  125. package/dist/commands/publish.js +0 -47
  126. package/dist/commands/publish.js.map +0 -1
  127. package/dist/commands/tui.d.ts +0 -12
  128. package/dist/commands/tui.d.ts.map +0 -1
  129. package/dist/commands/tui.js +0 -112
  130. package/dist/commands/tui.js.map +0 -1
  131. package/dist/help-format.d.ts +0 -4
  132. package/dist/help-format.d.ts.map +0 -1
  133. package/dist/help-format.js +0 -30
  134. package/dist/help-format.js.map +0 -1
  135. package/dist/lab/config.d.ts +0 -32
  136. package/dist/lab/config.d.ts.map +0 -1
  137. package/dist/lab/config.js +0 -148
  138. package/dist/lab/config.js.map +0 -1
  139. package/dist/lab/contentStatus.d.ts +0 -6
  140. package/dist/lab/contentStatus.d.ts.map +0 -1
  141. package/dist/lab/contentStatus.js +0 -19
  142. package/dist/lab/contentStatus.js.map +0 -1
  143. package/dist/ui/banner.d.ts +0 -2
  144. package/dist/ui/banner.d.ts.map +0 -1
  145. package/dist/ui/banner.js +0 -22
  146. package/dist/ui/banner.js.map +0 -1
  147. package/dist/utils/findRepoRoot.d.ts +0 -2
  148. package/dist/utils/findRepoRoot.d.ts.map +0 -1
  149. package/dist/utils/findRepoRoot.js +0 -17
  150. package/dist/utils/findRepoRoot.js.map +0 -1
  151. package/dist/utils/pathExists.d.ts +0 -2
  152. package/dist/utils/pathExists.d.ts.map +0 -1
  153. package/dist/utils/pathExists.js +0 -11
  154. package/dist/utils/pathExists.js.map +0 -1
@@ -0,0 +1,543 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { loadConfig } from '../config.js';
5
+ import { emptyResult, findFiles, TokenCollector, toDateStr, } from './util.js';
6
+ export * from './util.js';
7
+ // One self-contained scanner per tool. Each returns a uniform ScanResult and
8
+ // keeps its own state (via TokenCollector), so they're pure and run in parallel.
9
+ export async function scanClaudeCode() {
10
+ const dir = join(homedir(), '.claude', 'projects');
11
+ try {
12
+ await stat(dir);
13
+ }
14
+ catch {
15
+ return emptyResult('claude_code');
16
+ }
17
+ const files = await findFiles(dir, '.jsonl');
18
+ const collector = new TokenCollector('claude_code');
19
+ for (const filePath of files) {
20
+ try {
21
+ const content = await readFile(filePath, 'utf8');
22
+ for (const line of content.split('\n')) {
23
+ if (!line.trim())
24
+ continue;
25
+ try {
26
+ const parsed = JSON.parse(line);
27
+ const usage = parsed.message?.usage ?? parsed.usage ?? null;
28
+ if (!usage)
29
+ continue;
30
+ const tokens = (usage.input_tokens ?? 0) +
31
+ (usage.output_tokens ?? 0) +
32
+ (usage.cache_creation_input_tokens ?? 0) +
33
+ (usage.cache_read_input_tokens ?? 0);
34
+ if (tokens <= 0)
35
+ continue;
36
+ let date;
37
+ let hour = null;
38
+ if (parsed.timestamp) {
39
+ const d = new Date(typeof parsed.timestamp === 'string' &&
40
+ /^\d+$/.test(parsed.timestamp)
41
+ ? Number(parsed.timestamp)
42
+ : parsed.timestamp);
43
+ date = toDateStr(d);
44
+ hour = d.getHours();
45
+ }
46
+ else {
47
+ date = toDateStr((await stat(filePath)).mtime);
48
+ }
49
+ const model = parsed.message?.model ?? '';
50
+ collector.addDaily(date, model, tokens, 1);
51
+ if (hour !== null)
52
+ collector.addHourly(date, hour, model, tokens, 1);
53
+ }
54
+ catch {
55
+ // skip malformed lines
56
+ }
57
+ }
58
+ }
59
+ catch {
60
+ // skip unreadable files
61
+ }
62
+ }
63
+ return collector.result();
64
+ }
65
+ export async function scanCodex() {
66
+ const dir = join(homedir(), '.codex', 'sessions');
67
+ try {
68
+ await stat(dir);
69
+ }
70
+ catch {
71
+ return emptyResult('codex');
72
+ }
73
+ const files = await findFiles(dir, '.jsonl');
74
+ const collector = new TokenCollector('codex');
75
+ for (const filePath of files) {
76
+ try {
77
+ const content = await readFile(filePath, 'utf8');
78
+ // Date from path: .codex/sessions/YYYY/MM/DD/file.jsonl
79
+ const relPath = filePath.slice(dir.length + 1);
80
+ const parts = relPath.split('/');
81
+ let date;
82
+ if (parts.length >= 3) {
83
+ date = `${parts[0]}-${parts[1]?.padStart(2, '0')}-${parts[2]?.padStart(2, '0')}`;
84
+ }
85
+ else {
86
+ date = toDateStr((await stat(filePath)).mtime);
87
+ }
88
+ // Codex stores running totals; take the max per file.
89
+ let maxTotal = 0;
90
+ let fileModel = '';
91
+ for (const line of content.split('\n')) {
92
+ if (!line.trim())
93
+ continue;
94
+ try {
95
+ const parsed = JSON.parse(line);
96
+ if (parsed.payload?.model)
97
+ fileModel = parsed.payload.model;
98
+ const usage = parsed.payload?.info?.total_token_usage;
99
+ if (usage) {
100
+ const t = (usage.input_tokens ?? 0) + (usage.output_tokens ?? 0);
101
+ if (t > maxTotal)
102
+ maxTotal = t;
103
+ }
104
+ }
105
+ catch {
106
+ // skip
107
+ }
108
+ }
109
+ if (maxTotal > 0)
110
+ collector.addDaily(date, fileModel, maxTotal, 1);
111
+ }
112
+ catch {
113
+ // skip unreadable files
114
+ }
115
+ }
116
+ return collector.result();
117
+ }
118
+ export async function scanHermes() {
119
+ const dbPath = join(homedir(), '.hermes', 'state.db');
120
+ try {
121
+ await stat(dbPath);
122
+ }
123
+ catch {
124
+ return emptyResult('hermes');
125
+ }
126
+ const { execSync } = await import('node:child_process');
127
+ const collector = new TokenCollector('hermes');
128
+ try {
129
+ const raw = execSync(`sqlite3 -readonly "${dbPath}" "select s.id, coalesce(s.model,'') as model, s.started_at, s.input_tokens, s.output_tokens, s.cache_read_tokens, s.cache_write_tokens, s.reasoning_tokens, coalesce((select count(*) from messages m where m.session_id = s.id and m.role = 'assistant'), 0) as msg_count from sessions s"`, { encoding: 'utf8', timeout: 10000 }).trim();
130
+ if (!raw)
131
+ return emptyResult('hermes');
132
+ for (const row of raw.split('\n')) {
133
+ const [, model, startedAt, inputTokens, outputTokens, cacheRead, cacheWrite, reasoning, msgCount,] = row.split('|');
134
+ const tokens = (Number.parseInt(inputTokens ?? '0', 10) || 0) +
135
+ (Number.parseInt(outputTokens ?? '0', 10) || 0) +
136
+ (Number.parseInt(cacheRead ?? '0', 10) || 0) +
137
+ (Number.parseInt(cacheWrite ?? '0', 10) || 0) +
138
+ (Number.parseInt(reasoning ?? '0', 10) || 0);
139
+ if (tokens <= 0)
140
+ continue;
141
+ const tsSec = Number.parseFloat(startedAt ?? '0');
142
+ if (!Number.isFinite(tsSec) || tsSec <= 0)
143
+ continue;
144
+ const d = new Date(Math.round(tsSec * 1000));
145
+ const date = toDateStr(d);
146
+ const m = (model ?? '').trim();
147
+ const messages = Number.parseInt(msgCount ?? '0', 10) || 1;
148
+ collector.addDaily(date, m, tokens, messages);
149
+ collector.addHourly(date, d.getHours(), m, tokens, messages);
150
+ }
151
+ }
152
+ catch {
153
+ return emptyResult('hermes');
154
+ }
155
+ return collector.result();
156
+ }
157
+ export async function scanOpenclaw() {
158
+ const agentsDir = join(homedir(), '.openclaw', 'agents');
159
+ try {
160
+ await stat(agentsDir);
161
+ }
162
+ catch {
163
+ return emptyResult('openclaw');
164
+ }
165
+ const sessionFiles = [];
166
+ try {
167
+ const agentIds = await readdir(agentsDir, { withFileTypes: true });
168
+ for (const entry of agentIds) {
169
+ if (!entry.isDirectory())
170
+ continue;
171
+ const discovered = await findFiles(join(agentsDir, entry.name, 'sessions'), '.jsonl');
172
+ sessionFiles.push(...discovered);
173
+ }
174
+ }
175
+ catch {
176
+ return emptyResult('openclaw');
177
+ }
178
+ if (sessionFiles.length === 0)
179
+ return emptyResult('openclaw');
180
+ const collector = new TokenCollector('openclaw');
181
+ for (const filePath of sessionFiles) {
182
+ try {
183
+ const content = await readFile(filePath, 'utf8');
184
+ let fileFallbackDate = null;
185
+ for (const line of content.split('\n')) {
186
+ if (!line.trim())
187
+ continue;
188
+ try {
189
+ const parsed = JSON.parse(line);
190
+ const usage = parsed.usage ??
191
+ parsed.tokenUsage ??
192
+ parsed.message?.usage ??
193
+ parsed.response?.usage ??
194
+ null;
195
+ if (!usage || typeof usage !== 'object')
196
+ continue;
197
+ const tokens = (usage.total ??
198
+ (usage.input ?? usage.inputTokens ?? 0) +
199
+ (usage.output ?? usage.outputTokens ?? 0) +
200
+ (usage.cacheRead ?? usage.cacheReadTokens ?? 0) +
201
+ (usage.cacheWrite ?? usage.cacheWriteTokens ?? 0));
202
+ if (!tokens || tokens <= 0)
203
+ continue;
204
+ let date;
205
+ let hour = null;
206
+ const ts = parsed.timestamp ?? parsed.t ?? parsed.time ?? null;
207
+ if (ts) {
208
+ const tsMs = typeof ts === 'string' && /^\d+$/.test(ts) ? Number(ts) : ts;
209
+ const d = new Date(tsMs);
210
+ if (!Number.isNaN(d.getTime())) {
211
+ date = toDateStr(d);
212
+ hour = d.getHours();
213
+ }
214
+ else {
215
+ fileFallbackDate ??= toDateStr((await stat(filePath)).mtime);
216
+ date = fileFallbackDate;
217
+ }
218
+ }
219
+ else {
220
+ fileFallbackDate ??= toDateStr((await stat(filePath)).mtime);
221
+ date = fileFallbackDate;
222
+ }
223
+ const model = parsed.model ?? parsed.response?.model ?? '';
224
+ collector.addDaily(date, model, tokens, 1);
225
+ if (hour !== null)
226
+ collector.addHourly(date, hour, model, tokens, 1);
227
+ }
228
+ catch {
229
+ // skip malformed lines
230
+ }
231
+ }
232
+ }
233
+ catch {
234
+ // skip unreadable files
235
+ }
236
+ }
237
+ return collector.result();
238
+ }
239
+ export async function scanOpenCode() {
240
+ const baseDir = join(homedir(), '.local', 'share', 'opencode');
241
+ try {
242
+ await stat(baseDir);
243
+ }
244
+ catch {
245
+ return emptyResult('opencode');
246
+ }
247
+ const collector = new TokenCollector('opencode');
248
+ // Preferred: SQLite. Schema: message.data JSON with
249
+ // { role, modelID, time: { created: ms }, tokens: { input, output, reasoning, cache: { read, write } } }
250
+ const dbPath = join(baseDir, 'opencode.db');
251
+ try {
252
+ await stat(dbPath);
253
+ const { execSync } = await import('node:child_process');
254
+ const raw = execSync(`sqlite3 -readonly "${dbPath}" "SELECT json_extract(data,'$.time.created'), coalesce(json_extract(data,'$.modelID'),''), coalesce(json_extract(data,'$.tokens.input'),0), coalesce(json_extract(data,'$.tokens.output'),0), coalesce(json_extract(data,'$.tokens.cache.read'),0), coalesce(json_extract(data,'$.tokens.cache.write'),0), coalesce(json_extract(data,'$.tokens.reasoning'),0) FROM message WHERE json_extract(data,'$.role')='assistant'"`, { encoding: 'utf8', timeout: 15000, stdio: 'pipe' }).trim();
255
+ if (raw) {
256
+ for (const row of raw.split('\n')) {
257
+ const [time, model, inp, out, cr, cw, reason] = row.split('|');
258
+ const tokens = (Number.parseInt(inp ?? '0', 10) || 0) +
259
+ (Number.parseInt(out ?? '0', 10) || 0) +
260
+ (Number.parseInt(cr ?? '0', 10) || 0) +
261
+ (Number.parseInt(cw ?? '0', 10) || 0) +
262
+ (Number.parseInt(reason ?? '0', 10) || 0);
263
+ if (tokens <= 0)
264
+ continue;
265
+ const tsMs = Number(time ?? '0');
266
+ if (!Number.isFinite(tsMs) || tsMs <= 0)
267
+ continue;
268
+ const d = new Date(tsMs);
269
+ const m = (model ?? '').trim();
270
+ collector.addDaily(toDateStr(d), m, tokens, 1);
271
+ collector.addHourly(toDateStr(d), d.getHours(), m, tokens, 1);
272
+ }
273
+ const dbResult = collector.result();
274
+ if (dbResult.daily.length > 0)
275
+ return dbResult;
276
+ }
277
+ }
278
+ catch {
279
+ // DB unavailable; fall through to JSON files
280
+ }
281
+ // Fallback: storage/message/{sessionID}/msg_*.json
282
+ const messageDir = join(baseDir, 'storage', 'message');
283
+ try {
284
+ await stat(messageDir);
285
+ }
286
+ catch {
287
+ return collector.result();
288
+ }
289
+ try {
290
+ const sessionDirs = await readdir(messageDir, { withFileTypes: true });
291
+ for (const sessionEntry of sessionDirs) {
292
+ if (!sessionEntry.isDirectory())
293
+ continue;
294
+ const msgFiles = await findFiles(join(messageDir, sessionEntry.name), '.json');
295
+ for (const filePath of msgFiles) {
296
+ try {
297
+ const parsed = JSON.parse(await readFile(filePath, 'utf8'));
298
+ if (parsed.role !== 'assistant')
299
+ continue;
300
+ const t = parsed.tokens;
301
+ if (!t || typeof t !== 'object')
302
+ continue;
303
+ const tokens = (t.input ?? 0) +
304
+ (t.output ?? 0) +
305
+ (t.cache?.read ?? 0) +
306
+ (t.cache?.write ?? 0) +
307
+ (t.reasoning ?? 0);
308
+ if (tokens <= 0)
309
+ continue;
310
+ const tsMs = parsed.time?.created ?? 0;
311
+ let date;
312
+ let hour = null;
313
+ if (tsMs > 0) {
314
+ const d = new Date(tsMs);
315
+ date = toDateStr(d);
316
+ hour = d.getHours();
317
+ }
318
+ else {
319
+ date = toDateStr((await stat(filePath)).mtime);
320
+ }
321
+ const model = String(parsed.modelID ?? '');
322
+ collector.addDaily(date, model, tokens, 1);
323
+ if (hour !== null)
324
+ collector.addHourly(date, hour, model, tokens, 1);
325
+ }
326
+ catch {
327
+ // skip malformed files
328
+ }
329
+ }
330
+ }
331
+ }
332
+ catch {
333
+ // skip
334
+ }
335
+ return collector.result();
336
+ }
337
+ export async function scanCursorLocal() {
338
+ const dbPath = join(homedir(), '.cursor', 'ai-tracking', 'ai-code-tracking.db');
339
+ try {
340
+ await stat(dbPath);
341
+ }
342
+ catch {
343
+ return { ...emptyResult('cursor'), cursorStats: null };
344
+ }
345
+ const { execSync } = await import('node:child_process');
346
+ const collector = new TokenCollector('cursor');
347
+ try {
348
+ const raw = execSync(`sqlite3 "${dbPath}" "select commitHash, linesAdded, linesDeleted, composerLinesAdded, composerLinesDeleted, humanLinesAdded, humanLinesDeleted, v2AiPercentage from scored_commits;"`, { encoding: 'utf8', timeout: 10000 }).trim();
349
+ if (!raw)
350
+ return { ...emptyResult('cursor'), cursorStats: null };
351
+ const rows = raw.split('\n');
352
+ let totalTokens = 0;
353
+ let totalAiLines = 0;
354
+ let totalHumanLines = 0;
355
+ let aiPctSum = 0;
356
+ for (const row of rows) {
357
+ const [, , , composerAdded, composerDeleted, humanAdded, , aiPct] = row.split('|');
358
+ const aiLines = (parseInt(composerAdded ?? '0', 10) || 0) +
359
+ (parseInt(composerDeleted ?? '0', 10) || 0);
360
+ totalAiLines += parseInt(composerAdded ?? '0', 10) || 0;
361
+ totalHumanLines += parseInt(humanAdded ?? '0', 10) || 0;
362
+ aiPctSum += parseFloat(aiPct ?? '0') || 0;
363
+ totalTokens += aiLines * 30;
364
+ }
365
+ let models = [];
366
+ try {
367
+ const modelRaw = execSync(`sqlite3 "${dbPath}" "select model, count(*) from ai_code_hashes where model is not null and model != '' group by model order by count(*) desc;"`, { encoding: 'utf8', timeout: 5000 }).trim();
368
+ if (modelRaw) {
369
+ models = modelRaw.split('\n').map((line) => {
370
+ const [model, count] = line.split('|');
371
+ return { model: model ?? '', uses: parseInt(count ?? '0', 10) || 0 };
372
+ });
373
+ }
374
+ }
375
+ catch {
376
+ // optional
377
+ }
378
+ if (totalTokens > 0)
379
+ collector.addDaily(toDateStr(new Date()), '', totalTokens, 1);
380
+ const stats = {
381
+ totalCommits: rows.length,
382
+ aiLinesAdded: totalAiLines,
383
+ humanLinesAdded: totalHumanLines,
384
+ avgAiPercent: rows.length > 0 ? Math.round((aiPctSum / rows.length) * 10) / 10 : 0,
385
+ models,
386
+ };
387
+ return collector.result({ cursorStats: stats });
388
+ }
389
+ catch {
390
+ return { ...emptyResult('cursor'), cursorStats: null };
391
+ }
392
+ }
393
+ export async function scanCursorApi() {
394
+ const config = await loadConfig();
395
+ if (!config.cursorApiKey) {
396
+ return { ...emptyResult('cursor'), cursorScanStatus: { source: 'none' } };
397
+ }
398
+ const collector = new TokenCollector('cursor');
399
+ const email = config.cursorEmail;
400
+ const now = Date.now();
401
+ const startDate = now - 5 * 365 * 24 * 60 * 60 * 1000;
402
+ const endDate = now;
403
+ let page = 1;
404
+ let hasMore = true;
405
+ let retries = 0;
406
+ const MAX_RETRIES = 3;
407
+ let eventsProcessed = 0;
408
+ let partialReason = null;
409
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
410
+ while (hasMore) {
411
+ const body = {
412
+ startDate,
413
+ endDate,
414
+ page,
415
+ pageSize: 100,
416
+ };
417
+ if (email)
418
+ body.email = email;
419
+ let res;
420
+ try {
421
+ res = await fetch('https://api.cursor.com/teams/filtered-usage-events', {
422
+ method: 'POST',
423
+ headers: {
424
+ 'Content-Type': 'application/json',
425
+ Authorization: `Bearer ${config.cursorApiKey}`,
426
+ },
427
+ body: JSON.stringify(body),
428
+ });
429
+ }
430
+ catch (err) {
431
+ partialReason = `network: ${err instanceof Error ? err.message : 'unknown'}`;
432
+ break;
433
+ }
434
+ if (!res.ok) {
435
+ if (res.status === 429 && retries < MAX_RETRIES) {
436
+ await sleep(2000 * 2 ** retries);
437
+ retries++;
438
+ continue;
439
+ }
440
+ if (res.status === 401 || res.status === 403) {
441
+ if (eventsProcessed === 0) {
442
+ return {
443
+ ...emptyResult('cursor'),
444
+ cursorScanStatus: {
445
+ source: 'api-failed',
446
+ reason: `auth ${res.status} — check CURSOR_API_KEY`,
447
+ },
448
+ };
449
+ }
450
+ partialReason = `auth ${res.status} mid-scan`;
451
+ break;
452
+ }
453
+ partialReason = `HTTP ${res.status}`;
454
+ break;
455
+ }
456
+ retries = 0;
457
+ let data;
458
+ try {
459
+ data = await res.json();
460
+ }
461
+ catch {
462
+ partialReason = 'invalid json';
463
+ break;
464
+ }
465
+ for (const event of data.usageEvents ?? []) {
466
+ if (!event.isTokenBasedCall)
467
+ continue;
468
+ const tu = event.tokenUsage ??
469
+ event;
470
+ const tokens = (tu.inputTokens ?? 0) +
471
+ (tu.outputTokens ?? 0) +
472
+ (tu.cacheWriteTokens ?? 0) +
473
+ (tu.cacheReadTokens ?? 0);
474
+ if (tokens > 0 && event.timestamp) {
475
+ const rawTs = event.timestamp;
476
+ const tsMs = typeof rawTs === 'string' && /^\d+$/.test(rawTs)
477
+ ? Number(rawTs)
478
+ : rawTs;
479
+ const d = new Date(tsMs);
480
+ const model = event.model ?? '';
481
+ collector.addDaily(toDateStr(d), model, tokens, 1);
482
+ collector.addHourly(toDateStr(d), d.getHours(), model, tokens, 1);
483
+ eventsProcessed++;
484
+ }
485
+ }
486
+ hasMore = data.pagination?.hasNextPage ?? false;
487
+ page++;
488
+ if (page > 500) {
489
+ partialReason = 'pagination cap (500 pages)';
490
+ break;
491
+ }
492
+ }
493
+ const cursorScanStatus = partialReason
494
+ ? { source: 'api-partial', events: eventsProcessed, reason: partialReason }
495
+ : { source: 'api', events: eventsProcessed };
496
+ return collector.result({ cursorScanStatus });
497
+ }
498
+ /**
499
+ * Run every scanner in parallel and merge into a single submit-ready payload.
500
+ * Cursor prefers the API source when configured; otherwise the local estimate.
501
+ */
502
+ export async function scanAllTools() {
503
+ const [claude, codex, cursorApi, cursorLocal, openclaw, hermes, opencode] = await Promise.all([
504
+ scanClaudeCode(),
505
+ scanCodex(),
506
+ scanCursorApi(),
507
+ scanCursorLocal(),
508
+ scanOpenclaw(),
509
+ scanHermes(),
510
+ scanOpenCode(),
511
+ ]);
512
+ const cursorApiHasData = cursorApi.daily.length > 0;
513
+ const cursor = cursorApiHasData ? cursorApi : cursorLocal;
514
+ const results = [claude, codex, cursor, openclaw, hermes, opencode];
515
+ const toolTotals = {};
516
+ const dailyTotals = [];
517
+ const hourlyTotals = [];
518
+ const modelTotals = {};
519
+ let grandTotal = 0;
520
+ for (const r of results) {
521
+ let toolSum = 0;
522
+ for (const d of r.daily) {
523
+ dailyTotals.push(d);
524
+ toolSum += d.tokens;
525
+ }
526
+ toolTotals[r.tool] = (toolTotals[r.tool] ?? 0) + toolSum;
527
+ grandTotal += toolSum;
528
+ hourlyTotals.push(...r.hourly);
529
+ for (const [model, tokens] of Object.entries(r.models)) {
530
+ modelTotals[model] = (modelTotals[model] ?? 0) + tokens;
531
+ }
532
+ }
533
+ return {
534
+ toolTotals,
535
+ dailyTotals,
536
+ hourlyTotals,
537
+ modelTotals,
538
+ grandTotal,
539
+ cursorStats: cursorLocal.cursorStats ?? null,
540
+ cursorScanStatus: cursor.cursorScanStatus ?? { source: 'none' },
541
+ };
542
+ }
543
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/scanners/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ export type Tool = 'claude_code' | 'codex' | 'cursor' | 'openclaw' | 'hermes' | 'opencode';
2
+ export type DailyToolEntry = {
3
+ date: string;
4
+ tool: string;
5
+ tokens: number;
6
+ messages?: number;
7
+ model?: string;
8
+ };
9
+ export type HourlyEntry = {
10
+ date: string;
11
+ hour: number;
12
+ tool: string;
13
+ model?: string;
14
+ tokens: number;
15
+ messages?: number;
16
+ };
17
+ export type CursorStats = {
18
+ totalCommits: number;
19
+ aiLinesAdded: number;
20
+ humanLinesAdded: number;
21
+ avgAiPercent: number;
22
+ models: Array<{
23
+ model: string;
24
+ uses: number;
25
+ }>;
26
+ };
27
+ export type CursorScanStatus = {
28
+ source: 'none';
29
+ } | {
30
+ source: 'api';
31
+ events: number;
32
+ } | {
33
+ source: 'api-partial';
34
+ events: number;
35
+ reason: string;
36
+ } | {
37
+ source: 'api-failed';
38
+ reason: string;
39
+ };
40
+ /**
41
+ * Uniform result every scanner returns. No shared module state — each scanner
42
+ * owns its own maps, so scanners are pure and safe to run concurrently.
43
+ */
44
+ export type ScanResult = {
45
+ tool: Tool;
46
+ daily: DailyToolEntry[];
47
+ hourly: HourlyEntry[];
48
+ /** model name -> tokens, for the share card + modelTotals payload. */
49
+ models: Record<string, number>;
50
+ /** Cursor-only: local commit stats (null for other tools). */
51
+ cursorStats?: CursorStats | null;
52
+ /** Cursor-only: how the scan resolved (api/local/failed). */
53
+ cursorScanStatus?: CursorScanStatus;
54
+ };
55
+ export declare function emptyResult(tool: Tool): ScanResult;
56
+ export declare const HOURLY_WINDOW_DAYS = 90;
57
+ export type TokensMessages = {
58
+ tokens: number;
59
+ messages: number;
60
+ };
61
+ export declare function toDateStr(ts: string | number | Date): string;
62
+ export declare function hourlyCutoff(): string;
63
+ export declare function formatTokens(n: number): string;
64
+ export declare function formatBytes(n: number): string;
65
+ /** Recursively collect files with a given extension; unreadable dirs are skipped. */
66
+ export declare function findFiles(dir: string, ext: string): Promise<string[]>;
67
+ /**
68
+ * Per-scanner accumulator. Replaces the old module-level modelAccumulator /
69
+ * hourlyAccumulator globals — each scanner instantiates its own, so there is no
70
+ * cross-scan state to clear and concurrent runs can't clobber each other.
71
+ */
72
+ export declare class TokenCollector {
73
+ private readonly tool;
74
+ private readonly dailyByModel;
75
+ private readonly hourly;
76
+ private readonly models;
77
+ private readonly cutoff;
78
+ constructor(tool: Tool);
79
+ addDaily(date: string, model: string, tokens: number, messages?: number): void;
80
+ addHourly(date: string, hour: number, model: string | undefined, tokens: number, messages?: number): void;
81
+ result(extra?: Partial<ScanResult>): ScanResult;
82
+ }
83
+ //# sourceMappingURL=util.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../src/scanners/util.ts"],"names":[],"mappings":"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"}