@yhong91/vibetime 0.1.38 → 0.1.40
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/bin/vibetime.mjs +111 -26
- package/package.json +1 -1
package/bin/vibetime.mjs
CHANGED
|
@@ -1928,7 +1928,7 @@ function countTextLines(text) {
|
|
|
1928
1928
|
}
|
|
1929
1929
|
|
|
1930
1930
|
// src/lib/constants.ts
|
|
1931
|
-
var PACKAGE_VERSION = true ? "0.1.
|
|
1931
|
+
var PACKAGE_VERSION = true ? "0.1.40" : "0.1.1";
|
|
1932
1932
|
var DEFAULT_API_URL = "http://121.196.224.82:3001";
|
|
1933
1933
|
var DEFAULT_BACKFILL_BATCH_SIZE = 50;
|
|
1934
1934
|
var DEFAULT_BACKFILL_BATCH_BYTES = 800 * 1024;
|
|
@@ -4209,7 +4209,7 @@ async function parseCodebuddyTraceFile(filePath, options) {
|
|
|
4209
4209
|
return [];
|
|
4210
4210
|
}
|
|
4211
4211
|
const sessionMeta = await readCodebuddySessionMeta(trace.workerPid, trace.sessionId, options);
|
|
4212
|
-
const sessionId = trace.sessionId || sessionMeta.sessionId || sessionIdFromTracePath(filePath);
|
|
4212
|
+
const sessionId = trace.sessionId || sessionMeta.sessionId || await resolveSessionIdFromSiblingTraces(filePath) || sessionIdFromTracePath(filePath);
|
|
4213
4213
|
let cwd = sessionMeta.cwd;
|
|
4214
4214
|
if (!cwd && trace.startedAt) {
|
|
4215
4215
|
cwd = await cwdFromHistoryFile(trace.startedAt, options);
|
|
@@ -4565,46 +4565,71 @@ function normalizeModelCandidate(value) {
|
|
|
4565
4565
|
}
|
|
4566
4566
|
return trimmed;
|
|
4567
4567
|
}
|
|
4568
|
-
function
|
|
4569
|
-
|
|
4570
|
-
if (!Array.isArray(parsed) || parsed.length === 0) {
|
|
4571
|
-
return void 0;
|
|
4572
|
-
}
|
|
4573
|
-
const first = parsed[0];
|
|
4574
|
-
if (!isPlainObject(first)) {
|
|
4575
|
-
return void 0;
|
|
4576
|
-
}
|
|
4577
|
-
const usage = objectField(first, "usage");
|
|
4578
|
-
if (!isPlainObject(usage)) {
|
|
4568
|
+
function finitePositive(value) {
|
|
4569
|
+
if (typeof value !== "number" && typeof value !== "string") {
|
|
4579
4570
|
return void 0;
|
|
4580
4571
|
}
|
|
4572
|
+
const parsed = Number(value);
|
|
4573
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
|
|
4574
|
+
}
|
|
4575
|
+
function extractUsageFromGenerationSpan(span) {
|
|
4576
|
+
const parsed = parseEmbeddedJson(span.toolOutput);
|
|
4577
|
+
const first = Array.isArray(parsed) ? parsed[0] : void 0;
|
|
4578
|
+
const usage = isPlainObject(first) ? objectField(first, "usage") : {};
|
|
4581
4579
|
const inputTokens = numberField(usage, "prompt_tokens");
|
|
4582
4580
|
const outputTokens = numberField(usage, "completion_tokens");
|
|
4583
4581
|
const totalTokens = numberField(usage, "total_tokens");
|
|
4584
4582
|
const details = objectField(usage, "prompt_tokens_details");
|
|
4585
4583
|
const cachedTokens = isPlainObject(details) ? numberField(details, "cached_tokens") : void 0;
|
|
4584
|
+
const otelAttributes = span.attributes || {};
|
|
4585
|
+
const otelInputTokens = finitePositive(otelAttributes["gen_ai.usage.input_tokens"]);
|
|
4586
|
+
const otelOutputTokens = finitePositive(otelAttributes["gen_ai.usage.output_tokens"]);
|
|
4587
|
+
const otelCacheReadTokens = finitePositive(otelAttributes["gen_ai.usage.cache_read_input_tokens"]);
|
|
4588
|
+
const otelCacheCreationTokens = finitePositive(otelAttributes["gen_ai.usage.cache_creation_input_tokens"]);
|
|
4589
|
+
const otelReasoningTokens = finitePositive(otelAttributes["gen_ai.usage.reasoning_output_tokens"]);
|
|
4590
|
+
const tokensInput = otelInputTokens ?? inputTokens;
|
|
4591
|
+
const tokensOutput = otelOutputTokens ?? outputTokens;
|
|
4592
|
+
const tokensCacheReadInput = otelCacheReadTokens ?? cachedTokens;
|
|
4593
|
+
const tokensCachedInput = (tokensCacheReadInput ?? 0) + (otelCacheCreationTokens ?? 0);
|
|
4594
|
+
const tokensTotal = totalTokens || (tokensInput ?? 0) + (tokensOutput ?? 0);
|
|
4595
|
+
if (!tokensInput && !tokensOutput && !tokensCachedInput && !otelReasoningTokens && !tokensTotal) {
|
|
4596
|
+
return void 0;
|
|
4597
|
+
}
|
|
4586
4598
|
return {
|
|
4587
|
-
tokensInput:
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4599
|
+
tokensInput: tokensInput || void 0,
|
|
4600
|
+
tokensOutput: tokensOutput || void 0,
|
|
4601
|
+
tokensCachedInput: tokensCachedInput || void 0,
|
|
4602
|
+
tokensCacheReadInput: tokensCacheReadInput || void 0,
|
|
4603
|
+
tokensCacheCreationInput: otelCacheCreationTokens,
|
|
4604
|
+
tokensReasoningOutput: otelReasoningTokens,
|
|
4605
|
+
tokensTotal: tokensTotal || void 0,
|
|
4591
4606
|
modelCalls: 1
|
|
4592
4607
|
};
|
|
4593
4608
|
}
|
|
4594
4609
|
function modelUsageFromTrace(trace, generationIndex, totalGenerations) {
|
|
4595
4610
|
const info = trace.modelInfo;
|
|
4596
|
-
|
|
4611
|
+
const otelAttributes = trace.attributes || {};
|
|
4612
|
+
const otelInputTokens = finitePositive(otelAttributes["gen_ai.usage.input_tokens"]);
|
|
4613
|
+
const otelOutputTokens = finitePositive(otelAttributes["gen_ai.usage.output_tokens"]);
|
|
4614
|
+
const otelCacheReadTokens = finitePositive(otelAttributes["gen_ai.usage.cache_read_input_tokens"]);
|
|
4615
|
+
const otelCacheCreationTokens = finitePositive(otelAttributes["gen_ai.usage.cache_creation_input_tokens"]);
|
|
4616
|
+
const otelReasoningTokens = finitePositive(otelAttributes["gen_ai.usage.reasoning_output_tokens"]);
|
|
4617
|
+
if (!info && !trace.totalTokens && !otelInputTokens && !otelOutputTokens && !otelCacheReadTokens && !otelCacheCreationTokens && !otelReasoningTokens) {
|
|
4597
4618
|
return void 0;
|
|
4598
4619
|
}
|
|
4620
|
+
const inputTokens = otelInputTokens ?? (info?.totalInputTokens || 0);
|
|
4621
|
+
const outputTokens = otelOutputTokens ?? (info?.totalOutputTokens || 0);
|
|
4622
|
+
const cacheReadTokens = otelCacheReadTokens ?? info?.totalCachedTokens;
|
|
4623
|
+
const cachedTokens = (cacheReadTokens ?? 0) + (otelCacheCreationTokens ?? 0);
|
|
4624
|
+
const totalTokens = trace.totalTokens || inputTokens + outputTokens;
|
|
4599
4625
|
if (generationIndex === 1) {
|
|
4600
|
-
const inputTokens = info.totalInputTokens || 0;
|
|
4601
|
-
const outputTokens = info.totalOutputTokens || 0;
|
|
4602
|
-
const cachedTokens = info.totalCachedTokens || 0;
|
|
4603
|
-
const totalTokens = trace.totalTokens || inputTokens + outputTokens;
|
|
4604
4626
|
return {
|
|
4605
4627
|
tokensInput: inputTokens || void 0,
|
|
4606
4628
|
tokensCachedInput: cachedTokens || void 0,
|
|
4629
|
+
tokensCacheReadInput: cacheReadTokens,
|
|
4630
|
+
tokensCacheCreationInput: otelCacheCreationTokens || void 0,
|
|
4607
4631
|
tokensOutput: outputTokens || void 0,
|
|
4632
|
+
tokensReasoningOutput: otelReasoningTokens || void 0,
|
|
4608
4633
|
tokensTotal: totalTokens || void 0,
|
|
4609
4634
|
modelCalls: totalGenerations || 1
|
|
4610
4635
|
};
|
|
@@ -4615,6 +4640,42 @@ function sessionIdFromTracePath(filePath) {
|
|
|
4615
4640
|
const match = path9.basename(filePath).match(/trace_([0-9a-f]{32})/);
|
|
4616
4641
|
return match?.[1] ? `codebuddy_${match[1]}` : `codebuddy_${createStableHash(filePath).slice(0, 24)}`;
|
|
4617
4642
|
}
|
|
4643
|
+
var siblingSessionIdByDir = /* @__PURE__ */ new Map();
|
|
4644
|
+
async function resolveSessionIdFromSiblingTraces(filePath) {
|
|
4645
|
+
const dir = path9.dirname(filePath);
|
|
4646
|
+
let cached = siblingSessionIdByDir.get(dir);
|
|
4647
|
+
if (!cached) {
|
|
4648
|
+
cached = (async () => {
|
|
4649
|
+
try {
|
|
4650
|
+
const entries = await readdir4(dir);
|
|
4651
|
+
for (const entry of entries) {
|
|
4652
|
+
if (!entry.startsWith("trace_") || !entry.endsWith(".json")) {
|
|
4653
|
+
continue;
|
|
4654
|
+
}
|
|
4655
|
+
const siblingPath = path9.join(dir, entry);
|
|
4656
|
+
if (siblingPath === filePath) {
|
|
4657
|
+
continue;
|
|
4658
|
+
}
|
|
4659
|
+
try {
|
|
4660
|
+
const text = await readFile5(siblingPath, "utf8");
|
|
4661
|
+
const data = JSON.parse(text);
|
|
4662
|
+
if (isPlainObject(data) && isPlainObject(data.trace)) {
|
|
4663
|
+
const sid = stringField(data.trace, "sessionId");
|
|
4664
|
+
if (sid) {
|
|
4665
|
+
return sid;
|
|
4666
|
+
}
|
|
4667
|
+
}
|
|
4668
|
+
} catch {
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
} catch {
|
|
4672
|
+
}
|
|
4673
|
+
return void 0;
|
|
4674
|
+
})();
|
|
4675
|
+
siblingSessionIdByDir.set(dir, cached);
|
|
4676
|
+
}
|
|
4677
|
+
return cached;
|
|
4678
|
+
}
|
|
4618
4679
|
function resolveHome(options) {
|
|
4619
4680
|
return options.home ? path9.resolve(String(options.home)) : process.env.HOME || __require("node:os").homedir();
|
|
4620
4681
|
}
|
|
@@ -7579,9 +7640,8 @@ function rebuildEventIdentity2(event) {
|
|
|
7579
7640
|
}
|
|
7580
7641
|
};
|
|
7581
7642
|
}
|
|
7582
|
-
async function
|
|
7643
|
+
async function parseModelNamesFromDynamicTexts(dynamicTextsPath) {
|
|
7583
7644
|
try {
|
|
7584
|
-
const dynamicTextsPath = path17.join(configDir2, ".auth", "dynamic-texts.json");
|
|
7585
7645
|
const content = await readFile10(dynamicTextsPath, "utf8");
|
|
7586
7646
|
const json = JSON.parse(content);
|
|
7587
7647
|
const texts = json.texts || {};
|
|
@@ -7597,6 +7657,19 @@ async function loadQoderCnModelNames(configDir2) {
|
|
|
7597
7657
|
return {};
|
|
7598
7658
|
}
|
|
7599
7659
|
}
|
|
7660
|
+
async function loadQoderCnModelNames(configDir2) {
|
|
7661
|
+
const map = await parseModelNamesFromDynamicTexts(path17.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
7662
|
+
const siblingConfigDir = configDir2.replace(/\.qoder-cn$/, ".qoder");
|
|
7663
|
+
if (siblingConfigDir !== configDir2) {
|
|
7664
|
+
const siblingMap = await parseModelNamesFromDynamicTexts(path17.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
7665
|
+
for (const [key, val] of Object.entries(siblingMap)) {
|
|
7666
|
+
if (!(key in map)) {
|
|
7667
|
+
map[key] = val;
|
|
7668
|
+
}
|
|
7669
|
+
}
|
|
7670
|
+
}
|
|
7671
|
+
return map;
|
|
7672
|
+
}
|
|
7600
7673
|
async function loadQoderCnSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
7601
7674
|
const { configDir: configDir2, projectName, sessionId } = parseQoderCnPaths(filePath);
|
|
7602
7675
|
const segmentsPath = path17.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
|
@@ -8382,9 +8455,8 @@ function rebuildEventIdentity3(event) {
|
|
|
8382
8455
|
}
|
|
8383
8456
|
};
|
|
8384
8457
|
}
|
|
8385
|
-
async function
|
|
8458
|
+
async function parseModelNamesFromDynamicTexts2(dynamicTextsPath) {
|
|
8386
8459
|
try {
|
|
8387
|
-
const dynamicTextsPath = path18.join(configDir2, ".auth", "dynamic-texts.json");
|
|
8388
8460
|
const content = await readFile11(dynamicTextsPath, "utf8");
|
|
8389
8461
|
const json = JSON.parse(content);
|
|
8390
8462
|
const texts = json.texts || {};
|
|
@@ -8400,6 +8472,19 @@ async function loadQoderModelNames(configDir2) {
|
|
|
8400
8472
|
return {};
|
|
8401
8473
|
}
|
|
8402
8474
|
}
|
|
8475
|
+
async function loadQoderModelNames(configDir2) {
|
|
8476
|
+
const map = await parseModelNamesFromDynamicTexts2(path18.join(configDir2, ".auth", "dynamic-texts.json"));
|
|
8477
|
+
const siblingConfigDir = configDir2.replace(/\.qoder$/, ".qoder-cn");
|
|
8478
|
+
if (siblingConfigDir !== configDir2) {
|
|
8479
|
+
const siblingMap = await parseModelNamesFromDynamicTexts2(path18.join(siblingConfigDir, ".auth", "dynamic-texts.json"));
|
|
8480
|
+
for (const [key, val] of Object.entries(siblingMap)) {
|
|
8481
|
+
if (!(key in map)) {
|
|
8482
|
+
map[key] = val;
|
|
8483
|
+
}
|
|
8484
|
+
}
|
|
8485
|
+
}
|
|
8486
|
+
return map;
|
|
8487
|
+
}
|
|
8403
8488
|
async function loadQoderSegmentModelCalls(filePath, isSubagentSession, modelMap) {
|
|
8404
8489
|
const { configDir: configDir2, projectName, sessionId } = parseQoderPaths(filePath);
|
|
8405
8490
|
const segmentsPath = path18.join(configDir2, "logs", "sessions", projectName, sessionId, "segments");
|
package/package.json
CHANGED