@juliantanx/aiusage 1.5.7 → 1.5.8
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/dist/index.js +395 -95
- package/dist/web/_app/immutable/chunks/entry.DJZO-wBk.js +3 -0
- package/dist/web/_app/immutable/chunks/{stores.BYZRdBSl.js → stores.CDuvMHgD.js} +1 -1
- package/dist/web/_app/immutable/entry/{app.CM2PdbpC.js → app.WQCJU-_e.js} +2 -2
- package/dist/web/_app/immutable/entry/start.COue4Eiw.js +1 -0
- package/dist/web/_app/immutable/nodes/{0.DDrgmg6l.js → 0.Fq-nYlaS.js} +1 -1
- package/dist/web/_app/immutable/nodes/{1.DTUl4JbV.js → 1.DrSfUVzz.js} +1 -1
- package/dist/web/_app/immutable/nodes/{11.DB5iERgm.js → 11.YqYsFEzd.js} +1 -1
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +6 -6
- package/package.json +3 -3
- package/dist/web/_app/immutable/chunks/entry.NbJb2eQR.js +0 -3
- package/dist/web/_app/immutable/entry/start.Cj8FkSB_.js +0 -1
package/dist/index.js
CHANGED
|
@@ -13,8 +13,8 @@ import { execSync as execSync5 } from "child_process";
|
|
|
13
13
|
|
|
14
14
|
// src/commands/serve.ts
|
|
15
15
|
import http2 from "http";
|
|
16
|
-
import { readFileSync as
|
|
17
|
-
import { join as
|
|
16
|
+
import { readFileSync as readFileSync11, existsSync as existsSync12, statSync as statSync4, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4 } from "fs";
|
|
17
|
+
import { join as join13, extname as extname2, dirname as dirname6 } from "path";
|
|
18
18
|
import { fileURLToPath } from "url";
|
|
19
19
|
|
|
20
20
|
// src/api/server.ts
|
|
@@ -872,7 +872,39 @@ function sanitizeModel(value, fallback) {
|
|
|
872
872
|
const model = lastPathSegment(value);
|
|
873
873
|
return model || fallback;
|
|
874
874
|
}
|
|
875
|
-
function
|
|
875
|
+
function codeBuddyUsage(parsed) {
|
|
876
|
+
const ru = parsed?.providerData?.rawUsage;
|
|
877
|
+
if (ru && typeof ru === "object") {
|
|
878
|
+
const hit = num(ru.prompt_cache_hit_tokens ?? ru.prompt_tokens_details?.cached_tokens);
|
|
879
|
+
const miss = ru.prompt_cache_miss_tokens;
|
|
880
|
+
const prompt2 = num(ru.prompt_tokens ?? ru.input_tokens);
|
|
881
|
+
return {
|
|
882
|
+
inputTokens: miss != null ? num(miss) : Math.max(0, prompt2 - hit),
|
|
883
|
+
outputTokens: num(ru.completion_tokens ?? ru.output_tokens),
|
|
884
|
+
cacheReadTokens: hit,
|
|
885
|
+
cacheWriteTokens: num(ru.prompt_cache_write_tokens ?? ru.cache_creation_input_tokens),
|
|
886
|
+
thinkingTokens: num(ru.completion_thinking_tokens ?? ru.completion_tokens_details?.reasoning_tokens)
|
|
887
|
+
};
|
|
888
|
+
}
|
|
889
|
+
const mu = parsed?.message?.usage;
|
|
890
|
+
if (mu && typeof mu === "object") {
|
|
891
|
+
const cacheRead = num(mu.cache_read_input_tokens ?? mu.prompt_tokens_details?.cached_tokens);
|
|
892
|
+
const rawInput = num(mu.input_tokens ?? mu.prompt_tokens);
|
|
893
|
+
return {
|
|
894
|
+
inputTokens: Math.max(0, rawInput - cacheRead),
|
|
895
|
+
outputTokens: num(mu.output_tokens ?? mu.completion_tokens),
|
|
896
|
+
cacheReadTokens: cacheRead,
|
|
897
|
+
cacheWriteTokens: num(mu.cache_creation_input_tokens ?? mu.cache_write_input_tokens),
|
|
898
|
+
thinkingTokens: num(mu.thinking_tokens ?? mu.reasoning_tokens)
|
|
899
|
+
};
|
|
900
|
+
}
|
|
901
|
+
return null;
|
|
902
|
+
}
|
|
903
|
+
function usageFromAny(parsed, tool) {
|
|
904
|
+
if (tool === "codebuddy") {
|
|
905
|
+
const cb = codeBuddyUsage(parsed);
|
|
906
|
+
if (cb) return cb;
|
|
907
|
+
}
|
|
876
908
|
const usage = parsed?.message?.usage ?? parsed?.usage ?? parsed?.event?.usage ?? parsed?.payload?.token_usage ?? parsed?.message?.payload?.token_usage ?? parsed?.providerData?.rawUsage ?? parsed?.data?.usage;
|
|
877
909
|
if (!usage || typeof usage !== "object") return null;
|
|
878
910
|
const details = usage.prompt_tokens_details ?? usage.input_tokens_details ?? {};
|
|
@@ -942,7 +974,7 @@ var GenericJsonlParser = class {
|
|
|
942
974
|
}
|
|
943
975
|
const normalized = parsed?.type === "context.append_loop_event" && parsed.event ? { ...parsed.event, time: parsed.time } : parsed;
|
|
944
976
|
if (!shouldAccept(this.tool, normalized)) return null;
|
|
945
|
-
const usage = usageFromAny(normalized);
|
|
977
|
+
const usage = usageFromAny(normalized, this.tool);
|
|
946
978
|
if (!usage) return null;
|
|
947
979
|
const total = usage.inputTokens + usage.outputTokens + usage.cacheReadTokens + usage.cacheWriteTokens + usage.thinkingTokens;
|
|
948
980
|
if (total === 0) return null;
|
|
@@ -1603,6 +1635,55 @@ function probeCodeBuddy(ctx) {
|
|
|
1603
1635
|
const dir = join3(ctx.env.CODEBUDDY_HOME ?? join3(ctx.home, ".codebuddy"), "projects");
|
|
1604
1636
|
return existsSync3(dir) ? dir : null;
|
|
1605
1637
|
}
|
|
1638
|
+
function codeBuddyIdeRoots(ctx) {
|
|
1639
|
+
const roots = [];
|
|
1640
|
+
if (platform() === "darwin") {
|
|
1641
|
+
roots.push(join3(ctx.home, "Library", "Application Support", "CodeBuddyExtension", "Data"));
|
|
1642
|
+
} else if (platform() === "win32") {
|
|
1643
|
+
const appData = ctx.env.APPDATA ?? join3(ctx.home, "AppData", "Roaming");
|
|
1644
|
+
roots.push(join3(appData, "CodeBuddyExtension", "Data"));
|
|
1645
|
+
} else {
|
|
1646
|
+
const config = ctx.env.XDG_CONFIG_HOME ?? join3(ctx.home, ".config");
|
|
1647
|
+
roots.push(join3(config, "CodeBuddyExtension", "Data"));
|
|
1648
|
+
}
|
|
1649
|
+
return unique(roots);
|
|
1650
|
+
}
|
|
1651
|
+
function probeCodeBuddyIde(ctx) {
|
|
1652
|
+
const override = envOverride("codebuddy-ide", ctx.env);
|
|
1653
|
+
if (override) return override;
|
|
1654
|
+
const legacy = ctx.legacySources?.["codebuddy-ide"];
|
|
1655
|
+
if (legacy) return legacy;
|
|
1656
|
+
for (const root of codeBuddyIdeRoots(ctx)) {
|
|
1657
|
+
if (existsSync3(root)) return root;
|
|
1658
|
+
}
|
|
1659
|
+
return null;
|
|
1660
|
+
}
|
|
1661
|
+
function countCodeBuddyIdeConversations(dir) {
|
|
1662
|
+
let count = 0;
|
|
1663
|
+
const walk = (root, depth) => {
|
|
1664
|
+
if (depth > 12) return;
|
|
1665
|
+
let entries;
|
|
1666
|
+
try {
|
|
1667
|
+
entries = readdirSync(root, { withFileTypes: true });
|
|
1668
|
+
} catch {
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
for (const entry of entries) {
|
|
1672
|
+
if (!entry.isDirectory()) continue;
|
|
1673
|
+
const full = join3(root, entry.name);
|
|
1674
|
+
if (entry.name === "messages") {
|
|
1675
|
+
try {
|
|
1676
|
+
if (readdirSync(full).some((f) => f.endsWith(".json"))) count++;
|
|
1677
|
+
} catch {
|
|
1678
|
+
}
|
|
1679
|
+
continue;
|
|
1680
|
+
}
|
|
1681
|
+
walk(full, depth + 1);
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1684
|
+
walk(dir, 0);
|
|
1685
|
+
return count;
|
|
1686
|
+
}
|
|
1606
1687
|
function probeKiro(ctx) {
|
|
1607
1688
|
const override = envOverride("kiro", ctx.env);
|
|
1608
1689
|
if (override) return override;
|
|
@@ -1810,6 +1891,7 @@ var TOOL_REGISTRY = [
|
|
|
1810
1891
|
{ tool: "gemini", sourceKey: "gemini", label: "Gemini CLI", probe: probeGemini },
|
|
1811
1892
|
{ tool: "kimi", sourceKey: "kimi", label: "Kimi Code", probe: probeKimi },
|
|
1812
1893
|
{ tool: "codebuddy", sourceKey: "codebuddy", label: "CodeBuddy", probe: probeCodeBuddy },
|
|
1894
|
+
{ tool: "codebuddy", sourceKey: "codebuddy-ide", label: "CodeBuddy (IDE)", probe: probeCodeBuddyIde },
|
|
1813
1895
|
{ tool: "kiro", sourceKey: "kiro", label: "Kiro", probe: probeKiro },
|
|
1814
1896
|
{ tool: "grok", sourceKey: "grok", label: "Grok Build", probe: probeGrok },
|
|
1815
1897
|
{ tool: "antigravity", sourceKey: "antigravity", label: "Antigravity", probe: probeAntigravity },
|
|
@@ -1839,7 +1921,9 @@ function discoverTools(env = process.env) {
|
|
|
1839
1921
|
try {
|
|
1840
1922
|
const stat2 = statSync(detectedPath);
|
|
1841
1923
|
if (stat2.isDirectory()) {
|
|
1842
|
-
if (entry.sourceKey === "
|
|
1924
|
+
if (entry.sourceKey === "codebuddy-ide") {
|
|
1925
|
+
fileCount += countCodeBuddyIdeConversations(detectedPath);
|
|
1926
|
+
} else if (entry.sourceKey === "roocode" || entry.sourceKey === "kilocode") {
|
|
1843
1927
|
fileCount += findJsonFiles(detectedPath).filter((p) => basename(p) === "ui_messages.json").length;
|
|
1844
1928
|
} else if (entry.sourceKey === "kelivo") {
|
|
1845
1929
|
fileCount += findJsonFiles(detectedPath).filter((p) => basename(p) === "chats.json").length + findZipFiles(detectedPath).length;
|
|
@@ -3176,6 +3260,17 @@ function migrateV11(db) {
|
|
|
3176
3260
|
`);
|
|
3177
3261
|
}
|
|
3178
3262
|
|
|
3263
|
+
// src/db/migrations/v12.ts
|
|
3264
|
+
function migrateV12(db) {
|
|
3265
|
+
db.prepare(`
|
|
3266
|
+
UPDATE records
|
|
3267
|
+
SET updated_at = ?
|
|
3268
|
+
WHERE source_file NOT LIKE 'synced/%'
|
|
3269
|
+
AND (cwd != '' OR source_file LIKE '%:session:%')
|
|
3270
|
+
`).run(Date.now());
|
|
3271
|
+
db.prepare("INSERT INTO schema_version (version) VALUES (12)").run();
|
|
3272
|
+
}
|
|
3273
|
+
|
|
3179
3274
|
// src/db/migrations/index.ts
|
|
3180
3275
|
var MIGRATIONS = [
|
|
3181
3276
|
{ version: 1, migrate: migrateV1 },
|
|
@@ -3188,7 +3283,8 @@ var MIGRATIONS = [
|
|
|
3188
3283
|
{ version: 8, migrate: migrateV8 },
|
|
3189
3284
|
{ version: 9, migrate: migrateV9 },
|
|
3190
3285
|
{ version: 10, migrate: migrateV10 },
|
|
3191
|
-
{ version: 11, migrate: migrateV11 }
|
|
3286
|
+
{ version: 11, migrate: migrateV11 },
|
|
3287
|
+
{ version: 12, migrate: migrateV12 }
|
|
3192
3288
|
];
|
|
3193
3289
|
function runMigrations(db) {
|
|
3194
3290
|
createSchemaVersionTable(db);
|
|
@@ -4031,10 +4127,10 @@ function getClientPlatform() {
|
|
|
4031
4127
|
}
|
|
4032
4128
|
function getCliVersion() {
|
|
4033
4129
|
try {
|
|
4034
|
-
const { readFileSync:
|
|
4035
|
-
const { join:
|
|
4036
|
-
const pkgPath =
|
|
4037
|
-
const pkg = JSON.parse(
|
|
4130
|
+
const { readFileSync: readFileSync14 } = __require("fs");
|
|
4131
|
+
const { join: join18 } = __require("path");
|
|
4132
|
+
const pkgPath = join18(__dirname, "../../package.json");
|
|
4133
|
+
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
4038
4134
|
return pkg.version || "0.0.0";
|
|
4039
4135
|
} catch {
|
|
4040
4136
|
return "0.0.0";
|
|
@@ -6245,8 +6341,8 @@ function createApiServer(db, options) {
|
|
|
6245
6341
|
|
|
6246
6342
|
// src/commands/parse.ts
|
|
6247
6343
|
import Database2 from "better-sqlite3";
|
|
6248
|
-
import { readFileSync as
|
|
6249
|
-
import { join as
|
|
6344
|
+
import { readFileSync as readFileSync10, statSync as statSync3, existsSync as existsSync10, openSync, readSync, closeSync } from "fs";
|
|
6345
|
+
import { join as join9, dirname as dirname5 } from "path";
|
|
6250
6346
|
import { hostname as hostname2 } from "os";
|
|
6251
6347
|
|
|
6252
6348
|
// src/watermark.ts
|
|
@@ -6297,7 +6393,7 @@ var WatermarkManager = class {
|
|
|
6297
6393
|
if (parsed && typeof parsed === "object" && !("files" in parsed)) {
|
|
6298
6394
|
return { files: { ...defaultFileData(), ...parsed } };
|
|
6299
6395
|
}
|
|
6300
|
-
return { files: { ...defaultFileData(), ...parsed.files ?? {} }, opencode: parsed.opencode ?? null, hermes: parsed.hermes ?? null, qoder: parsed.qoder ?? null, cursor: parsed.cursor ?? null, goose: parsed.goose ?? null, zed: parsed.zed ?? null, kiro: parsed.kiro ?? null, zcode: parsed.zcode ?? null, zcodeTools: parsed.zcodeTools ?? null, trae: parsed.trae ?? null };
|
|
6396
|
+
return { files: { ...defaultFileData(), ...parsed.files ?? {} }, opencode: parsed.opencode ?? null, hermes: parsed.hermes ?? null, qoder: parsed.qoder ?? null, cursor: parsed.cursor ?? null, goose: parsed.goose ?? null, zed: parsed.zed ?? null, kiro: parsed.kiro ?? null, zcode: parsed.zcode ?? null, zcodeTools: parsed.zcodeTools ?? null, trae: parsed.trae ?? null, codebuddyIde: parsed.codebuddyIde ?? null };
|
|
6301
6397
|
} catch {
|
|
6302
6398
|
return { files: defaultFileData() };
|
|
6303
6399
|
}
|
|
@@ -6384,6 +6480,12 @@ var WatermarkManager = class {
|
|
|
6384
6480
|
setTraeLastImported(ts3) {
|
|
6385
6481
|
this.data.trae = ts3;
|
|
6386
6482
|
}
|
|
6483
|
+
getCodeBuddyIdeCursor() {
|
|
6484
|
+
return this.data.codebuddyIde ?? 0;
|
|
6485
|
+
}
|
|
6486
|
+
setCodeBuddyIdeCursor(ts3) {
|
|
6487
|
+
this.data.codebuddyIde = ts3;
|
|
6488
|
+
}
|
|
6387
6489
|
};
|
|
6388
6490
|
|
|
6389
6491
|
// src/commands/parse-opencode.ts
|
|
@@ -7430,6 +7532,173 @@ function runParseTrae(options) {
|
|
|
7430
7532
|
return { records, toolCalls, lastImportedAt: latestTs, errors };
|
|
7431
7533
|
}
|
|
7432
7534
|
|
|
7535
|
+
// src/commands/parse-codebuddy.ts
|
|
7536
|
+
import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync9 } from "fs";
|
|
7537
|
+
import { join as join8, basename as basename4, dirname as dirname4 } from "path";
|
|
7538
|
+
function num3(value) {
|
|
7539
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
7540
|
+
}
|
|
7541
|
+
function toMs(iso) {
|
|
7542
|
+
if (typeof iso !== "string") return 0;
|
|
7543
|
+
const ms = Date.parse(iso);
|
|
7544
|
+
return Number.isFinite(ms) ? ms : 0;
|
|
7545
|
+
}
|
|
7546
|
+
var WORKSPACE_FOLDER_RE = /Workspace Folder:\s*(.+)/;
|
|
7547
|
+
function userMessageText(raw) {
|
|
7548
|
+
try {
|
|
7549
|
+
const inner = JSON.parse(raw);
|
|
7550
|
+
if (Array.isArray(inner.content)) {
|
|
7551
|
+
return inner.content.filter((block) => block?.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n");
|
|
7552
|
+
}
|
|
7553
|
+
} catch {
|
|
7554
|
+
}
|
|
7555
|
+
return raw;
|
|
7556
|
+
}
|
|
7557
|
+
function findMessagesDirs(root, depth = 0) {
|
|
7558
|
+
if (depth > 12) return [];
|
|
7559
|
+
let entries;
|
|
7560
|
+
try {
|
|
7561
|
+
entries = readdirSync3(root, { withFileTypes: true });
|
|
7562
|
+
} catch {
|
|
7563
|
+
return [];
|
|
7564
|
+
}
|
|
7565
|
+
const out = [];
|
|
7566
|
+
for (const entry of entries) {
|
|
7567
|
+
if (!entry.isDirectory()) continue;
|
|
7568
|
+
const full = join8(root, entry.name);
|
|
7569
|
+
if (entry.name === "messages") {
|
|
7570
|
+
out.push(full);
|
|
7571
|
+
continue;
|
|
7572
|
+
}
|
|
7573
|
+
out.push(...findMessagesDirs(full, depth + 1));
|
|
7574
|
+
}
|
|
7575
|
+
return out;
|
|
7576
|
+
}
|
|
7577
|
+
function readConversation(messagesDir) {
|
|
7578
|
+
let files;
|
|
7579
|
+
try {
|
|
7580
|
+
files = readdirSync3(messagesDir).filter((f) => f.endsWith(".json"));
|
|
7581
|
+
} catch {
|
|
7582
|
+
return null;
|
|
7583
|
+
}
|
|
7584
|
+
if (files.length === 0) return null;
|
|
7585
|
+
const parsed = [];
|
|
7586
|
+
for (const file of files) {
|
|
7587
|
+
try {
|
|
7588
|
+
const data = JSON.parse(readFileSync9(join8(messagesDir, file), "utf-8"));
|
|
7589
|
+
if (data && typeof data === "object") parsed.push(data);
|
|
7590
|
+
} catch {
|
|
7591
|
+
}
|
|
7592
|
+
}
|
|
7593
|
+
if (parsed.length === 0) return null;
|
|
7594
|
+
let cwd;
|
|
7595
|
+
for (const msg of parsed) {
|
|
7596
|
+
if (msg.role !== "user" || typeof msg.message !== "string") continue;
|
|
7597
|
+
const match = WORKSPACE_FOLDER_RE.exec(userMessageText(msg.message));
|
|
7598
|
+
if (match) {
|
|
7599
|
+
cwd = match[1].trim();
|
|
7600
|
+
break;
|
|
7601
|
+
}
|
|
7602
|
+
}
|
|
7603
|
+
let latest = null;
|
|
7604
|
+
for (const msg of parsed) {
|
|
7605
|
+
if (msg.role !== "assistant" || typeof msg.extra !== "string") continue;
|
|
7606
|
+
let extra2;
|
|
7607
|
+
try {
|
|
7608
|
+
extra2 = JSON.parse(msg.extra);
|
|
7609
|
+
} catch {
|
|
7610
|
+
continue;
|
|
7611
|
+
}
|
|
7612
|
+
const hasStats = extra2.statsSnapshot != null || extra2.lastStepInputTokens != null;
|
|
7613
|
+
if (!hasStats) continue;
|
|
7614
|
+
const ts3 = toMs(msg.createdAt);
|
|
7615
|
+
if (!latest || ts3 >= latest.ts) latest = { ts: ts3, extra: extra2 };
|
|
7616
|
+
}
|
|
7617
|
+
if (!latest) return null;
|
|
7618
|
+
const extra = latest.extra;
|
|
7619
|
+
const snapshot = extra.statsSnapshot ?? {};
|
|
7620
|
+
const cacheReadTokens = num3(snapshot.cachedInputTokens ?? extra.lastStepCachedInputTokens);
|
|
7621
|
+
const inputTokens = snapshot.cacheMissTokens != null ? num3(snapshot.cacheMissTokens) : Math.max(0, num3(extra.lastStepInputTokens) - cacheReadTokens);
|
|
7622
|
+
const outputTokens = num3(snapshot.lastOutputTokens ?? extra.lastStepOutputTokens);
|
|
7623
|
+
const cacheWriteTokens = num3(snapshot.cacheWriteTokens);
|
|
7624
|
+
const thinkingTokens = num3(snapshot.thinkingTokens);
|
|
7625
|
+
const model = typeof extra.modelId === "string" && extra.modelId.trim() ? extra.modelId.trim() : "unknown";
|
|
7626
|
+
return {
|
|
7627
|
+
ts: latest.ts,
|
|
7628
|
+
model,
|
|
7629
|
+
inputTokens,
|
|
7630
|
+
outputTokens,
|
|
7631
|
+
cacheReadTokens,
|
|
7632
|
+
cacheWriteTokens,
|
|
7633
|
+
thinkingTokens,
|
|
7634
|
+
cwd
|
|
7635
|
+
};
|
|
7636
|
+
}
|
|
7637
|
+
function runParseCodeBuddy(options) {
|
|
7638
|
+
const { dataDir, device, deviceInstanceId, platform: platform5, now, cursor, exchangeRate } = options;
|
|
7639
|
+
const records = [];
|
|
7640
|
+
const errors = [];
|
|
7641
|
+
let nextCursor = cursor ?? 0;
|
|
7642
|
+
if (!existsSync9(dataDir)) {
|
|
7643
|
+
return { records, nextCursor, errors };
|
|
7644
|
+
}
|
|
7645
|
+
let messagesDirs;
|
|
7646
|
+
try {
|
|
7647
|
+
messagesDirs = findMessagesDirs(dataDir);
|
|
7648
|
+
} catch (e) {
|
|
7649
|
+
return { records, nextCursor, errors: [String(e)] };
|
|
7650
|
+
}
|
|
7651
|
+
for (const messagesDir of messagesDirs) {
|
|
7652
|
+
const conversationDir = dirname4(messagesDir);
|
|
7653
|
+
const sessionId = basename4(conversationDir);
|
|
7654
|
+
let usage;
|
|
7655
|
+
try {
|
|
7656
|
+
usage = readConversation(messagesDir);
|
|
7657
|
+
} catch (e) {
|
|
7658
|
+
errors.push(`${messagesDir}: ${e instanceof Error ? e.message : e}`);
|
|
7659
|
+
continue;
|
|
7660
|
+
}
|
|
7661
|
+
if (!usage) continue;
|
|
7662
|
+
if (usage.inputTokens + usage.outputTokens + usage.cacheReadTokens === 0) continue;
|
|
7663
|
+
if (cursor && usage.ts <= cursor) continue;
|
|
7664
|
+
if (usage.ts > nextCursor) nextCursor = usage.ts;
|
|
7665
|
+
const provider = inferProvider(usage.model);
|
|
7666
|
+
const tokenArgs = {
|
|
7667
|
+
inputTokens: usage.inputTokens,
|
|
7668
|
+
outputTokens: usage.outputTokens,
|
|
7669
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
7670
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
7671
|
+
thinkingTokens: usage.thinkingTokens
|
|
7672
|
+
};
|
|
7673
|
+
const cost = calculateCost(usage.model, tokenArgs, exchangeRate);
|
|
7674
|
+
const recordId = generateRecordId(deviceInstanceId, conversationDir, usage.ts);
|
|
7675
|
+
records.push({
|
|
7676
|
+
id: recordId,
|
|
7677
|
+
ts: usage.ts,
|
|
7678
|
+
ingestedAt: now,
|
|
7679
|
+
updatedAt: now,
|
|
7680
|
+
lineOffset: 0,
|
|
7681
|
+
tool: "codebuddy",
|
|
7682
|
+
model: usage.model,
|
|
7683
|
+
provider,
|
|
7684
|
+
inputTokens: usage.inputTokens,
|
|
7685
|
+
outputTokens: usage.outputTokens,
|
|
7686
|
+
cacheReadTokens: usage.cacheReadTokens,
|
|
7687
|
+
cacheWriteTokens: usage.cacheWriteTokens,
|
|
7688
|
+
thinkingTokens: usage.thinkingTokens,
|
|
7689
|
+
cost,
|
|
7690
|
+
costSource: cost > 0 ? "pricing" : "unknown",
|
|
7691
|
+
sessionId,
|
|
7692
|
+
sourceFile: conversationDir,
|
|
7693
|
+
cwd: usage.cwd,
|
|
7694
|
+
device,
|
|
7695
|
+
deviceInstanceId,
|
|
7696
|
+
platform: platform5
|
|
7697
|
+
});
|
|
7698
|
+
}
|
|
7699
|
+
return { records, nextCursor, errors };
|
|
7700
|
+
}
|
|
7701
|
+
|
|
7433
7702
|
// src/commands/parse.ts
|
|
7434
7703
|
function extractCwdFromJson(data) {
|
|
7435
7704
|
if (typeof data.cwd === "string" && data.cwd) return data.cwd;
|
|
@@ -7484,7 +7753,7 @@ function parseUiMessagesFile(options) {
|
|
|
7484
7753
|
const errors = [];
|
|
7485
7754
|
let messages;
|
|
7486
7755
|
try {
|
|
7487
|
-
const parsed = JSON.parse(
|
|
7756
|
+
const parsed = JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
7488
7757
|
messages = Array.isArray(parsed) ? parsed : [];
|
|
7489
7758
|
} catch (e) {
|
|
7490
7759
|
return { records, errors: [`${filePath}: ${e instanceof Error ? e.message : e}`] };
|
|
@@ -7562,7 +7831,7 @@ function parseKiroSessionFile(options) {
|
|
|
7562
7831
|
const errors = [];
|
|
7563
7832
|
let parsed;
|
|
7564
7833
|
try {
|
|
7565
|
-
parsed = JSON.parse(
|
|
7834
|
+
parsed = JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
7566
7835
|
} catch (e) {
|
|
7567
7836
|
return { records, errors: [`${filePath}: ${e instanceof Error ? e.message : e}`] };
|
|
7568
7837
|
}
|
|
@@ -7617,8 +7886,8 @@ function parseKiroWorkspaceSession(options) {
|
|
|
7617
7886
|
const sessionId = parsed?.sessionId ?? extractSessionId2(filePath, "kiro");
|
|
7618
7887
|
let sessionTs = now;
|
|
7619
7888
|
try {
|
|
7620
|
-
const dir =
|
|
7621
|
-
const sessionsJson =
|
|
7889
|
+
const dir = dirname5(filePath);
|
|
7890
|
+
const sessionsJson = readFileSync10(join9(dir, "sessions.json"), "utf-8");
|
|
7622
7891
|
const sessions = JSON.parse(sessionsJson);
|
|
7623
7892
|
const match = Array.isArray(sessions) && sessions.find((s) => s.sessionId === sessionId);
|
|
7624
7893
|
if (match?.dateCreated) {
|
|
@@ -7694,7 +7963,7 @@ async function runParse(db, filterTool, options) {
|
|
|
7694
7963
|
const device = config?.device || hostname2() || state?.deviceInstanceId?.slice(0, 8) || "unknown";
|
|
7695
7964
|
const deviceInstanceId = state?.deviceInstanceId ?? "unknown";
|
|
7696
7965
|
const devicePlatform = config?.platform;
|
|
7697
|
-
const watermarkPath =
|
|
7966
|
+
const watermarkPath = join9(AIUSAGE_DIR, "watermark.json");
|
|
7698
7967
|
const wm = new WatermarkManager(watermarkPath);
|
|
7699
7968
|
const toolPaths = discoverLogFiles();
|
|
7700
7969
|
const aggregator = new Aggregator();
|
|
@@ -7765,7 +8034,7 @@ async function runParse(db, filterTool, options) {
|
|
|
7765
8034
|
continue;
|
|
7766
8035
|
}
|
|
7767
8036
|
if (tool === "kiro" && filePath.endsWith(".jsonl")) {
|
|
7768
|
-
const content2 =
|
|
8037
|
+
const content2 = readFileSync10(filePath, "utf-8");
|
|
7769
8038
|
const lines2 = content2.split("\n");
|
|
7770
8039
|
let byteOffset2 = 0;
|
|
7771
8040
|
for (const line of lines2) {
|
|
@@ -7895,7 +8164,7 @@ async function runParse(db, filterTool, options) {
|
|
|
7895
8164
|
onProgress({ phase: "Parsing logs", tool, current: toolIndex, total: toolTotal, records: parsedCount, toolCalls: toolCallCount });
|
|
7896
8165
|
continue;
|
|
7897
8166
|
}
|
|
7898
|
-
const content =
|
|
8167
|
+
const content = readFileSync10(filePath, "utf-8");
|
|
7899
8168
|
const lines = content.split("\n");
|
|
7900
8169
|
let byteOffset = 0;
|
|
7901
8170
|
let fileCwd;
|
|
@@ -7959,7 +8228,7 @@ async function runParse(db, filterTool, options) {
|
|
|
7959
8228
|
}
|
|
7960
8229
|
}
|
|
7961
8230
|
if (fileCwd) {
|
|
7962
|
-
db.prepare(`UPDATE records SET cwd = ? WHERE source_file = ? AND cwd = ''`).run(fileCwd, filePath);
|
|
8231
|
+
db.prepare(`UPDATE records SET cwd = ?, updated_at = ? WHERE source_file = ? AND cwd = ''`).run(fileCwd, Date.now(), filePath);
|
|
7963
8232
|
}
|
|
7964
8233
|
wm.setEntry(tool, filePath, {
|
|
7965
8234
|
offset: stat2.size,
|
|
@@ -7974,7 +8243,7 @@ async function runParse(db, filterTool, options) {
|
|
|
7974
8243
|
}
|
|
7975
8244
|
}
|
|
7976
8245
|
const openCodeDbPath = options?.openCodeDbPath ?? getDbPath("opencode") ?? "";
|
|
7977
|
-
if ((!filterTool || filterTool === "opencode") &&
|
|
8246
|
+
if ((!filterTool || filterTool === "opencode") && existsSync10(openCodeDbPath)) {
|
|
7978
8247
|
try {
|
|
7979
8248
|
const openCodeDb = new Database2(openCodeDbPath, { readonly: true });
|
|
7980
8249
|
try {
|
|
@@ -8005,7 +8274,7 @@ async function runParse(db, filterTool, options) {
|
|
|
8005
8274
|
}
|
|
8006
8275
|
}
|
|
8007
8276
|
const hermesDbPath = options?.hermesDbPath ?? getDbPath("hermes") ?? "";
|
|
8008
|
-
if ((!filterTool || filterTool === "hermes") &&
|
|
8277
|
+
if ((!filterTool || filterTool === "hermes") && existsSync10(hermesDbPath)) {
|
|
8009
8278
|
try {
|
|
8010
8279
|
const hermesDb = new Database2(hermesDbPath, { readonly: true });
|
|
8011
8280
|
try {
|
|
@@ -8036,7 +8305,7 @@ async function runParse(db, filterTool, options) {
|
|
|
8036
8305
|
}
|
|
8037
8306
|
}
|
|
8038
8307
|
const qoderDbPath = options?.qoderDbPath ?? getDbPath("qoder-db") ?? "";
|
|
8039
|
-
if ((!filterTool || filterTool === "qoder") &&
|
|
8308
|
+
if ((!filterTool || filterTool === "qoder") && existsSync10(qoderDbPath)) {
|
|
8040
8309
|
try {
|
|
8041
8310
|
const qoderDb = new Database2(qoderDbPath, { readonly: true });
|
|
8042
8311
|
try {
|
|
@@ -8067,7 +8336,7 @@ async function runParse(db, filterTool, options) {
|
|
|
8067
8336
|
}
|
|
8068
8337
|
}
|
|
8069
8338
|
const cursorDbPath = options?.cursorDbPath ?? getDbPath("cursor") ?? "";
|
|
8070
|
-
if ((!filterTool || filterTool === "cursor") &&
|
|
8339
|
+
if ((!filterTool || filterTool === "cursor") && existsSync10(cursorDbPath)) {
|
|
8071
8340
|
try {
|
|
8072
8341
|
const cursorDb = new Database2(cursorDbPath, { readonly: true });
|
|
8073
8342
|
try {
|
|
@@ -8097,7 +8366,7 @@ async function runParse(db, filterTool, options) {
|
|
|
8097
8366
|
}
|
|
8098
8367
|
}
|
|
8099
8368
|
const kiloDbPath = getDbPath("kilocode-db") ?? "";
|
|
8100
|
-
if ((!filterTool || filterTool === "kilocode") &&
|
|
8369
|
+
if ((!filterTool || filterTool === "kilocode") && existsSync10(kiloDbPath)) {
|
|
8101
8370
|
try {
|
|
8102
8371
|
const kiloDb = new Database2(kiloDbPath, { readonly: true });
|
|
8103
8372
|
try {
|
|
@@ -8137,7 +8406,7 @@ async function runParse(db, filterTool, options) {
|
|
|
8137
8406
|
}
|
|
8138
8407
|
}
|
|
8139
8408
|
const gooseDbPath = getDbPath("goose") ?? "";
|
|
8140
|
-
if ((!filterTool || filterTool === "goose") &&
|
|
8409
|
+
if ((!filterTool || filterTool === "goose") && existsSync10(gooseDbPath)) {
|
|
8141
8410
|
try {
|
|
8142
8411
|
const gooseDb = new Database2(gooseDbPath, { readonly: true });
|
|
8143
8412
|
try {
|
|
@@ -8195,7 +8464,7 @@ async function runParse(db, filterTool, options) {
|
|
|
8195
8464
|
}
|
|
8196
8465
|
}
|
|
8197
8466
|
const zedDbPath = getDbPath("zed") ?? "";
|
|
8198
|
-
if ((!filterTool || filterTool === "zed") &&
|
|
8467
|
+
if ((!filterTool || filterTool === "zed") && existsSync10(zedDbPath)) {
|
|
8199
8468
|
try {
|
|
8200
8469
|
const zedDb = new Database2(zedDbPath, { readonly: true });
|
|
8201
8470
|
try {
|
|
@@ -8225,7 +8494,7 @@ async function runParse(db, filterTool, options) {
|
|
|
8225
8494
|
}
|
|
8226
8495
|
if (!filterTool || filterTool === "zcode") {
|
|
8227
8496
|
const zcodeDbPath = getDbPath("zcode") ?? "";
|
|
8228
|
-
if (
|
|
8497
|
+
if (existsSync10(zcodeDbPath)) {
|
|
8229
8498
|
try {
|
|
8230
8499
|
const zcodeDb = new Database2(zcodeDbPath, { readonly: true });
|
|
8231
8500
|
try {
|
|
@@ -8284,6 +8553,31 @@ async function runParse(db, filterTool, options) {
|
|
|
8284
8553
|
}
|
|
8285
8554
|
onProgress({ phase: "Parsing SQLite", tool: "trae", current: 1, total: 1, records: parsedCount, toolCalls: toolCallCount });
|
|
8286
8555
|
}
|
|
8556
|
+
const codeBuddyIdeDir = getDbPath("codebuddy-ide") ?? "";
|
|
8557
|
+
if ((!filterTool || filterTool === "codebuddy") && existsSync10(codeBuddyIdeDir)) {
|
|
8558
|
+
try {
|
|
8559
|
+
const cbCursor = wm.getCodeBuddyIdeCursor();
|
|
8560
|
+
const result = runParseCodeBuddy({
|
|
8561
|
+
dataDir: codeBuddyIdeDir,
|
|
8562
|
+
device,
|
|
8563
|
+
deviceInstanceId,
|
|
8564
|
+
platform: devicePlatform,
|
|
8565
|
+
now: Date.now(),
|
|
8566
|
+
cursor: cbCursor,
|
|
8567
|
+
exchangeRate
|
|
8568
|
+
});
|
|
8569
|
+
for (const record of result.records) insertRecord(db, record);
|
|
8570
|
+
parsedCount += result.records.length;
|
|
8571
|
+
errors.push(...result.errors);
|
|
8572
|
+
if (result.nextCursor > cbCursor) {
|
|
8573
|
+
wm.setCodeBuddyIdeCursor(result.nextCursor);
|
|
8574
|
+
wm.save();
|
|
8575
|
+
}
|
|
8576
|
+
onProgress({ phase: "Parsing logs", tool: "codebuddy", current: 1, total: 1, records: parsedCount, toolCalls: toolCallCount });
|
|
8577
|
+
} catch (e) {
|
|
8578
|
+
errors.push(`${codeBuddyIdeDir}: ${e instanceof Error ? e.message : e}`);
|
|
8579
|
+
}
|
|
8580
|
+
}
|
|
8287
8581
|
if (deviceInstanceId !== "unknown") {
|
|
8288
8582
|
db.prepare(
|
|
8289
8583
|
`UPDATE records SET device_instance_id = ?, device = ? WHERE device_instance_id = 'unknown'`
|
|
@@ -8295,9 +8589,19 @@ async function runParse(db, filterTool, options) {
|
|
|
8295
8589
|
).run(devicePlatform);
|
|
8296
8590
|
}
|
|
8297
8591
|
backfillHermesSourceFiles(db);
|
|
8592
|
+
backfillCwd(db);
|
|
8593
|
+
backfillSkillNames(db);
|
|
8594
|
+
backfillCodexModels(db);
|
|
8595
|
+
backfillMissingToolCalls(db, exchangeRate);
|
|
8596
|
+
return { parsedCount, toolCallCount, errors };
|
|
8597
|
+
}
|
|
8598
|
+
function backfillCwd(db) {
|
|
8298
8599
|
const staleFiles = db.prepare(
|
|
8299
8600
|
`SELECT DISTINCT source_file FROM records WHERE cwd = '' AND source_file NOT LIKE 'synced/%'`
|
|
8300
8601
|
).all();
|
|
8602
|
+
const updateStmt = db.prepare(
|
|
8603
|
+
`UPDATE records SET cwd = ?, updated_at = ? WHERE source_file = ? AND cwd = ''`
|
|
8604
|
+
);
|
|
8301
8605
|
for (const { source_file } of staleFiles) {
|
|
8302
8606
|
try {
|
|
8303
8607
|
const fd = openSync(source_file, "r");
|
|
@@ -8308,15 +8612,11 @@ async function runParse(db, filterTool, options) {
|
|
|
8308
8612
|
const data = JSON.parse(firstLine);
|
|
8309
8613
|
const cwd = extractCwdFromJson(data);
|
|
8310
8614
|
if (cwd) {
|
|
8311
|
-
|
|
8615
|
+
updateStmt.run(cwd, Date.now(), source_file);
|
|
8312
8616
|
}
|
|
8313
8617
|
} catch {
|
|
8314
8618
|
}
|
|
8315
8619
|
}
|
|
8316
|
-
backfillSkillNames(db);
|
|
8317
|
-
backfillCodexModels(db);
|
|
8318
|
-
backfillMissingToolCalls(db, exchangeRate);
|
|
8319
|
-
return { parsedCount, toolCallCount, errors };
|
|
8320
8620
|
}
|
|
8321
8621
|
function backfillHermesSourceFiles(db) {
|
|
8322
8622
|
const rows = db.prepare(`
|
|
@@ -8330,7 +8630,7 @@ function backfillHermesSourceFiles(db) {
|
|
|
8330
8630
|
const dbPath = rows[0].source_file;
|
|
8331
8631
|
let titleMap = /* @__PURE__ */ new Map();
|
|
8332
8632
|
try {
|
|
8333
|
-
if (
|
|
8633
|
+
if (existsSync10(dbPath)) {
|
|
8334
8634
|
const hermesDb = new Database2(dbPath, { readonly: true });
|
|
8335
8635
|
try {
|
|
8336
8636
|
const sessions = hermesDb.prepare(
|
|
@@ -8343,11 +8643,11 @@ function backfillHermesSourceFiles(db) {
|
|
|
8343
8643
|
}
|
|
8344
8644
|
} catch {
|
|
8345
8645
|
}
|
|
8346
|
-
const updateStmt = db.prepare(`UPDATE records SET source_file = ? WHERE tool = 'hermes' AND session_id = ? AND source_file = ?`);
|
|
8646
|
+
const updateStmt = db.prepare(`UPDATE records SET source_file = ?, updated_at = ? WHERE tool = 'hermes' AND session_id = ? AND source_file = ?`);
|
|
8347
8647
|
for (const row of rows) {
|
|
8348
8648
|
const title = (titleMap.get(row.session_id) || "").replace(/[/\\:]/g, "_").slice(0, 80);
|
|
8349
8649
|
const newSourceFile = title ? `${row.source_file}:session:${row.session_id}:${title}` : `${row.source_file}:session:${row.session_id}`;
|
|
8350
|
-
updateStmt.run(newSourceFile, row.session_id, row.source_file);
|
|
8650
|
+
updateStmt.run(newSourceFile, Date.now(), row.session_id, row.source_file);
|
|
8351
8651
|
}
|
|
8352
8652
|
}
|
|
8353
8653
|
function backfillSkillNames(db) {
|
|
@@ -8411,7 +8711,7 @@ function backfillCodexModels(db) {
|
|
|
8411
8711
|
);
|
|
8412
8712
|
for (const [sourceFile, fileRows] of byFile) {
|
|
8413
8713
|
try {
|
|
8414
|
-
const content =
|
|
8714
|
+
const content = readFileSync10(sourceFile, "utf-8");
|
|
8415
8715
|
const lines = content.split("\n");
|
|
8416
8716
|
const offsetToModel = /* @__PURE__ */ new Map();
|
|
8417
8717
|
let currentModel = "";
|
|
@@ -8459,7 +8759,7 @@ function backfillMissingToolCalls(db, exchangeRate) {
|
|
|
8459
8759
|
}
|
|
8460
8760
|
for (const [sourceFile, fileRows] of rowsByFile) {
|
|
8461
8761
|
try {
|
|
8462
|
-
const content =
|
|
8762
|
+
const content = readFileSync10(sourceFile, "utf-8");
|
|
8463
8763
|
const lines = content.split("\n");
|
|
8464
8764
|
const aggregator = new Aggregator();
|
|
8465
8765
|
const recordIdByOffset = /* @__PURE__ */ new Map();
|
|
@@ -8521,7 +8821,7 @@ function deriveSessionId(tool, sourceFile) {
|
|
|
8521
8821
|
}
|
|
8522
8822
|
|
|
8523
8823
|
// src/commands/sync.ts
|
|
8524
|
-
import { join as
|
|
8824
|
+
import { join as join11 } from "path";
|
|
8525
8825
|
|
|
8526
8826
|
// src/db/synced-records.ts
|
|
8527
8827
|
function insertSyncedRecord(db, record) {
|
|
@@ -8954,10 +9254,10 @@ async function cloudClear() {
|
|
|
8954
9254
|
}
|
|
8955
9255
|
function getClientVersion() {
|
|
8956
9256
|
try {
|
|
8957
|
-
const { readFileSync:
|
|
8958
|
-
const { join:
|
|
8959
|
-
const pkgPath =
|
|
8960
|
-
const pkg = JSON.parse(
|
|
9257
|
+
const { readFileSync: readFileSync14 } = __require("fs");
|
|
9258
|
+
const { join: join18 } = __require("path");
|
|
9259
|
+
const pkgPath = join18(__dirname, "../../package.json");
|
|
9260
|
+
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
8961
9261
|
return pkg.version || "0.0.0";
|
|
8962
9262
|
} catch {
|
|
8963
9263
|
return "0.0.0";
|
|
@@ -9048,7 +9348,7 @@ var CloudSyncOrchestrator = class {
|
|
|
9048
9348
|
import { execFile } from "child_process";
|
|
9049
9349
|
import { promisify } from "util";
|
|
9050
9350
|
import { readFile, writeFile, mkdir, readdir, stat, unlink, rm } from "fs/promises";
|
|
9051
|
-
import { join as
|
|
9351
|
+
import { join as join10 } from "path";
|
|
9052
9352
|
var exec = promisify(execFile);
|
|
9053
9353
|
var GitSyncBackend = class _GitSyncBackend {
|
|
9054
9354
|
repo;
|
|
@@ -9060,7 +9360,7 @@ var GitSyncBackend = class _GitSyncBackend {
|
|
|
9060
9360
|
this.repo = config.repo;
|
|
9061
9361
|
this.token = config.token;
|
|
9062
9362
|
this.cacheDir = config.cacheDir;
|
|
9063
|
-
this.dataDir =
|
|
9363
|
+
this.dataDir = join10(config.cacheDir, "data");
|
|
9064
9364
|
this.branch = config.branch ?? "main";
|
|
9065
9365
|
}
|
|
9066
9366
|
get remoteUrl() {
|
|
@@ -9092,7 +9392,7 @@ var GitSyncBackend = class _GitSyncBackend {
|
|
|
9092
9392
|
/** Clone or pull the repo to get latest remote state */
|
|
9093
9393
|
async prepare() {
|
|
9094
9394
|
try {
|
|
9095
|
-
await stat(
|
|
9395
|
+
await stat(join10(this.cacheDir, ".git"));
|
|
9096
9396
|
await this.git(["fetch", "origin", this.branch, "--depth=1"]);
|
|
9097
9397
|
await this.git(["reset", "--hard", `origin/${this.branch}`]);
|
|
9098
9398
|
} catch {
|
|
@@ -9109,15 +9409,15 @@ var GitSyncBackend = class _GitSyncBackend {
|
|
|
9109
9409
|
}
|
|
9110
9410
|
async readFile(path3) {
|
|
9111
9411
|
try {
|
|
9112
|
-
const fullPath =
|
|
9412
|
+
const fullPath = join10(this.dataDir, path3);
|
|
9113
9413
|
return await readFile(fullPath, "utf-8");
|
|
9114
9414
|
} catch {
|
|
9115
9415
|
return null;
|
|
9116
9416
|
}
|
|
9117
9417
|
}
|
|
9118
9418
|
async writeFile(path3, content) {
|
|
9119
|
-
const fullPath =
|
|
9120
|
-
await mkdir(
|
|
9419
|
+
const fullPath = join10(this.dataDir, path3);
|
|
9420
|
+
await mkdir(join10(fullPath, ".."), { recursive: true });
|
|
9121
9421
|
await writeFile(fullPath, content, "utf-8");
|
|
9122
9422
|
}
|
|
9123
9423
|
async listFiles() {
|
|
@@ -9128,7 +9428,7 @@ var GitSyncBackend = class _GitSyncBackend {
|
|
|
9128
9428
|
}
|
|
9129
9429
|
}
|
|
9130
9430
|
async deleteFile(path3) {
|
|
9131
|
-
const fullPath =
|
|
9431
|
+
const fullPath = join10(this.dataDir, path3);
|
|
9132
9432
|
try {
|
|
9133
9433
|
await unlink(fullPath);
|
|
9134
9434
|
} catch {
|
|
@@ -9167,7 +9467,7 @@ var GitSyncBackend = class _GitSyncBackend {
|
|
|
9167
9467
|
for (const entry of entries) {
|
|
9168
9468
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
9169
9469
|
if (entry.isDirectory()) {
|
|
9170
|
-
files.push(...await this.walkDir(
|
|
9470
|
+
files.push(...await this.walkDir(join10(dir, entry.name), relPath));
|
|
9171
9471
|
} else if (entry.name.endsWith(".ndjson")) {
|
|
9172
9472
|
files.push(relPath);
|
|
9173
9473
|
}
|
|
@@ -9301,7 +9601,7 @@ function createBackend(config) {
|
|
|
9301
9601
|
return new GitSyncBackend({
|
|
9302
9602
|
repo: sync.repo,
|
|
9303
9603
|
token,
|
|
9304
|
-
cacheDir:
|
|
9604
|
+
cacheDir: join11(AIUSAGE_DIR, "sync-repo")
|
|
9305
9605
|
});
|
|
9306
9606
|
}
|
|
9307
9607
|
if (sync.backend === "s3") {
|
|
@@ -9396,8 +9696,8 @@ async function runSync(db, options) {
|
|
|
9396
9696
|
}
|
|
9397
9697
|
|
|
9398
9698
|
// src/commands/clean.ts
|
|
9399
|
-
import { unlinkSync as unlinkSync3, existsSync as
|
|
9400
|
-
import { join as
|
|
9699
|
+
import { unlinkSync as unlinkSync3, existsSync as existsSync11 } from "fs";
|
|
9700
|
+
import { join as join12 } from "path";
|
|
9401
9701
|
function cleanOldData(db, days) {
|
|
9402
9702
|
const cutoff = Date.now() - days * 864e5;
|
|
9403
9703
|
const recordsResult = db.prepare("DELETE FROM records WHERE ts < ?").run(cutoff);
|
|
@@ -9418,9 +9718,9 @@ function cleanAll(db) {
|
|
|
9418
9718
|
const syncedResult = db.prepare("DELETE FROM synced_records").run();
|
|
9419
9719
|
const syncStateResult = db.prepare("DELETE FROM sync_record_state").run();
|
|
9420
9720
|
const tombstonesResult = db.prepare("DELETE FROM sync_tombstones").run();
|
|
9421
|
-
const watermarkPath =
|
|
9721
|
+
const watermarkPath = join12(AIUSAGE_DIR, "watermark.json");
|
|
9422
9722
|
let watermarkRemoved = false;
|
|
9423
|
-
if (
|
|
9723
|
+
if (existsSync11(watermarkPath)) {
|
|
9424
9724
|
unlinkSync3(watermarkPath);
|
|
9425
9725
|
watermarkRemoved = true;
|
|
9426
9726
|
}
|
|
@@ -9455,7 +9755,7 @@ function createBackend2(config) {
|
|
|
9455
9755
|
return new GitSyncBackend({
|
|
9456
9756
|
repo: config.sync.repo,
|
|
9457
9757
|
token,
|
|
9458
|
-
cacheDir:
|
|
9758
|
+
cacheDir: join12(AIUSAGE_DIR, "sync-repo")
|
|
9459
9759
|
});
|
|
9460
9760
|
}
|
|
9461
9761
|
if (config.sync.backend === "s3") {
|
|
@@ -9788,7 +10088,7 @@ var RuntimeSettingsController = class {
|
|
|
9788
10088
|
|
|
9789
10089
|
// src/commands/serve.ts
|
|
9790
10090
|
var MAX_PORT_ATTEMPTS = 10;
|
|
9791
|
-
var PORT_FILE =
|
|
10091
|
+
var PORT_FILE = join13(AIUSAGE_DIR, ".serve-port");
|
|
9792
10092
|
var MIME_TYPES = {
|
|
9793
10093
|
".html": "text/html",
|
|
9794
10094
|
".js": "application/javascript",
|
|
@@ -9863,11 +10163,11 @@ function serve(options) {
|
|
|
9863
10163
|
getDbWriteQueueStatus: () => dbWriteQueue.getStatus()
|
|
9864
10164
|
});
|
|
9865
10165
|
const webBuildDir = (() => {
|
|
9866
|
-
const prodDir =
|
|
9867
|
-
if (
|
|
9868
|
-
return
|
|
10166
|
+
const prodDir = join13(dirname6(fileURLToPath(import.meta.url)), "web");
|
|
10167
|
+
if (existsSync12(prodDir)) return prodDir;
|
|
10168
|
+
return join13(dirname6(fileURLToPath(import.meta.url)), "..", "..", "..", "web", "build");
|
|
9869
10169
|
})();
|
|
9870
|
-
if (!
|
|
10170
|
+
if (!existsSync12(webBuildDir)) {
|
|
9871
10171
|
console.error("Web dashboard not found. Reinstall the package: npm install -g @juliantanx/aiusage");
|
|
9872
10172
|
process.exit(1);
|
|
9873
10173
|
}
|
|
@@ -9877,19 +10177,19 @@ function serve(options) {
|
|
|
9877
10177
|
apiServer.emit("request", req, res);
|
|
9878
10178
|
return;
|
|
9879
10179
|
}
|
|
9880
|
-
if (
|
|
9881
|
-
let filePath =
|
|
10180
|
+
if (existsSync12(webBuildDir)) {
|
|
10181
|
+
let filePath = join13(webBuildDir, url.pathname);
|
|
9882
10182
|
try {
|
|
9883
10183
|
if (statSync4(filePath).isDirectory()) {
|
|
9884
|
-
filePath =
|
|
10184
|
+
filePath = join13(filePath, "index.html");
|
|
9885
10185
|
}
|
|
9886
10186
|
} catch {
|
|
9887
10187
|
}
|
|
9888
|
-
if (!
|
|
9889
|
-
filePath =
|
|
10188
|
+
if (!existsSync12(filePath)) {
|
|
10189
|
+
filePath = join13(webBuildDir, "index.html");
|
|
9890
10190
|
}
|
|
9891
10191
|
try {
|
|
9892
|
-
const content =
|
|
10192
|
+
const content = readFileSync11(filePath);
|
|
9893
10193
|
const ext = extname2(filePath);
|
|
9894
10194
|
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
9895
10195
|
res.writeHead(200, { "Content-Type": contentType });
|
|
@@ -10071,9 +10371,9 @@ Consent recorded for schema v1.`
|
|
|
10071
10371
|
}
|
|
10072
10372
|
|
|
10073
10373
|
// src/commands/status.ts
|
|
10074
|
-
import { statSync as statSync5, existsSync as
|
|
10374
|
+
import { statSync as statSync5, existsSync as existsSync13 } from "fs";
|
|
10075
10375
|
import { hostname as hostname3 } from "os";
|
|
10076
|
-
import { join as
|
|
10376
|
+
import { join as join14 } from "path";
|
|
10077
10377
|
function formatFileSize(bytes) {
|
|
10078
10378
|
if (bytes < 1024) return `${bytes} B`;
|
|
10079
10379
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
@@ -10091,9 +10391,9 @@ function generateStatus(db) {
|
|
|
10091
10391
|
const schemaVersion = db.prepare("SELECT version FROM schema_version ORDER BY version DESC LIMIT 1").get()?.version ?? 0;
|
|
10092
10392
|
const tableCount = db.prepare("SELECT COUNT(*) as count FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'").get()?.count ?? 0;
|
|
10093
10393
|
const viewCount = db.prepare("SELECT COUNT(*) as count FROM sqlite_master WHERE type = 'view'").get()?.count ?? 0;
|
|
10094
|
-
const sizePath =
|
|
10394
|
+
const sizePath = join14(AIUSAGE_DIR, "cache.db");
|
|
10095
10395
|
let databaseSize = "0 B";
|
|
10096
|
-
if (
|
|
10396
|
+
if (existsSync13(sizePath)) {
|
|
10097
10397
|
try {
|
|
10098
10398
|
const stat2 = statSync5(sizePath);
|
|
10099
10399
|
databaseSize = formatFileSize(stat2.size);
|
|
@@ -10316,10 +10616,10 @@ var SyncProgressReporter = class {
|
|
|
10316
10616
|
};
|
|
10317
10617
|
|
|
10318
10618
|
// src/commands/widget.ts
|
|
10319
|
-
import { existsSync as
|
|
10619
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
10320
10620
|
import { spawn, execSync as execSync2 } from "child_process";
|
|
10321
|
-
import { join as
|
|
10322
|
-
var WIDGET_PID_PATH =
|
|
10621
|
+
import { join as join15 } from "path";
|
|
10622
|
+
var WIDGET_PID_PATH = join15(AIUSAGE_DIR, "widget.pid");
|
|
10323
10623
|
async function launchWidget() {
|
|
10324
10624
|
if (isWidgetRunning()) {
|
|
10325
10625
|
console.log("aiusage widget is already running in the system tray.");
|
|
@@ -10341,10 +10641,10 @@ async function launchWidget() {
|
|
|
10341
10641
|
console.log("aiusage widget started.");
|
|
10342
10642
|
}
|
|
10343
10643
|
function isWidgetRunning() {
|
|
10344
|
-
if (!
|
|
10644
|
+
if (!existsSync14(WIDGET_PID_PATH)) return false;
|
|
10345
10645
|
let pid;
|
|
10346
10646
|
try {
|
|
10347
|
-
pid = parseInt(
|
|
10647
|
+
pid = parseInt(readFileSync12(WIDGET_PID_PATH, "utf-8").trim(), 10);
|
|
10348
10648
|
} catch {
|
|
10349
10649
|
return false;
|
|
10350
10650
|
}
|
|
@@ -10388,10 +10688,10 @@ function getDeviceName2() {
|
|
|
10388
10688
|
}
|
|
10389
10689
|
function getCliVersion2() {
|
|
10390
10690
|
try {
|
|
10391
|
-
const { readFileSync:
|
|
10392
|
-
const { join:
|
|
10393
|
-
const pkgPath =
|
|
10394
|
-
const pkg = JSON.parse(
|
|
10691
|
+
const { readFileSync: readFileSync14 } = __require("fs");
|
|
10692
|
+
const { join: join18 } = __require("path");
|
|
10693
|
+
const pkgPath = join18(__dirname, "../../package.json");
|
|
10694
|
+
const pkg = JSON.parse(readFileSync14(pkgPath, "utf-8"));
|
|
10395
10695
|
return pkg.version || "0.0.0";
|
|
10396
10696
|
} catch {
|
|
10397
10697
|
return "0.0.0";
|
|
@@ -10560,8 +10860,8 @@ function formatTokens(value) {
|
|
|
10560
10860
|
return Number(value).toLocaleString();
|
|
10561
10861
|
}
|
|
10562
10862
|
function formatCost(value) {
|
|
10563
|
-
const
|
|
10564
|
-
return Number.isFinite(
|
|
10863
|
+
const num4 = Number(value);
|
|
10864
|
+
return Number.isFinite(num4) ? `$${num4.toFixed(4)}` : "$0.0000";
|
|
10565
10865
|
}
|
|
10566
10866
|
function formatUpdatedAt(value) {
|
|
10567
10867
|
const date = new Date(value);
|
|
@@ -10635,16 +10935,16 @@ async function runLeaderboardView(options = {}) {
|
|
|
10635
10935
|
// src/commands/menu.ts
|
|
10636
10936
|
import { createInterface } from "readline";
|
|
10637
10937
|
import { spawn as spawn2, spawnSync as spawnSync2, execSync as execSync4 } from "child_process";
|
|
10638
|
-
import { existsSync as
|
|
10639
|
-
import { join as
|
|
10938
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
10939
|
+
import { join as join16 } from "path";
|
|
10640
10940
|
var DEFAULT_PORT = 3847;
|
|
10641
|
-
var PORT_FILE2 =
|
|
10941
|
+
var PORT_FILE2 = join16(AIUSAGE_DIR, ".serve-port");
|
|
10642
10942
|
function clearScreen() {
|
|
10643
10943
|
process.stdout.write("\x1Bc");
|
|
10644
10944
|
}
|
|
10645
10945
|
function getPort() {
|
|
10646
|
-
if (
|
|
10647
|
-
const raw =
|
|
10946
|
+
if (existsSync15(PORT_FILE2)) {
|
|
10947
|
+
const raw = readFileSync13(PORT_FILE2, "utf-8").trim();
|
|
10648
10948
|
const n = parseInt(raw, 10);
|
|
10649
10949
|
if (!isNaN(n) && n > 0) return n;
|
|
10650
10950
|
}
|
|
@@ -11133,10 +11433,10 @@ ${dashboardStatusLine()}
|
|
|
11133
11433
|
}
|
|
11134
11434
|
|
|
11135
11435
|
// src/cli.ts
|
|
11136
|
-
import { join as
|
|
11137
|
-
var DB_PATH2 =
|
|
11436
|
+
import { join as join17 } from "path";
|
|
11437
|
+
var DB_PATH2 = join17(AIUSAGE_DIR, "cache.db");
|
|
11138
11438
|
var program = new Command();
|
|
11139
|
-
program.name("aiusage").version(true ? "1.5.
|
|
11439
|
+
program.name("aiusage").version(true ? "1.5.8" : "dev").description("CLI tool for AI usage statistics");
|
|
11140
11440
|
program.action(() => {
|
|
11141
11441
|
const unknownCommand = program.args.find((arg) => typeof arg === "string");
|
|
11142
11442
|
if (unknownCommand) {
|
|
@@ -11423,7 +11723,7 @@ function hasWidget() {
|
|
|
11423
11723
|
}
|
|
11424
11724
|
}
|
|
11425
11725
|
function buildPm2Config(includeWidget) {
|
|
11426
|
-
const wrapperPath =
|
|
11726
|
+
const wrapperPath = join17(AIUSAGE_DIR, "pm2-server.cjs");
|
|
11427
11727
|
writeFileSync7(wrapperPath, [
|
|
11428
11728
|
`// Auto-generated by aiusage pm2-start \u2014 do not edit`,
|
|
11429
11729
|
`const { execSync, spawn } = require('child_process')`,
|
|
@@ -11470,7 +11770,7 @@ ${apps.join(",\n")}
|
|
|
11470
11770
|
program.command("pm2-setup").description("Generate ecosystem.config.cjs for PM2 background services").option("--server-only", "Only include server, skip widget").action((options) => {
|
|
11471
11771
|
const includeWidget = options.serverOnly ? false : hasWidget();
|
|
11472
11772
|
const config = buildPm2Config(includeWidget);
|
|
11473
|
-
const configPath =
|
|
11773
|
+
const configPath = join17(AIUSAGE_DIR, "ecosystem.config.cjs");
|
|
11474
11774
|
writeFileSync7(configPath, config, "utf-8");
|
|
11475
11775
|
console.log(`Config created: ${configPath}`);
|
|
11476
11776
|
if (!includeWidget) {
|
|
@@ -11480,7 +11780,7 @@ program.command("pm2-setup").description("Generate ecosystem.config.cjs for PM2
|
|
|
11480
11780
|
program.command("pm2-start").description("Setup and start PM2 background services (requires pm2 installed globally)").option("--server-only", "Only start server, skip widget").action((options) => {
|
|
11481
11781
|
const includeWidget = options.serverOnly ? false : hasWidget();
|
|
11482
11782
|
const config = buildPm2Config(includeWidget);
|
|
11483
|
-
const configPath =
|
|
11783
|
+
const configPath = join17(AIUSAGE_DIR, "ecosystem.config.cjs");
|
|
11484
11784
|
writeFileSync7(configPath, config, "utf-8");
|
|
11485
11785
|
console.log(`Config: ${configPath}`);
|
|
11486
11786
|
try {
|